mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Merge fix
This commit is contained in:
commit
8ae76bc217
5
.gitignore
vendored
5
.gitignore
vendored
@ -30,4 +30,7 @@ vcpkg/
|
||||
perl/
|
||||
|
||||
.idea/*
|
||||
*cbp
|
||||
*cbp
|
||||
|
||||
submodules/*
|
||||
cmake-build-debug/
|
||||
1113
changelog.txt
1113
changelog.txt
File diff suppressed because it is too large
Load Diff
@ -39,20 +39,19 @@ int main(int argc, char **argv) {
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
Log(Logs::General, Logs::Status, "Client Files Export Utility");
|
||||
LogInfo("Client Files Export Utility");
|
||||
if(!EQEmuConfig::LoadConfig()) {
|
||||
Log(Logs::General, Logs::Error, "Unable to load configuration file.");
|
||||
LogError("Unable to load configuration file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto Config = EQEmuConfig::get();
|
||||
|
||||
SharedDatabase database;
|
||||
Log(Logs::General, Logs::Status, "Connecting to database...");
|
||||
LogInfo("Connecting to database");
|
||||
if(!database.Connect(Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(),
|
||||
Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) {
|
||||
Log(Logs::General, Logs::Error, "Unable to connect to the database, cannot continue without a "
|
||||
"database connection");
|
||||
LogError("Unable to connect to the database, cannot continue without a database connection");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -94,11 +93,11 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
void ExportSpells(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Exporting Spells...");
|
||||
LogInfo("Exporting Spells");
|
||||
|
||||
FILE *f = fopen("export/spells_us.txt", "w");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open export/spells_us.txt to write, skipping.");
|
||||
LogError("Unable to open export/spells_us.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -165,11 +164,11 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level) {
|
||||
}
|
||||
|
||||
void ExportSkillCaps(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Exporting Skill Caps...");
|
||||
LogInfo("Exporting Skill Caps");
|
||||
|
||||
FILE *f = fopen("export/SkillCaps.txt", "w");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -194,11 +193,11 @@ void ExportSkillCaps(SharedDatabase *db) {
|
||||
}
|
||||
|
||||
void ExportBaseData(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Exporting Base Data...");
|
||||
LogInfo("Exporting Base Data");
|
||||
|
||||
FILE *f = fopen("export/BaseData.txt", "w");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open export/BaseData.txt to write, skipping.");
|
||||
LogError("Unable to open export/BaseData.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -225,11 +224,11 @@ void ExportBaseData(SharedDatabase *db) {
|
||||
}
|
||||
|
||||
void ExportDBStrings(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Exporting DB Strings...");
|
||||
LogInfo("Exporting DB Strings");
|
||||
|
||||
FILE *f = fopen("export/dbstr_us.txt", "w");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open export/dbstr_us.txt to write, skipping.");
|
||||
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -37,19 +37,19 @@ int main(int argc, char **argv) {
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
Log(Logs::General, Logs::Status, "Client Files Import Utility");
|
||||
LogInfo("Client Files Import Utility");
|
||||
if(!EQEmuConfig::LoadConfig()) {
|
||||
Log(Logs::General, Logs::Error, "Unable to load configuration file.");
|
||||
LogError("Unable to load configuration file.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto Config = EQEmuConfig::get();
|
||||
|
||||
SharedDatabase database;
|
||||
Log(Logs::General, Logs::Status, "Connecting to database...");
|
||||
LogInfo("Connecting to database");
|
||||
if(!database.Connect(Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(),
|
||||
Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) {
|
||||
Log(Logs::General, Logs::Error, "Unable to connect to the database, cannot continue without a "
|
||||
LogError("Unable to connect to the database, cannot continue without a "
|
||||
"database connection");
|
||||
return 1;
|
||||
}
|
||||
@ -97,10 +97,10 @@ bool IsStringField(int i) {
|
||||
}
|
||||
|
||||
void ImportSpells(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Importing Spells...");
|
||||
LogInfo("Importing Spells");
|
||||
FILE *f = fopen("import/spells_us.txt", "r");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open import/spells_us.txt to read, skipping.");
|
||||
LogError("Unable to open import/spells_us.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -173,23 +173,23 @@ void ImportSpells(SharedDatabase *db) {
|
||||
|
||||
spells_imported++;
|
||||
if(spells_imported % 1000 == 0) {
|
||||
Log(Logs::General, Logs::Status, "%d spells imported.", spells_imported);
|
||||
LogInfo("[{}] spells imported", spells_imported);
|
||||
}
|
||||
}
|
||||
|
||||
if(spells_imported % 1000 != 0) {
|
||||
Log(Logs::General, Logs::Status, "%d spells imported.", spells_imported);
|
||||
LogInfo("[{}] spells imported", spells_imported);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void ImportSkillCaps(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Importing Skill Caps...");
|
||||
LogInfo("Importing Skill Caps");
|
||||
|
||||
FILE *f = fopen("import/SkillCaps.txt", "r");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open import/SkillCaps.txt to read, skipping.");
|
||||
LogError("Unable to open import/SkillCaps.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -220,11 +220,11 @@ void ImportSkillCaps(SharedDatabase *db) {
|
||||
}
|
||||
|
||||
void ImportBaseData(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Importing Base Data...");
|
||||
LogInfo("Importing Base Data");
|
||||
|
||||
FILE *f = fopen("import/BaseData.txt", "r");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open import/BaseData.txt to read, skipping.");
|
||||
LogError("Unable to open import/BaseData.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -265,11 +265,11 @@ void ImportBaseData(SharedDatabase *db) {
|
||||
}
|
||||
|
||||
void ImportDBStrings(SharedDatabase *db) {
|
||||
Log(Logs::General, Logs::Status, "Importing DB Strings...");
|
||||
LogInfo("Importing DB Strings");
|
||||
|
||||
FILE *f = fopen("import/dbstr_us.txt", "r");
|
||||
if(!f) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open import/dbstr_us.txt to read, skipping.");
|
||||
LogError("Unable to open import/dbstr_us.txt to read, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
SET(common_sources
|
||||
base_packet.cpp
|
||||
classes.cpp
|
||||
cli/eqemu_command_handler.cpp
|
||||
compression.cpp
|
||||
condition.cpp
|
||||
crash.cpp
|
||||
@ -35,6 +36,7 @@ SET(common_sources
|
||||
inventory_profile.cpp
|
||||
inventory_slot.cpp
|
||||
ipc_mutex.cpp
|
||||
ip_util.cpp
|
||||
item_data.cpp
|
||||
item_instance.cpp
|
||||
json_config.cpp
|
||||
@ -71,7 +73,6 @@ SET(common_sources
|
||||
textures.cpp
|
||||
timer.cpp
|
||||
unix.cpp
|
||||
xml_parser.cpp
|
||||
platform.cpp
|
||||
json/jsoncpp.cpp
|
||||
net/console_server.cpp
|
||||
@ -102,13 +103,8 @@ SET(common_sources
|
||||
patches/uf.cpp
|
||||
patches/uf_limits.cpp
|
||||
StackWalker/StackWalker.cpp
|
||||
tinyxml/tinystr.cpp
|
||||
tinyxml/tinyxml.cpp
|
||||
tinyxml/tinyxmlerror.cpp
|
||||
tinyxml/tinyxmlparser.cpp
|
||||
util/directory.cpp
|
||||
util/uuid.cpp
|
||||
)
|
||||
util/uuid.cpp)
|
||||
|
||||
SET(common_headers
|
||||
any.h
|
||||
@ -121,6 +117,9 @@ SET(common_headers
|
||||
crash.h
|
||||
crc16.h
|
||||
crc32.h
|
||||
cli/argh.h
|
||||
cli/eqemu_command_handler.h
|
||||
cli/terminal_color.hpp
|
||||
data_verification.h
|
||||
database.h
|
||||
dbcore.h
|
||||
@ -138,7 +137,7 @@ SET(common_headers
|
||||
eqemu_config.h
|
||||
eqemu_config_elements.h
|
||||
eqemu_logsys.h
|
||||
eqemu_logsys_fmt.h
|
||||
eqemu_logsys_log_aliases.h
|
||||
eq_limits.h
|
||||
eq_packet.h
|
||||
eq_stream_ident.h
|
||||
@ -156,9 +155,11 @@ SET(common_headers
|
||||
global_define.h
|
||||
guild_base.h
|
||||
guilds.h
|
||||
http/httplib.h
|
||||
inventory_profile.h
|
||||
inventory_slot.h
|
||||
ipc_mutex.h
|
||||
ip_util.h
|
||||
item_data.h
|
||||
item_fieldlist.h
|
||||
item_instance.h
|
||||
@ -209,7 +210,6 @@ SET(common_headers
|
||||
unix.h
|
||||
useperl.h
|
||||
version.h
|
||||
xml_parser.h
|
||||
zone_numbers.h
|
||||
event/event_loop.h
|
||||
event/task.h
|
||||
@ -263,12 +263,9 @@ SET(common_headers
|
||||
patches/uf_ops.h
|
||||
patches/uf_structs.h
|
||||
StackWalker/StackWalker.h
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
util/memory_stream.h
|
||||
util/directory.h
|
||||
util/uuid.h
|
||||
)
|
||||
util/uuid.h)
|
||||
|
||||
SOURCE_GROUP(Event FILES
|
||||
event/event_loop.h
|
||||
@ -368,15 +365,6 @@ SOURCE_GROUP(StackWalker FILES
|
||||
StackWalker/StackWalker.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(TinyXML FILES
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
tinyxml/tinystr.cpp
|
||||
tinyxml/tinyxml.cpp
|
||||
tinyxml/tinyxmlerror.cpp
|
||||
tinyxml/tinyxmlparser.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Util FILES
|
||||
util/memory_stream.h
|
||||
util/directory.cpp
|
||||
@ -385,7 +373,7 @@ SOURCE_GROUP(Util FILES
|
||||
util/uuid.h
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker)
|
||||
|
||||
ADD_LIBRARY(common ${common_sources} ${common_headers})
|
||||
|
||||
|
||||
434
common/cli/argh.h
Normal file
434
common/cli/argh.h
Normal file
@ -0,0 +1,434 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
namespace argh
|
||||
{
|
||||
// Terminology:
|
||||
// A command line is composed of 2 types of args:
|
||||
// 1. Positional args, i.e. free standing values
|
||||
// 2. Options: args beginning with '-'. We identify two kinds:
|
||||
// 2.1: Flags: boolean options => (exist ? true : false)
|
||||
// 2.2: Parameters: a name followed by a non-option value
|
||||
|
||||
#if !defined(__GNUC__) || (__GNUC__ >= 5)
|
||||
using string_stream = std::istringstream;
|
||||
#else
|
||||
// Until GCC 5, istringstream did not have a move constructor.
|
||||
// stringstream_proxy is used instead, as a workaround.
|
||||
class stringstream_proxy
|
||||
{
|
||||
public:
|
||||
stringstream_proxy() = default;
|
||||
|
||||
// Construct with a value.
|
||||
stringstream_proxy(std::string const& value) :
|
||||
stream_(value)
|
||||
{}
|
||||
|
||||
// Copy constructor.
|
||||
stringstream_proxy(const stringstream_proxy& other) :
|
||||
stream_(other.stream_.str())
|
||||
{
|
||||
stream_.setstate(other.stream_.rdstate());
|
||||
}
|
||||
|
||||
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
|
||||
|
||||
// Stream out the value of the parameter.
|
||||
// If the conversion was not possible, the stream will enter the fail state,
|
||||
// and operator bool will return false.
|
||||
template<typename T>
|
||||
stringstream_proxy& operator >> (T& thing)
|
||||
{
|
||||
stream_ >> thing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Get the string value.
|
||||
std::string str() const { return stream_.str(); }
|
||||
|
||||
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
|
||||
|
||||
// Check the state of the stream.
|
||||
// False when the most recent stream operation failed
|
||||
operator bool() const { return !!stream_; }
|
||||
|
||||
~stringstream_proxy() = default;
|
||||
private:
|
||||
std::istringstream stream_;
|
||||
};
|
||||
using string_stream = stringstream_proxy;
|
||||
#endif
|
||||
|
||||
class parser
|
||||
{
|
||||
public:
|
||||
enum Mode { PREFER_FLAG_FOR_UNREG_OPTION = 1 << 0,
|
||||
PREFER_PARAM_FOR_UNREG_OPTION = 1 << 1,
|
||||
NO_SPLIT_ON_EQUALSIGN = 1 << 2,
|
||||
SINGLE_DASH_IS_MULTIFLAG = 1 << 3,
|
||||
};
|
||||
|
||||
parser() = default;
|
||||
|
||||
parser(std::initializer_list<char const* const> pre_reg_names)
|
||||
{ add_params(pre_reg_names); }
|
||||
|
||||
parser(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argv, mode); }
|
||||
|
||||
parser(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argc, argv, mode); }
|
||||
|
||||
void add_param(std::string const& name);
|
||||
void add_params(std::initializer_list<char const* const> init_list);
|
||||
|
||||
void parse(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
void parse(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
|
||||
std::multiset<std::string> const& flags() const { return flags_; }
|
||||
std::map<std::string, std::string> const& params() const { return params_; }
|
||||
std::vector<std::string> const& pos_args() const { return pos_args_; }
|
||||
|
||||
// begin() and end() for using range-for over positional args.
|
||||
std::vector<std::string>::const_iterator begin() const { return pos_args_.cbegin(); }
|
||||
std::vector<std::string>::const_iterator end() const { return pos_args_.cend(); }
|
||||
size_t size() const { return pos_args_.size(); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
|
||||
// flag (boolean) accessors: return true if the flag appeared, otherwise false.
|
||||
bool operator[](std::string const& name) const;
|
||||
|
||||
// multiple flag (boolean) accessors: return true if at least one of the flag appeared, otherwise false.
|
||||
bool operator[](std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// returns positional arg string by order. Like argv[] but without the options
|
||||
std::string const& operator[](size_t ind) const;
|
||||
|
||||
// returns a std::istream that can be used to convert a positional arg to a typed value.
|
||||
string_stream operator()(size_t ind) const;
|
||||
|
||||
// same as above, but with a default value in case the arg is missing (index out of range).
|
||||
template<typename T>
|
||||
string_stream operator()(size_t ind, T&& def_val) const;
|
||||
|
||||
// parameter accessors, give a name get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
string_stream operator()(std::string const& name) const;
|
||||
|
||||
// accessor for a parameter with multiple names, give a list of names, get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
// returns the first value in the list to be found.
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// same as above, but with a default value in case the param was missing.
|
||||
// Non-string def_val types must have an operator<<() (output stream operator)
|
||||
// If T only has an input stream operator, pass the string version of the type as in "3" instead of 3.
|
||||
template<typename T>
|
||||
string_stream operator()(std::string const& name, T&& def_val) const;
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list, T&& def_val) const;
|
||||
|
||||
private:
|
||||
string_stream bad_stream() const;
|
||||
std::string trim_leading_dashes(std::string const& name) const;
|
||||
bool is_number(std::string const& arg) const;
|
||||
bool is_option(std::string const& arg) const;
|
||||
bool got_flag(std::string const& name) const;
|
||||
bool is_param(std::string const& name) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> args_;
|
||||
std::map<std::string, std::string> params_;
|
||||
std::vector<std::string> pos_args_;
|
||||
std::multiset<std::string> flags_;
|
||||
std::set<std::string> registeredParams_;
|
||||
std::string empty_;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(const char * const argv[], int mode)
|
||||
{
|
||||
int argc = 0;
|
||||
for (auto argvp = argv; *argvp; ++argc, ++argvp);
|
||||
parse(argc, argv, mode);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)
|
||||
{
|
||||
// convert to strings
|
||||
args_.resize(argc);
|
||||
std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });
|
||||
|
||||
// parse line
|
||||
for (auto i = 0u; i < args_.size(); ++i)
|
||||
{
|
||||
if (!is_option(args_[i]))
|
||||
{
|
||||
pos_args_.emplace_back(args_[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name = trim_leading_dashes(args_[i]);
|
||||
|
||||
if (!(mode & NO_SPLIT_ON_EQUALSIGN))
|
||||
{
|
||||
auto equalPos = name.find('=');
|
||||
if (equalPos != std::string::npos)
|
||||
{
|
||||
params_.insert({ name.substr(0, equalPos), name.substr(equalPos + 1) });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if the option is unregistered and should be a multi-flag
|
||||
if (1 == (args_[i].size() - name.size()) && // single dash
|
||||
argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode
|
||||
!is_param(name)) // unregistered
|
||||
{
|
||||
std::string keep_param;
|
||||
|
||||
if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param
|
||||
{
|
||||
keep_param += name.back();
|
||||
name.resize(name.size() - 1);
|
||||
}
|
||||
|
||||
for (auto const& c : name)
|
||||
{
|
||||
flags_.emplace(std::string{ c });
|
||||
}
|
||||
|
||||
if (!keep_param.empty())
|
||||
{
|
||||
name = keep_param;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // do not consider other options for this arg
|
||||
}
|
||||
}
|
||||
|
||||
// any potential option will get as its value the next arg, unless that arg is an option too
|
||||
// in that case it will be determined a flag.
|
||||
if (i == args_.size() - 1 || is_option(args_[i + 1]))
|
||||
{
|
||||
flags_.emplace(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped
|
||||
// otherwise we have 2 modes:
|
||||
// PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
|
||||
// The following value (the next arg) will be a free parameter.
|
||||
//
|
||||
// PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg
|
||||
// will be the value of that option.
|
||||
|
||||
assert(!(mode & argh::parser::PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
|| !(mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION));
|
||||
|
||||
bool preferParam = mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION;
|
||||
|
||||
if (is_param(name) || preferParam)
|
||||
{
|
||||
params_.insert({ name, args_[i + 1] });
|
||||
++i; // skip next value, it is not a free parameter
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_.emplace(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::bad_stream() const
|
||||
{
|
||||
string_stream bad;
|
||||
bad.setstate(std::ios_base::failbit);
|
||||
return bad;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_number(std::string const& arg) const
|
||||
{
|
||||
// inefficient but simple way to determine if a string is a number (which can start with a '-')
|
||||
std::istringstream istr(arg);
|
||||
double number;
|
||||
istr >> number;
|
||||
return !(istr.fail() || istr.bad());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_option(std::string const& arg) const
|
||||
{
|
||||
assert(0 != arg.size());
|
||||
if (is_number(arg))
|
||||
return false;
|
||||
return '-' == arg[0];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string parser::trim_leading_dashes(std::string const& name) const
|
||||
{
|
||||
auto pos = name.find_first_not_of('-');
|
||||
return std::string::npos != pos ? name.substr(pos) : name;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::got_flag(std::string const& name) const
|
||||
{
|
||||
return flags_.end() != flags_.find(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::is_param(std::string const& name) const
|
||||
{
|
||||
return registeredParams_.count(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::string const& name) const
|
||||
{
|
||||
return got_flag(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
return std::any_of(init_list.begin(), init_list.end(), [&](char const* const name) { return got_flag(name); });
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string const& parser::operator[](size_t ind) const
|
||||
{
|
||||
if (ind < pos_args_.size())
|
||||
return pos_args_[ind];
|
||||
return empty_;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::string const& name) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::string const& name, T&& def_val) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::initializer_list<char const* const> init_list, T&& def_val) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(size_t ind) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
return bad_stream();
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(size_t ind, T&& def_val) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str());
|
||||
}
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_param(std::string const& name)
|
||||
{
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_params(std::initializer_list<char const* const> init_list)
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
}
|
||||
193
common/cli/eqemu_command_handler.cpp
Normal file
193
common/cli/eqemu_command_handler.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "eqemu_command_handler.h"
|
||||
#include "terminal_color.hpp"
|
||||
#include "../platform.h"
|
||||
|
||||
namespace EQEmuCommand {
|
||||
|
||||
std::map<std::string, void (*)(
|
||||
int argc,
|
||||
char **argv,
|
||||
argh::parser &cmd,
|
||||
std::string &description
|
||||
)> function_map;
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
*/
|
||||
void DisplayDebug(argh::parser &cmd)
|
||||
{
|
||||
if (cmd[{"-d", "--debug"}]) {
|
||||
std::cout << "Positional args:\n";
|
||||
for (auto &pos_arg : cmd)
|
||||
std::cout << '\t' << pos_arg << std::endl;
|
||||
|
||||
std::cout << "Positional args:\n";
|
||||
for (auto &pos_arg : cmd.pos_args())
|
||||
std::cout << '\t' << pos_arg << std::endl;
|
||||
|
||||
std::cout << "\nFlags:\n";
|
||||
for (auto &flag : cmd.flags())
|
||||
std::cout << '\t' << flag << std::endl;
|
||||
|
||||
std::cout << "\nParameters:\n";
|
||||
for (auto ¶m : cmd.params())
|
||||
std::cout << '\t' << param.first << " : " << param.second << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param arguments
|
||||
* @param options
|
||||
* @param cmd
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void ValidateCmdInput(
|
||||
std::vector<std::string> &arguments,
|
||||
std::vector<std::string> &options,
|
||||
argh::parser &cmd,
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
bool arguments_filled = true;
|
||||
|
||||
for (auto &arg : arguments) {
|
||||
if (cmd(arg).str().empty()) {
|
||||
arguments_filled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arguments_filled || argc == 2) {
|
||||
std::string arguments_string;
|
||||
for (auto &arg : arguments) {
|
||||
arguments_string += " " + arg + "=*\n";
|
||||
}
|
||||
|
||||
std::string options_string;
|
||||
for (auto &opt : options) {
|
||||
options_string += " " + opt + "\n";
|
||||
}
|
||||
|
||||
std::cout << fmt::format(
|
||||
"Command\n\n{0} \n\nArgs\n{1}\nOptions\n{2}",
|
||||
argv[1],
|
||||
arguments_string,
|
||||
options_string
|
||||
) << std::endl;
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_function_map
|
||||
* @param cmd
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void HandleMenu(
|
||||
std::map<std::string, void (*)(
|
||||
int argc,
|
||||
char **argv,
|
||||
argh::parser &cmd,
|
||||
std::string &description
|
||||
)> &in_function_map,
|
||||
argh::parser &cmd,
|
||||
int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
std::string description;
|
||||
bool ran_command = false;
|
||||
for (auto &it: in_function_map) {
|
||||
if (it.first == argv[1]) {
|
||||
std::cout << std::endl;
|
||||
std::cout << "> " << termcolor::cyan << "Executing CLI Command" << termcolor::reset << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
(it.second)(argc, argv, cmd, description);
|
||||
ran_command = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
std::cout << std::endl;
|
||||
std::cout <<
|
||||
"> " <<
|
||||
termcolor::yellow <<
|
||||
"EQEmulator [" + GetPlatformName() + "] CLI Menu" <<
|
||||
termcolor::reset
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
|
||||
/**
|
||||
* Get max command length for padding length
|
||||
*/
|
||||
int max_command_length = 0;
|
||||
|
||||
for (auto &it: in_function_map) {
|
||||
std::stringstream command;
|
||||
command << termcolor::colorize << termcolor::yellow << it.first << termcolor::reset;
|
||||
if (command.str().length() > max_command_length) {
|
||||
max_command_length = command.str().length() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display command menu
|
||||
*/
|
||||
std::string command_section;
|
||||
for (auto &it: in_function_map) {
|
||||
description = "";
|
||||
|
||||
(it.second)(argc, argv, cmd, description);
|
||||
|
||||
/**
|
||||
* Print section header
|
||||
*/
|
||||
std::string command_prefix = it.first.substr(0, it.first.find(":"));
|
||||
if (command_section != command_prefix) {
|
||||
command_section = command_prefix;
|
||||
std::cout << termcolor::reset << command_prefix << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print commands
|
||||
*/
|
||||
std::stringstream command;
|
||||
command << termcolor::colorize << termcolor::yellow << it.first << termcolor::reset;
|
||||
printf(" %-*s %s\n", max_command_length, command.str().c_str(), description.c_str());
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
else if (!ran_command) {
|
||||
std::cerr << "Unknown command [" << argv[1] << "] ! Try --help" << std::endl;
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
75
common/cli/eqemu_command_handler.h
Normal file
75
common/cli/eqemu_command_handler.h
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_EQEMU_COMMAND_HANDLER_H
|
||||
#define EQEMU_EQEMU_COMMAND_HANDLER_H
|
||||
|
||||
#include "argh.h"
|
||||
|
||||
namespace EQEmuCommand {
|
||||
|
||||
extern std::map<std::string, void (*)(
|
||||
int argc,
|
||||
char **argv,
|
||||
argh::parser &cmd,
|
||||
std::string &description
|
||||
)> function_map;
|
||||
|
||||
/**
|
||||
* @param arguments
|
||||
* @param options
|
||||
* @param cmd
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void ValidateCmdInput(
|
||||
std::vector<std::string> &arguments,
|
||||
std::vector<std::string> &options,
|
||||
argh::parser &cmd,
|
||||
int argc,
|
||||
char **argv
|
||||
);
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
*/
|
||||
void DisplayDebug(argh::parser &cmd);
|
||||
|
||||
/**
|
||||
* @param in_function_map
|
||||
* @param cmd
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void HandleMenu(
|
||||
std::map<std::string, void (*)(
|
||||
int argc,
|
||||
char **argv,
|
||||
argh::parser &cmd,
|
||||
std::string &description
|
||||
)> &in_function_map,
|
||||
argh::parser &cmd,
|
||||
int argc,
|
||||
char **argv
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_EQEMU_COMMAND_HANDLER_H
|
||||
557
common/cli/terminal_color.hpp
Normal file
557
common/cli/terminal_color.hpp
Normal file
@ -0,0 +1,557 @@
|
||||
//!
|
||||
//! termcolor
|
||||
//! ~~~~~~~~~
|
||||
//!
|
||||
//! termcolor is a header-only c++ library for printing colored messages
|
||||
//! to the terminal. Written just for fun with a help of the Force.
|
||||
//!
|
||||
//! :copyright: (c) 2013 by Ihor Kalnytskyi
|
||||
//! :license: BSD, see LICENSE for details
|
||||
//!
|
||||
|
||||
#ifndef TERMCOLOR_HPP_
|
||||
#define TERMCOLOR_HPP_
|
||||
|
||||
// the following snippet of code detects the current OS and
|
||||
// defines the appropriate macro that is used to wrap some
|
||||
// platform specific things
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# define TERMCOLOR_OS_WINDOWS
|
||||
#elif defined(__APPLE__)
|
||||
# define TERMCOLOR_OS_MACOS
|
||||
#elif defined(__unix__) || defined(__unix)
|
||||
# define TERMCOLOR_OS_LINUX
|
||||
#else
|
||||
# error unsupported platform
|
||||
#endif
|
||||
|
||||
|
||||
// This headers provides the `isatty()`/`fileno()` functions,
|
||||
// which are used for testing whether a standart stream refers
|
||||
// to the terminal. As for Windows, we also need WinApi funcs
|
||||
// for changing colors attributes of the terminal.
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
# include <unistd.h>
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
|
||||
namespace termcolor
|
||||
{
|
||||
// Forward declaration of the `_internal` namespace.
|
||||
// All comments are below.
|
||||
namespace _internal
|
||||
{
|
||||
// An index to be used to access a private storage of I/O streams. See
|
||||
// colorize / nocolorize I/O manipulators for details.
|
||||
static int colorize_index = std::ios_base::xalloc();
|
||||
|
||||
inline FILE* get_standard_stream(const std::ostream& stream);
|
||||
inline bool is_colorized(std::ostream& stream);
|
||||
inline bool is_atty(const std::ostream& stream);
|
||||
|
||||
#if defined(TERMCOLOR_OS_WINDOWS)
|
||||
inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& colorize(std::ostream& stream)
|
||||
{
|
||||
stream.iword(_internal::colorize_index) = 1L;
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& nocolorize(std::ostream& stream)
|
||||
{
|
||||
stream.iword(_internal::colorize_index) = 0L;
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& reset(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;00m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, -1);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& bold(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;1m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& dark(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;2m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& underline(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;4m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& blink(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;5m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& reverse(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;7m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& concealed(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;8m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& grey(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;30m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
0 // grey (black)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& red(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;31m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& green(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;32m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_GREEN
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& yellow(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;33m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_GREEN | FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& blue(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;34m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& magenta(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;35m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE | FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& cyan(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;36m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& white(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;37m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& on_grey(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;40m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
0 // grey (black)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_red(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;41m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_green(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;42m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_yellow(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;43m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN | BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_blue(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;44m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_BLUE
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_magenta(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;45m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_BLUE | BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_cyan(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;46m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_white(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\e[1;47m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Since C++ hasn't a way to hide something in the header from
|
||||
//! the outer access, I have to introduce this namespace which
|
||||
//! is used for internal purpose and should't be access from
|
||||
//! the user code.
|
||||
namespace _internal
|
||||
{
|
||||
//! Since C++ hasn't a true way to extract stream handler
|
||||
//! from the a given `std::ostream` object, I have to write
|
||||
//! this kind of hack.
|
||||
inline
|
||||
FILE* get_standard_stream(const std::ostream& stream)
|
||||
{
|
||||
if (&stream == &std::cout)
|
||||
return stdout;
|
||||
else if ((&stream == &std::cerr) || (&stream == &std::clog))
|
||||
return stderr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Say whether a given stream should be colorized or not. It's always
|
||||
// true for ATTY streams and may be true for streams marked with
|
||||
// colorize flag.
|
||||
inline
|
||||
bool is_colorized(std::ostream& stream)
|
||||
{
|
||||
return is_atty(stream) || static_cast<bool>(stream.iword(colorize_index));
|
||||
}
|
||||
|
||||
//! Test whether a given `std::ostream` object refers to
|
||||
//! a terminal.
|
||||
inline
|
||||
bool is_atty(const std::ostream& stream)
|
||||
{
|
||||
FILE* std_stream = get_standard_stream(stream);
|
||||
|
||||
// Unfortunately, fileno() ends with segmentation fault
|
||||
// if invalid file descriptor is passed. So we need to
|
||||
// handle this case gracefully and assume it's not a tty
|
||||
// if standard stream is not detected, and 0 is returned.
|
||||
if (!std_stream)
|
||||
return false;
|
||||
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
return ::isatty(fileno(std_stream));
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
return ::_isatty(_fileno(std_stream));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TERMCOLOR_OS_WINDOWS)
|
||||
//! Change Windows Terminal colors attribute. If some
|
||||
//! parameter is `-1` then attribute won't changed.
|
||||
inline void win_change_attributes(std::ostream& stream, int foreground, int background)
|
||||
{
|
||||
// yeah, i know.. it's ugly, it's windows.
|
||||
static WORD defaultAttributes = 0;
|
||||
|
||||
// Windows doesn't have ANSI escape sequences and so we use special
|
||||
// API to change Terminal output color. That means we can't
|
||||
// manipulate colors by means of "std::stringstream" and hence
|
||||
// should do nothing in this case.
|
||||
if (!_internal::is_atty(stream))
|
||||
return;
|
||||
|
||||
// get terminal handle
|
||||
HANDLE hTerminal = INVALID_HANDLE_VALUE;
|
||||
if (&stream == &std::cout)
|
||||
hTerminal = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
else if (&stream == &std::cerr)
|
||||
hTerminal = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
// save default terminal attributes if it unsaved
|
||||
if (!defaultAttributes)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (!GetConsoleScreenBufferInfo(hTerminal, &info))
|
||||
return;
|
||||
defaultAttributes = info.wAttributes;
|
||||
}
|
||||
|
||||
// restore all default settings
|
||||
if (foreground == -1 && background == -1)
|
||||
{
|
||||
SetConsoleTextAttribute(hTerminal, defaultAttributes);
|
||||
return;
|
||||
}
|
||||
|
||||
// get current settings
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (!GetConsoleScreenBufferInfo(hTerminal, &info))
|
||||
return;
|
||||
|
||||
if (foreground != -1)
|
||||
{
|
||||
info.wAttributes &= ~(info.wAttributes & 0x0F);
|
||||
info.wAttributes |= static_cast<WORD>(foreground);
|
||||
}
|
||||
|
||||
if (background != -1)
|
||||
{
|
||||
info.wAttributes &= ~(info.wAttributes & 0xF0);
|
||||
info.wAttributes |= static_cast<WORD>(background);
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(hTerminal, info.wAttributes);
|
||||
}
|
||||
#endif // TERMCOLOR_OS_WINDOWS
|
||||
|
||||
} // namespace _internal
|
||||
|
||||
} // namespace termcolor
|
||||
|
||||
|
||||
#undef TERMCOLOR_OS_WINDOWS
|
||||
#undef TERMCOLOR_OS_MACOS
|
||||
#undef TERMCOLOR_OS_LINUX
|
||||
|
||||
#endif // TERMCOLOR_HPP_
|
||||
@ -1,53 +1,57 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
template <typename T>
|
||||
T Clamp(const T& value, const T& lower, const T& upper) {
|
||||
namespace EQEmu {
|
||||
template<typename T>
|
||||
T Clamp(const T &value, const T &lower, const T &upper)
|
||||
{
|
||||
return std::max(lower, std::min(value, upper));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ClampLower(const T& value, const T& lower) {
|
||||
template<typename T>
|
||||
T ClampLower(const T &value, const T &lower)
|
||||
{
|
||||
return std::max(lower, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ClampUpper(const T& value, const T& upper) {
|
||||
template<typename T>
|
||||
T ClampUpper(const T &value, const T &upper)
|
||||
{
|
||||
return std::min(value, upper);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ValueWithin(const T& value, const T& lower, const T& upper) {
|
||||
template<typename T>
|
||||
bool ValueWithin(const T &value, const T &lower, const T &upper)
|
||||
{
|
||||
return value >= lower && value <= upper;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
bool ValueWithin(const T1& value, const T2& lower, const T3& upper) {
|
||||
return value >= (T1)lower && value <= (T1)upper;
|
||||
template<typename T1, typename T2, typename T3>
|
||||
bool ValueWithin(const T1 &value, const T2 &lower, const T3 &upper)
|
||||
{
|
||||
return value >= (T1) lower && value <= (T1) upper;
|
||||
}
|
||||
|
||||
} /*EQEmu*/
|
||||
|
||||
|
||||
@ -64,11 +64,11 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c
|
||||
uint32 errnum= 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!Open(host, user, passwd, database, port, &errnum, errbuf)) {
|
||||
Log(Logs::General, Logs::Error, "Failed to connect to database: Error: %s", errbuf);
|
||||
return false;
|
||||
LogError("Failed to connect to database: Error: {}", errbuf);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::Status, "Using database '%s' at %s:%d", database, host,port);
|
||||
LogInfo("Using database [{}] at [{}]:[{}]", database, host,port);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -86,7 +86,7 @@ Database::~Database()
|
||||
Return the account id or zero if no account matches.
|
||||
Zero will also be returned if there is a database error.
|
||||
*/
|
||||
uint32 Database::CheckLogin(const char* name, const char* password, int16* oStatus) {
|
||||
uint32 Database::CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus) {
|
||||
|
||||
if(strlen(name) >= 50 || strlen(password) >= 50)
|
||||
return(0);
|
||||
@ -97,9 +97,10 @@ uint32 Database::CheckLogin(const char* name, const char* password, int16* oStat
|
||||
DoEscapeString(tmpUN, name, strlen(name));
|
||||
DoEscapeString(tmpPW, password, strlen(password));
|
||||
|
||||
std::string query = StringFormat("SELECT id, status FROM account WHERE name='%s' AND password is not null "
|
||||
std::string query = StringFormat("SELECT id, status FROM account WHERE name='%s' AND ls_id='%s' AND password is not null "
|
||||
"and length(password) > 0 and (password='%s' or password=MD5('%s'))",
|
||||
tmpUN, tmpPW, tmpPW);
|
||||
tmpUN, EscapeString(loginserver).c_str(), tmpPW, tmpPW);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
@ -139,16 +140,16 @@ bool Database::CheckBannedIPs(const char* loginIP)
|
||||
}
|
||||
|
||||
bool Database::AddBannedIP(char* bannedIP, const char* notes) {
|
||||
std::string query = StringFormat("INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes);
|
||||
auto results = QueryDatabase(query);
|
||||
std::string query = StringFormat("INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::CheckGMIPs(const char* ip_address, uint32 account_id) {
|
||||
std::string query = StringFormat("SELECT * FROM `gm_ips` WHERE `ip_address` = '%s' AND `account_id` = %i", ip_address, account_id);
|
||||
std::string query = StringFormat("SELECT * FROM `gm_ips` WHERE `ip_address` = '%s' AND `account_id` = %i", ip_address, account_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
@ -161,14 +162,14 @@ bool Database::AddBannedIP(char* bannedIP, const char* notes) {
|
||||
}
|
||||
|
||||
bool Database::AddGMIP(char* ip_address, char* name) {
|
||||
std::string query = StringFormat("INSERT into `gm_ips` SET `ip_address` = '%s', `name` = '%s'", ip_address, name);
|
||||
auto results = QueryDatabase(query);
|
||||
std::string query = StringFormat("INSERT into `gm_ips` SET `ip_address` = '%s', `name` = '%s'", ip_address, name);
|
||||
auto results = QueryDatabase(query);
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
void Database::LoginIP(uint32 AccountID, const char* LoginIP) {
|
||||
std::string query = StringFormat("INSERT INTO account_ip SET accid=%i, ip='%s' ON DUPLICATE KEY UPDATE count=count+1, lastused=now()", AccountID, LoginIP);
|
||||
QueryDatabase(query);
|
||||
std::string query = StringFormat("INSERT INTO account_ip SET accid=%i, ip='%s' ON DUPLICATE KEY UPDATE count=count+1, lastused=now()", AccountID, LoginIP);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
int16 Database::CheckStatus(uint32 account_id)
|
||||
@ -197,34 +198,63 @@ int16 Database::CheckStatus(uint32 account_id)
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32 Database::CreateAccount(const char* name, const char* password, int16 status, uint32 lsaccount_id) {
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param status
|
||||
* @param loginserver
|
||||
* @param lsaccount_id
|
||||
* @return
|
||||
*/
|
||||
uint32 Database::CreateAccount(
|
||||
const char *name,
|
||||
const char *password,
|
||||
int16 status,
|
||||
const char *loginserver,
|
||||
uint32 lsaccount_id
|
||||
)
|
||||
{
|
||||
std::string query;
|
||||
|
||||
if (password)
|
||||
query = StringFormat("INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id=%i, time_creation=UNIX_TIMESTAMP();",name,password,status, lsaccount_id);
|
||||
else
|
||||
query = StringFormat("INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i, time_creation=UNIX_TIMESTAMP();",name, status, lsaccount_id);
|
||||
if (password) {
|
||||
query = StringFormat(
|
||||
"INSERT INTO account SET name='%s', password='%s', status=%i, ls_id='%s', lsaccount_id=%i, time_creation=UNIX_TIMESTAMP();",
|
||||
name,
|
||||
password,
|
||||
status,
|
||||
loginserver,
|
||||
lsaccount_id
|
||||
);
|
||||
}
|
||||
else {
|
||||
query = StringFormat(
|
||||
"INSERT INTO account SET name='%s', status=%i, ls_id='%s', lsaccount_id=%i, time_creation=UNIX_TIMESTAMP();",
|
||||
name,
|
||||
status,
|
||||
loginserver,
|
||||
lsaccount_id
|
||||
);
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::World_Server, "Account Attempting to be created: '%s' status: %i", name, status);
|
||||
LogInfo("Account Attempting to be created: [{0}:{1}] status: {2}", loginserver, name, status);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.LastInsertedID() == 0)
|
||||
{
|
||||
if (results.LastInsertedID() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return results.LastInsertedID();
|
||||
}
|
||||
|
||||
bool Database::DeleteAccount(const char* name) {
|
||||
std::string query = StringFormat("DELETE FROM account WHERE name='%s';",name);
|
||||
Log(Logs::General, Logs::World_Server, "Account Attempting to be deleted:'%s'", name);
|
||||
bool Database::DeleteAccount(const char* name, const char *loginserver) {
|
||||
std::string query = StringFormat("DELETE FROM account WHERE name='%s' AND ls_id='%s'", name, loginserver);
|
||||
LogInfo("Account Attempting to be deleted:'[{}]:[{}]'", loginserver, name);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
@ -257,7 +287,7 @@ bool Database::SetAccountStatus(const char* name, int16 status) {
|
||||
if (results.RowsAffected() == 0)
|
||||
{
|
||||
std::cout << "Account: " << name << " does not exist, therefore it cannot be flagged\n";
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -269,14 +299,14 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (row[0] && atoi(row[0]) > 0){
|
||||
Log(Logs::General, Logs::World_Server, "Account: %i tried to request name: %s, but it is already taken...", account_id, name);
|
||||
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name);
|
||||
query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success() || results.ErrorMessage() != ""){ return false; }
|
||||
if (!results.Success() || results.ErrorMessage() != ""){ return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -287,18 +317,18 @@ bool Database::ReserveName(uint32 account_id, char* name) {
|
||||
bool Database::DeleteCharacter(char *name) {
|
||||
uint32 charid = 0;
|
||||
if(!name || !strlen(name)) {
|
||||
Log(Logs::General, Logs::World_Server, "DeleteCharacter: request to delete without a name (empty char slot)");
|
||||
LogInfo("DeleteCharacter: request to delete without a name (empty char slot)");
|
||||
return false;
|
||||
}
|
||||
Log(Logs::General, Logs::World_Server, "Database::DeleteCharacter name : '%s'", name);
|
||||
LogInfo("Database::DeleteCharacter name : [{}]", name);
|
||||
|
||||
/* Get id from character_data before deleting record so we can clean up the rest of the tables */
|
||||
std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", name);
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) { charid = atoi(row[0]); }
|
||||
if (charid <= 0){
|
||||
Log(Logs::General, Logs::Error, "Database::DeleteCharacter :: Character (%s) not found, stopping delete...", name);
|
||||
return false;
|
||||
if (charid <= 0){
|
||||
LogError("Database::DeleteCharacter :: Character ({}) not found, stopping delete...", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", charid); QueryDatabase(query);
|
||||
@ -341,7 +371,7 @@ bool Database::DeleteCharacter(char *name) {
|
||||
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", charid);
|
||||
#endif
|
||||
QueryDatabase(query);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -656,7 +686,7 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
|
||||
}
|
||||
}
|
||||
}
|
||||
results = QueryDatabase(query);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
/* Save Language */
|
||||
firstquery = 0;
|
||||
@ -671,20 +701,20 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
|
||||
}
|
||||
}
|
||||
}
|
||||
results = QueryDatabase(query);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This only for new Character creation storing */
|
||||
bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, EQEmu::InventoryProfile* inv) {
|
||||
uint32 charid = 0;
|
||||
char zone[50];
|
||||
float x, y, z;
|
||||
uint32 charid = 0;
|
||||
char zone[50];
|
||||
float x, y, z;
|
||||
charid = GetCharacterID(pp->name);
|
||||
|
||||
if(!charid) {
|
||||
Log(Logs::General, Logs::Error, "StoreCharacter: no character id");
|
||||
LogError("StoreCharacter: no character id");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -701,7 +731,7 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, EQEmu
|
||||
z = pp->z;
|
||||
|
||||
/* Saves Player Profile Data */
|
||||
SaveCharacterCreate(charid, account_id, pp);
|
||||
SaveCharacterCreate(charid, account_id, pp);
|
||||
|
||||
/* Insert starting inventory... */
|
||||
std::string invquery;
|
||||
@ -709,23 +739,23 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, EQEmu
|
||||
const EQEmu::ItemInstance* newinv = inv->GetItem(i);
|
||||
if (newinv) {
|
||||
invquery = StringFormat("INSERT INTO `inventory` (charid, slotid, itemid, charges, color) VALUES (%u, %i, %u, %i, %u)",
|
||||
charid, i, newinv->GetItem()->ID, newinv->GetCharges(), newinv->GetColor());
|
||||
|
||||
auto results = QueryDatabase(invquery);
|
||||
charid, i, newinv->GetItem()->ID, newinv->GetCharges(), newinv->GetColor());
|
||||
|
||||
auto results = QueryDatabase(invquery);
|
||||
}
|
||||
|
||||
if (i == EQEmu::invslot::slotCursor) {
|
||||
i = EQEmu::invbag::GENERAL_BAGS_BEGIN;
|
||||
i = EQEmu::invbag::GENERAL_BAGS_BEGIN;
|
||||
continue;
|
||||
}
|
||||
else if (i == EQEmu::invbag::CURSOR_BAG_END) {
|
||||
i = EQEmu::invslot::BANK_BEGIN;
|
||||
continue;
|
||||
else if (i == EQEmu::invbag::CURSOR_BAG_END) {
|
||||
i = EQEmu::invslot::BANK_BEGIN;
|
||||
continue;
|
||||
}
|
||||
else if (i == EQEmu::invslot::BANK_END) {
|
||||
i = EQEmu::invbag::BANK_BAGS_BEGIN;
|
||||
continue;
|
||||
}
|
||||
else if (i == EQEmu::invslot::BANK_END) {
|
||||
i = EQEmu::invbag::BANK_BAGS_BEGIN;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
@ -739,7 +769,7 @@ uint32 Database::GetCharacterID(const char *name) {
|
||||
{
|
||||
return atoi(row[0]);
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -758,7 +788,7 @@ uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
@ -772,8 +802,8 @@ uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
|
||||
|
||||
// Retrieve account_id for a given char_id
|
||||
uint32 Database::GetAccountIDByChar(uint32 char_id) {
|
||||
std::string query = StringFormat("SELECT `account_id` FROM `character_data` WHERE `id` = %i LIMIT 1", char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
std::string query = StringFormat("SELECT `account_id` FROM `character_data` WHERE `id` = %i LIMIT 1", char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return 0;
|
||||
}
|
||||
@ -781,15 +811,16 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetAccountIDByName(const char* accname, int16* status, uint32* lsid) {
|
||||
uint32 Database::GetAccountIDByName(const char* accname, const char *loginserver, int16* status, uint32* lsid) {
|
||||
if (!isAlphaNumeric(accname))
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `id`, `status`, `lsaccount_id` FROM `account` WHERE `name` = '%s' LIMIT 1", accname);
|
||||
std::string query = StringFormat("SELECT `id`, `status`, `lsaccount_id` FROM `account` WHERE `name` = '%s' AND `ls_id`='%s' LIMIT 1",
|
||||
EscapeString(accname).c_str(), EscapeString(loginserver).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
@ -817,7 +848,7 @@ uint32 Database::GetAccountIDByName(const char* accname, int16* status, uint32*
|
||||
}
|
||||
|
||||
void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID) {
|
||||
std::string query = StringFormat("SELECT `name`, `lsaccount_id` FROM `account` WHERE `id` = '%i'", accountid);
|
||||
std::string query = StringFormat("SELECT `name`, `lsaccount_id` FROM `account` WHERE `id` = '%i'", accountid);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
@ -841,7 +872,7 @@ void Database::GetCharName(uint32 char_id, char* name) {
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
@ -918,21 +949,9 @@ bool Database::SetVariable(const std::string varname, const std::string &varvalu
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Database::GetMiniLoginAccount(char* ip)
|
||||
{
|
||||
std::string query = StringFormat("SELECT `id` FROM `account` WHERE `minilogin_ip` = '%s'", ip);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
// Get zone starting points from DB
|
||||
bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe_x, float* safe_y, float* safe_z, int16* minstatus, uint8* minlevel, char *flag_needed) {
|
||||
|
||||
|
||||
std::string query = StringFormat("SELECT safe_x, safe_y, safe_z, min_status, min_level, flag_needed FROM zone "
|
||||
" WHERE short_name='%s' AND (version=%i OR version=0) ORDER BY version DESC", short_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
@ -962,7 +981,7 @@ bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe
|
||||
}
|
||||
|
||||
bool Database::GetZoneLongName(const char* short_name, char** long_name, char* file_name, float* safe_x, float* safe_y, float* safe_z, uint32* graveyard_id, uint32* maxclients) {
|
||||
|
||||
|
||||
std::string query = StringFormat("SELECT long_name, file_name, safe_x, safe_y, safe_z, graveyard_id, maxclients FROM zone WHERE short_name='%s' AND version=0", short_name);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1015,7 +1034,7 @@ uint32 Database::GetZoneGraveyardID(uint32 zone_id, uint32 version) {
|
||||
}
|
||||
|
||||
bool Database::GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid, float* graveyard_x, float* graveyard_y, float* graveyard_z, float* graveyard_heading) {
|
||||
|
||||
|
||||
std::string query = StringFormat("SELECT zone_id, x, y, z, heading FROM graveyard WHERE id=%i", graveyard_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1087,7 +1106,7 @@ const char* Database::GetZoneName(uint32 zoneID, bool ErrorUnknown) {
|
||||
}
|
||||
|
||||
uint8 Database::GetPEQZone(uint32 zoneID, uint32 version){
|
||||
|
||||
|
||||
std::string query = StringFormat("SELECT peqzone from zone where zoneidnumber='%i' AND (version=%i OR version=0) ORDER BY version DESC", zoneID, version);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1151,7 +1170,7 @@ bool Database::CheckNameFilter(const char* name, bool surname)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string query("SELECT name FROM name_filter");
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1176,7 +1195,7 @@ bool Database::CheckNameFilter(const char* name, bool surname)
|
||||
}
|
||||
|
||||
bool Database::AddToNameFilter(const char* name) {
|
||||
|
||||
|
||||
std::string query = StringFormat("INSERT INTO name_filter (name) values ('%s')", name);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1191,32 +1210,53 @@ bool Database::AddToNameFilter(const char* name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Database::GetAccountIDFromLSID(uint32 iLSID, char* oAccountName, int16* oStatus) {
|
||||
/**
|
||||
* @param in_loginserver_id
|
||||
* @param in_loginserver_account_id
|
||||
* @param in_account_name
|
||||
* @param in_status
|
||||
* @return
|
||||
*/
|
||||
uint32 Database::GetAccountIDFromLSID(
|
||||
const std::string &in_loginserver_id,
|
||||
uint32 in_loginserver_account_id,
|
||||
char *in_account_name,
|
||||
int16 *in_status
|
||||
)
|
||||
{
|
||||
uint32 account_id = 0;
|
||||
std::string query = StringFormat("SELECT id, name, status FROM account WHERE lsaccount_id=%i", iLSID);
|
||||
auto query = fmt::format(
|
||||
"SELECT id, name, status FROM account WHERE lsaccount_id = {0} AND ls_id = '{1}'",
|
||||
in_loginserver_account_id,
|
||||
in_loginserver_id
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
if (results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
account_id = atoi(row[0]);
|
||||
account_id = std::stoi(row[0]);
|
||||
|
||||
if (oAccountName)
|
||||
strcpy(oAccountName, row[1]);
|
||||
if (oStatus)
|
||||
*oStatus = atoi(row[2]);
|
||||
if (in_account_name) {
|
||||
strcpy(in_account_name, row[1]);
|
||||
}
|
||||
if (in_status) {
|
||||
*in_status = std::stoi(row[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return account_id;
|
||||
}
|
||||
|
||||
void Database::GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus) {
|
||||
|
||||
|
||||
std::string query = StringFormat("SELECT name, status FROM account WHERE id=%i", id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1239,8 +1279,8 @@ void Database::ClearMerchantTemp(){
|
||||
QueryDatabase("DELETE FROM merchantlist_temp");
|
||||
}
|
||||
|
||||
bool Database::UpdateName(const char* oldname, const char* newname) {
|
||||
std::cout << "Renaming " << oldname << " to " << newname << "..." << std::endl;
|
||||
bool Database::UpdateName(const char* oldname, const char* newname) {
|
||||
std::cout << "Renaming " << oldname << " to " << newname << "..." << std::endl;
|
||||
std::string query = StringFormat("UPDATE `character_data` SET `name` = '%s' WHERE `name` = '%s';", newname, oldname);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1256,7 +1296,7 @@ bool Database::UpdateName(const char* oldname, const char* newname) {
|
||||
// If the name is used or an error occurs, it returns false, otherwise it returns true
|
||||
bool Database::CheckUsedName(const char* name) {
|
||||
std::string query = StringFormat("SELECT `id` FROM `character_data` WHERE `name` = '%s'", name);
|
||||
auto results = QueryDatabase(query);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
@ -1269,7 +1309,7 @@ bool Database::CheckUsedName(const char* name) {
|
||||
|
||||
uint8 Database::GetServerType() {
|
||||
std::string query("SELECT `value` FROM `variables` WHERE `varname` = 'ServerType' LIMIT 1");
|
||||
auto results = QueryDatabase(query);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return 0;
|
||||
}
|
||||
@ -1302,7 +1342,7 @@ bool Database::MoveCharacterToZone(const char* charname, const char* zonename) {
|
||||
return MoveCharacterToZone(charname, zonename, GetZoneID(zonename));
|
||||
}
|
||||
|
||||
bool Database::MoveCharacterToZone(uint32 iCharID, const char* iZonename) {
|
||||
bool Database::MoveCharacterToZone(uint32 iCharID, const char* iZonename) {
|
||||
std::string query = StringFormat("UPDATE `character_data` SET `zone_id` = %i, `x` = -1, `y` = -1, `z` = -1 WHERE `id` = %i", GetZoneID(iZonename), iCharID);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1313,7 +1353,7 @@ bool Database::MoveCharacterToZone(uint32 iCharID, const char* iZonename) {
|
||||
return results.RowsAffected() != 0;
|
||||
}
|
||||
|
||||
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
|
||||
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
|
||||
std::string query = StringFormat("INSERT INTO `hackers` (account, name, hacked) values('%s','%s','%s')", accountname, charactername, hacked);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1324,7 +1364,7 @@ bool Database::SetHackerFlag(const char* accountname, const char* charactername,
|
||||
return results.RowsAffected() != 0;
|
||||
}
|
||||
|
||||
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) {
|
||||
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) {
|
||||
//Utilize the "hacker" table, but also give zone information.
|
||||
std::string query = StringFormat("INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone);
|
||||
auto results = QueryDatabase(query);
|
||||
@ -1340,7 +1380,7 @@ bool Database::SetMQDetectionFlag(const char* accountname, const char* character
|
||||
uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
|
||||
{
|
||||
uint16 race_cap = 0;
|
||||
|
||||
|
||||
//Check for a racial cap!
|
||||
std::string query = StringFormat("SELECT skillcap from race_skillcaps where skill = %i && race = %i", skillid, in_race);
|
||||
auto results = QueryDatabase(query);
|
||||
@ -1359,7 +1399,7 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
|
||||
{
|
||||
uint8 skill_level = 0, skill_formula = 0;
|
||||
uint16 base_cap = 0, skill_cap = 0, skill_cap2 = 0, skill_cap3 = 0;
|
||||
|
||||
|
||||
|
||||
//Fetch the data from DB.
|
||||
std::string query = StringFormat("SELECT level, formula, pre50cap, post50cap, post60cap from skillcaps where skill = %i && class = %i", skillid, in_class);
|
||||
@ -1442,9 +1482,9 @@ uint32 Database::GetCharacterInfo(
|
||||
return charid;
|
||||
}
|
||||
|
||||
bool Database::UpdateLiveChar(char* charname,uint32 lsaccount_id) {
|
||||
bool Database::UpdateLiveChar(char* charname, uint32 account_id) {
|
||||
|
||||
std::string query = StringFormat("UPDATE account SET charname='%s' WHERE id=%i;",charname, lsaccount_id);
|
||||
std::string query = StringFormat("UPDATE account SET charname='%s' WHERE id=%i;", charname, account_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()){
|
||||
@ -1473,24 +1513,24 @@ bool Database::GetLiveChar(uint32 account_id, char* cname) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database::SetLFP(uint32 CharID, bool LFP) {
|
||||
void Database::SetLFP(uint32 CharID, bool LFP) {
|
||||
std::string query = StringFormat("UPDATE `character_data` SET `lfp` = %i WHERE `id` = %i",LFP, CharID);
|
||||
QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void Database::SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon) {
|
||||
void Database::SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon) {
|
||||
std::string query = StringFormat("update `character_data` SET `lfp` = %i, `lfg` = %i, `firstlogon` = %i WHERE `id` = %i",LFP, LFG, firstlogon, CharID);
|
||||
QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void Database::SetLFG(uint32 CharID, bool LFG) {
|
||||
void Database::SetLFG(uint32 CharID, bool LFG) {
|
||||
std::string query = StringFormat("update `character_data` SET `lfg` = %i WHERE `id` = %i",LFG, CharID);
|
||||
QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void Database::SetFirstLogon(uint32 CharID, uint8 firstlogon) {
|
||||
void Database::SetFirstLogon(uint32 CharID, uint8 firstlogon) {
|
||||
std::string query = StringFormat( "UPDATE `character_data` SET `firstlogon` = %i WHERE `id` = %i",firstlogon, CharID);
|
||||
QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void Database::AddReport(std::string who, std::string against, std::string lines)
|
||||
@ -1511,7 +1551,7 @@ void Database::SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ism
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
Log(Logs::General, Logs::Error, "Error deleting character from group id: %s", results.ErrorMessage().c_str());
|
||||
LogError("Error deleting character from group id: {}", results.ErrorMessage().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1530,7 +1570,7 @@ void Database::ClearAllGroups(void)
|
||||
|
||||
void Database::ClearGroup(uint32 gid) {
|
||||
ClearGroupLeader(gid);
|
||||
|
||||
|
||||
if(gid == 0)
|
||||
{
|
||||
//clear all groups
|
||||
@ -1543,7 +1583,7 @@ void Database::ClearGroup(uint32 gid) {
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
uint32 Database::GetGroupID(const char* name){
|
||||
uint32 Database::GetGroupID(const char* name){
|
||||
std::string query = StringFormat("SELECT groupid from group_id where name='%s'", name);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1554,7 +1594,7 @@ uint32 Database::GetGroupID(const char* name){
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
// Commenting this out until logging levels can prevent this from going to console
|
||||
//Log(Logs::General, Logs::None,, "Character not in a group: %s", name);
|
||||
//LogDebug(, "Character not in a group: [{}]", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1588,7 +1628,7 @@ char* Database::GetGroupLeaderForLogin(const char* name, char* leaderbuf) {
|
||||
return leaderbuf;
|
||||
}
|
||||
|
||||
void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
std::string query = StringFormat("UPDATE group_leaders SET leadername = '%s' WHERE gid = %u", EscapeString(name).c_str(), gid);
|
||||
auto result = QueryDatabase(query);
|
||||
|
||||
@ -1601,7 +1641,7 @@ void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
result = QueryDatabase(query);
|
||||
|
||||
if(!result.Success()) {
|
||||
Log(Logs::General, Logs::None, "Error in Database::SetGroupLeaderName: %s", result.ErrorMessage().c_str());
|
||||
LogDebug("Error in Database::SetGroupLeaderName: [{}]", result.ErrorMessage().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1676,7 +1716,7 @@ void Database::ClearAllGroupLeaders(void) {
|
||||
}
|
||||
|
||||
void Database::ClearGroupLeader(uint32 gid) {
|
||||
|
||||
|
||||
if(gid == 0)
|
||||
{
|
||||
ClearAllGroupLeaders();
|
||||
@ -1747,7 +1787,7 @@ void Database::ClearAllRaidDetails(void)
|
||||
}
|
||||
|
||||
void Database::ClearRaidDetails(uint32 rid) {
|
||||
|
||||
|
||||
if(rid == 0)
|
||||
{
|
||||
//clear all raids
|
||||
@ -1775,7 +1815,7 @@ void Database::PurgeAllDeletedDataBuckets() {
|
||||
// returns 0 on error or no raid for that character, or
|
||||
// the raid id that the character is a member of.
|
||||
uint32 Database::GetRaidID(const char* name)
|
||||
{
|
||||
{
|
||||
std::string query = StringFormat("SELECT `raidid` FROM `raid_members` WHERE `name` = '%s'", name);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@ -1783,7 +1823,7 @@ uint32 Database::GetRaidID(const char* name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
auto row = results.begin();
|
||||
if (row == results.end()) {
|
||||
return 0;
|
||||
}
|
||||
@ -1802,12 +1842,12 @@ const char* Database::GetRaidLeaderName(uint32 raid_id)
|
||||
// variable). C++0x standard states this should be thread safe
|
||||
// but may not be fully supported in some compilers.
|
||||
static char name[128];
|
||||
|
||||
|
||||
std::string query = StringFormat("SELECT `name` FROM `raid_members` WHERE `raidid` = %u AND `israidleader` = 1", raid_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Debug, "Unable to get Raid Leader Name for Raid ID: %u", raid_id);
|
||||
LogDebug("Unable to get Raid Leader Name for Raid ID: [{}]", raid_id);
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
@ -2030,7 +2070,7 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
|
||||
"FROM "
|
||||
"`adventure_stats` "
|
||||
"WHERE "
|
||||
"player_id = %u ",
|
||||
"player_id = %u ",
|
||||
char_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
@ -2059,7 +2099,7 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
||||
uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
||||
{
|
||||
std::string query = StringFormat("SELECT guild_id FROM guild_members WHERE char_id='%i'", character_id);
|
||||
auto results = QueryDatabase(query);
|
||||
@ -2074,9 +2114,11 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
|
||||
// log_settings previously initialized to '0' by EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
|
||||
/**
|
||||
* @param log_settings
|
||||
*/
|
||||
void Database::LoadLogSettings(EQEmuLogSys::LogSettings *log_settings)
|
||||
{
|
||||
std::string query =
|
||||
"SELECT "
|
||||
"log_category_id, "
|
||||
@ -2088,11 +2130,10 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
|
||||
"logsys_categories "
|
||||
"ORDER BY log_category_id";
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
auto results = QueryDatabase(query);
|
||||
int log_category_id = 0;
|
||||
|
||||
int log_category_id = 0;
|
||||
|
||||
int categories_in_database[1000] = {};
|
||||
int *categories_in_database = new int[1000];
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
log_category_id = atoi(row[0]);
|
||||
@ -2132,15 +2173,14 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
|
||||
* Auto inject categories that don't exist in the database...
|
||||
*/
|
||||
for (int log_index = Logs::AA; log_index != Logs::MaxCategoryID; log_index++) {
|
||||
if (!categories_in_database[log_index]) {
|
||||
if (categories_in_database[log_index] != 1) {
|
||||
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"New Log Category '%s' doesn't exist... Automatically adding to `logsys_categories` table...",
|
||||
LogInfo(
|
||||
"New Log Category [{0}] doesn't exist... Automatically adding to [logsys_categories] table...",
|
||||
Logs::LogCategoryName[log_index]
|
||||
);
|
||||
|
||||
std::string inject_query = StringFormat(
|
||||
auto inject_query = fmt::format(
|
||||
"INSERT INTO logsys_categories "
|
||||
"(log_category_id, "
|
||||
"log_category_description, "
|
||||
@ -2148,17 +2188,19 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) {
|
||||
"log_to_file, "
|
||||
"log_to_gmsay) "
|
||||
"VALUES "
|
||||
"(%i, '%s', %i, %i, %i)",
|
||||
"({0}, '{1}', {2}, {3}, {4})",
|
||||
log_index,
|
||||
EscapeString(Logs::LogCategoryName[log_index]).c_str(),
|
||||
log_settings[log_category_id].log_to_console,
|
||||
log_settings[log_category_id].log_to_file,
|
||||
log_settings[log_category_id].log_to_gmsay
|
||||
EscapeString(Logs::LogCategoryName[log_index]),
|
||||
std::to_string(log_settings[log_index].log_to_console),
|
||||
std::to_string(log_settings[log_index].log_to_file),
|
||||
std::to_string(log_settings[log_index].log_to_gmsay)
|
||||
);
|
||||
|
||||
QueryDatabase(inject_query);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] categories_in_database;
|
||||
}
|
||||
|
||||
int Database::CountInvSnapshots() {
|
||||
@ -2195,7 +2237,7 @@ struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || results.RowCount() == 0){
|
||||
Log(Logs::Detail, Logs::World_Server, "Loading EQ time of day failed. Using defaults.");
|
||||
LogInfo("Loading EQ time of day failed. Using defaults");
|
||||
eqTime.minute = 0;
|
||||
eqTime.hour = 9;
|
||||
eqTime.day = 1;
|
||||
@ -2229,12 +2271,12 @@ bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year
|
||||
int Database::GetIPExemption(std::string account_ip) {
|
||||
std::string query = StringFormat("SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '%s'", account_ip.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
|
||||
return RuleI(World, MaxClientsPerIP);
|
||||
}
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ public:
|
||||
|
||||
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
|
||||
uint32 GetAccountIDByChar(uint32 char_id);
|
||||
uint32 GetAccountIDByName(const char* accname, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetAccountIDByName(const char* accname, const char *loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetCharacterID(const char *name);
|
||||
uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
|
||||
uint32 GetGuildIDByCharID(uint32 char_id);
|
||||
@ -176,18 +176,17 @@ public:
|
||||
|
||||
/* Account Related */
|
||||
|
||||
bool DeleteAccount(const char* name);
|
||||
bool DeleteAccount(const char *name, const char* loginserver);
|
||||
bool GetLiveChar(uint32 account_id, char* cname);
|
||||
bool SetAccountStatus(const char* name, int16 status);
|
||||
bool SetLocalPassword(uint32 accid, const char* password);
|
||||
bool UpdateLiveChar(char* charname, uint32 lsaccount_id);
|
||||
bool UpdateLiveChar(char* charname, uint32 account_id);
|
||||
|
||||
int16 CheckStatus(uint32 account_id);
|
||||
|
||||
uint32 CheckLogin(const char* name, const char* password, int16* oStatus = 0);
|
||||
uint32 CreateAccount(const char* name, const char* password, int16 status, uint32 lsaccount_id = 0);
|
||||
uint32 GetAccountIDFromLSID(uint32 iLSID, char* oAccountName = 0, int16* oStatus = 0);
|
||||
uint32 GetMiniLoginAccount(char* ip);
|
||||
uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0);
|
||||
uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id);
|
||||
uint32 GetAccountIDFromLSID(const std::string& in_loginserver_id, uint32 in_loginserver_account_id, char* in_account_name = 0, int16* in_status = 0);
|
||||
uint8 GetAgreementFlag(uint32 acctid);
|
||||
|
||||
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
|
||||
|
||||
@ -2,8 +2,9 @@
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "misc_functions.h"
|
||||
#include "eqemu_logsys.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include "dbcore.h"
|
||||
|
||||
@ -14,33 +15,37 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#include <process.h>
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#include <process.h>
|
||||
#else
|
||||
#include "unix.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#include "unix.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
#define DEBUG_MYSQL_QUERIES 0
|
||||
#define DEBUG_MYSQL_QUERIES 0
|
||||
#else
|
||||
#define DEBUG_MYSQL_QUERIES 0
|
||||
#define DEBUG_MYSQL_QUERIES 0
|
||||
#endif
|
||||
|
||||
DBcore::DBcore() {
|
||||
DBcore::DBcore()
|
||||
{
|
||||
mysql_init(&mysql);
|
||||
pHost = 0;
|
||||
pUser = 0;
|
||||
pHost = 0;
|
||||
pUser = 0;
|
||||
pPassword = 0;
|
||||
pDatabase = 0;
|
||||
pCompress = false;
|
||||
pSSL = false;
|
||||
pStatus = Closed;
|
||||
pSSL = false;
|
||||
pStatus = Closed;
|
||||
}
|
||||
|
||||
DBcore::~DBcore() {
|
||||
DBcore::~DBcore()
|
||||
{
|
||||
mysql_close(&mysql);
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
@ -49,7 +54,8 @@ DBcore::~DBcore() {
|
||||
}
|
||||
|
||||
// Sends the MySQL server a keepalive
|
||||
void DBcore::ping() {
|
||||
void DBcore::ping()
|
||||
{
|
||||
if (!MDatabase.trylock()) {
|
||||
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
|
||||
return;
|
||||
@ -63,34 +69,35 @@ MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureO
|
||||
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
|
||||
}
|
||||
|
||||
MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, bool retryOnFailureOnce)
|
||||
MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce)
|
||||
{
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
LockMutex lock(&MDatabase);
|
||||
|
||||
// Reconnect if we are not connected before hand.
|
||||
if (pStatus != Connected)
|
||||
if (pStatus != Connected) {
|
||||
Open();
|
||||
}
|
||||
|
||||
// request query. != 0 indicates some kind of error.
|
||||
if (mysql_real_query(&mysql, query, querylen) != 0)
|
||||
{
|
||||
if (mysql_real_query(&mysql, query, querylen) != 0) {
|
||||
unsigned int errorNumber = mysql_errno(&mysql);
|
||||
|
||||
if (errorNumber == CR_SERVER_GONE_ERROR)
|
||||
if (errorNumber == CR_SERVER_GONE_ERROR) {
|
||||
pStatus = Error;
|
||||
}
|
||||
|
||||
// error appears to be a disconnect error, may need to try again.
|
||||
if (errorNumber == CR_SERVER_LOST || errorNumber == CR_SERVER_GONE_ERROR)
|
||||
{
|
||||
if (errorNumber == CR_SERVER_LOST || errorNumber == CR_SERVER_GONE_ERROR) {
|
||||
|
||||
if (retryOnFailureOnce)
|
||||
{
|
||||
std::cout << "Database Error: Lost connection, attempting to recover...." << std::endl;
|
||||
if (retryOnFailureOnce) {
|
||||
LogInfo("Database Error: Lost connection, attempting to recover");
|
||||
MySQLRequestResult requestResult = QueryDatabase(query, querylen, false);
|
||||
|
||||
if (requestResult.Success())
|
||||
{
|
||||
std::cout << "Reconnection to database successful." << std::endl;
|
||||
if (requestResult.Success()) {
|
||||
LogInfo("Reconnection to database successful");
|
||||
return requestResult;
|
||||
}
|
||||
|
||||
@ -102,109 +109,154 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo
|
||||
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32)mysql_errno(&mysql), errorBuffer);
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer);
|
||||
}
|
||||
|
||||
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
|
||||
/* Implement Logging at the Root */
|
||||
if (mysql_errno(&mysql) > 0 && strlen(query) > 0){
|
||||
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
|
||||
if (LogSys.log_settings[Logs::MySQLError].is_category_enabled == 1)
|
||||
Log(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query);
|
||||
}
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql),errorBuffer);
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
|
||||
|
||||
}
|
||||
|
||||
// successful query. get results.
|
||||
MYSQL_RES* res = mysql_store_result(&mysql);
|
||||
uint32 rowCount = 0;
|
||||
MYSQL_RES *res = mysql_store_result(&mysql);
|
||||
uint32 rowCount = 0;
|
||||
|
||||
if (res != nullptr)
|
||||
rowCount = (uint32)mysql_num_rows(res);
|
||||
if (res != nullptr) {
|
||||
rowCount = (uint32) mysql_num_rows(res);
|
||||
}
|
||||
|
||||
MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), rowCount, (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql));
|
||||
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1)
|
||||
{
|
||||
MySQLRequestResult requestResult(
|
||||
res,
|
||||
(uint32) mysql_affected_rows(&mysql),
|
||||
rowCount,
|
||||
(uint32) mysql_field_count(&mysql),
|
||||
(uint32) mysql_insert_id(&mysql)
|
||||
);
|
||||
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
|
||||
if ((strncasecmp(query, "select", 6) == 0)) {
|
||||
Log(Logs::General, Logs::MySQLQuery, "%s (%u row%s returned)", query, requestResult.RowCount(), requestResult.RowCount() == 1 ? "" : "s");
|
||||
LogF(
|
||||
Logs::General,
|
||||
Logs::MySQLQuery,
|
||||
"{0} ({1} row{2} returned) ({3}ms)",
|
||||
query,
|
||||
requestResult.RowCount(),
|
||||
requestResult.RowCount() == 1 ? "" : "s",
|
||||
std::to_string(timer.elapsed())
|
||||
);
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::MySQLQuery, "%s (%u row%s affected)", query, requestResult.RowsAffected(), requestResult.RowsAffected() == 1 ? "" : "s");
|
||||
LogF(
|
||||
Logs::General,
|
||||
Logs::MySQLQuery,
|
||||
"{0} ({1} row{2} affected) ({3}ms)",
|
||||
query,
|
||||
requestResult.RowsAffected(),
|
||||
requestResult.RowsAffected() == 1 ? "" : "s",
|
||||
std::to_string(timer.elapsed())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return requestResult;
|
||||
}
|
||||
|
||||
void DBcore::TransactionBegin() {
|
||||
void DBcore::TransactionBegin()
|
||||
{
|
||||
QueryDatabase("START TRANSACTION");
|
||||
}
|
||||
|
||||
void DBcore::TransactionCommit() {
|
||||
void DBcore::TransactionCommit()
|
||||
{
|
||||
QueryDatabase("COMMIT");
|
||||
}
|
||||
|
||||
void DBcore::TransactionRollback() {
|
||||
void DBcore::TransactionRollback()
|
||||
{
|
||||
QueryDatabase("ROLLBACK");
|
||||
}
|
||||
|
||||
uint32 DBcore::DoEscapeString(char* tobuf, const char* frombuf, uint32 fromlen) {
|
||||
uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen)
|
||||
{
|
||||
// No good reason to lock the DB, we only need it in the first place to check char encoding.
|
||||
// LockMutex lock(&MDatabase);
|
||||
return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
|
||||
}
|
||||
|
||||
bool DBcore::Open(const char* iHost, const char* iUser, const char* iPassword, const char* iDatabase,uint32 iPort, uint32* errnum, char* errbuf, bool iCompress, bool iSSL) {
|
||||
bool DBcore::Open(
|
||||
const char *iHost,
|
||||
const char *iUser,
|
||||
const char *iPassword,
|
||||
const char *iDatabase,
|
||||
uint32 iPort,
|
||||
uint32 *errnum,
|
||||
char *errbuf,
|
||||
bool iCompress,
|
||||
bool iSSL
|
||||
)
|
||||
{
|
||||
LockMutex lock(&MDatabase);
|
||||
safe_delete(pHost);
|
||||
safe_delete(pUser);
|
||||
safe_delete(pPassword);
|
||||
safe_delete(pDatabase);
|
||||
pHost = strcpy(new char[strlen(iHost) + 1], iHost);
|
||||
pUser = strcpy(new char[strlen(iUser) + 1], iUser);
|
||||
pHost = strcpy(new char[strlen(iHost) + 1], iHost);
|
||||
pUser = strcpy(new char[strlen(iUser) + 1], iUser);
|
||||
pPassword = strcpy(new char[strlen(iPassword) + 1], iPassword);
|
||||
pDatabase = strcpy(new char[strlen(iDatabase) + 1], iDatabase);
|
||||
pCompress = iCompress;
|
||||
pPort = iPort;
|
||||
pSSL = iSSL;
|
||||
pPort = iPort;
|
||||
pSSL = iSSL;
|
||||
return Open(errnum, errbuf);
|
||||
}
|
||||
|
||||
bool DBcore::Open(uint32* errnum, char* errbuf) {
|
||||
if (errbuf)
|
||||
bool DBcore::Open(uint32 *errnum, char *errbuf)
|
||||
{
|
||||
if (errbuf) {
|
||||
errbuf[0] = 0;
|
||||
}
|
||||
LockMutex lock(&MDatabase);
|
||||
if (GetStatus() == Connected)
|
||||
if (GetStatus() == Connected) {
|
||||
return true;
|
||||
}
|
||||
if (GetStatus() == Error) {
|
||||
mysql_close(&mysql);
|
||||
mysql_init(&mysql); // Initialize structure again
|
||||
mysql_init(&mysql); // Initialize structure again
|
||||
}
|
||||
if (!pHost)
|
||||
if (!pHost) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
Added CLIENT_FOUND_ROWS flag to the connect
|
||||
otherwise DB update calls would say 0 rows affected when the value already equalled
|
||||
what the function was tring to set it to, therefore the function would think it failed
|
||||
*/
|
||||
uint32 flags = CLIENT_FOUND_ROWS;
|
||||
if (pCompress)
|
||||
if (pCompress) {
|
||||
flags |= CLIENT_COMPRESS;
|
||||
if (pSSL)
|
||||
}
|
||||
if (pSSL) {
|
||||
flags |= CLIENT_SSL;
|
||||
}
|
||||
if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
|
||||
pStatus = Connected;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (errnum)
|
||||
if (errnum) {
|
||||
*errnum = mysql_errno(&mysql);
|
||||
if (errbuf)
|
||||
}
|
||||
if (errbuf) {
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
}
|
||||
pStatus = Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -459,4 +459,9 @@ enum ChatChannelNames : uint16
|
||||
ChatChannel_Emotes = 22
|
||||
};
|
||||
|
||||
namespace ZoneBlockedSpellTypes {
|
||||
const uint8 ZoneWide = 1;
|
||||
const uint8 Region = 2;
|
||||
};
|
||||
|
||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||
|
||||
@ -84,14 +84,14 @@ void EQStream::init(bool resetSession) {
|
||||
|
||||
OpMgr = nullptr;
|
||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "init Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
LogNetcode(_L "init Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
}
|
||||
}
|
||||
|
||||
EQRawApplicationPacket *EQStream::MakeApplicationPacket(EQProtocolPacket *p)
|
||||
{
|
||||
EQRawApplicationPacket *ap=nullptr;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Creating new application packet, length %d" __L, p->size);
|
||||
LogNetcode(_L "Creating new application packet, length [{}]" __L, p->size);
|
||||
// _raw(NET__APP_CREATE_HEX, 0xFFFF, p);
|
||||
ap = p->MakeAppPacket();
|
||||
return ap;
|
||||
@ -100,7 +100,7 @@ EQRawApplicationPacket *EQStream::MakeApplicationPacket(EQProtocolPacket *p)
|
||||
EQRawApplicationPacket *EQStream::MakeApplicationPacket(const unsigned char *buf, uint32 len)
|
||||
{
|
||||
EQRawApplicationPacket *ap=nullptr;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Creating new application packet, length %d" __L, len);
|
||||
LogNetcode(_L "Creating new application packet, length [{}]" __L, len);
|
||||
ap = new EQRawApplicationPacket(buf, len);
|
||||
return ap;
|
||||
}
|
||||
@ -130,7 +130,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
}
|
||||
|
||||
if (!Session && p->opcode!=OP_SessionRequest && p->opcode!=OP_SessionResponse) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Session not initialized, packet ignored" __L);
|
||||
LogNetcode(_L "Session not initialized, packet ignored" __L);
|
||||
// _raw(NET__DEBUG, 0xFFFF, p);
|
||||
return;
|
||||
}
|
||||
@ -141,7 +141,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
while(processed < p->size) {
|
||||
subpacket_length=*(p->pBuffer+processed);
|
||||
EQProtocolPacket *subp=MakeProtocolPacket(p->pBuffer+processed+1,subpacket_length);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Extracting combined packet of length %d" __L, subpacket_length);
|
||||
LogNetcode(_L "Extracting combined packet of length [{}]" __L, subpacket_length);
|
||||
// _raw(NET__NET_CREATE_HEX, 0xFFFF, subp);
|
||||
subp->copyInfo(p);
|
||||
ProcessPacket(subp);
|
||||
@ -156,12 +156,12 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
while(processed<p->size) {
|
||||
EQRawApplicationPacket *ap=nullptr;
|
||||
if ((subpacket_length=(unsigned char)*(p->pBuffer+processed))!=0xff) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Extracting combined app packet of length %d, short len" __L, subpacket_length);
|
||||
LogNetcode(_L "Extracting combined app packet of length [{}], short len" __L, subpacket_length);
|
||||
ap=MakeApplicationPacket(p->pBuffer+processed+1,subpacket_length);
|
||||
processed+=subpacket_length+1;
|
||||
} else {
|
||||
subpacket_length=ntohs(*(uint16 *)(p->pBuffer+processed+1));
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Extracting combined app packet of length %d, short len" __L, subpacket_length);
|
||||
LogNetcode(_L "Extracting combined app packet of length [{}], short len" __L, subpacket_length);
|
||||
ap=MakeApplicationPacket(p->pBuffer+processed+3,subpacket_length);
|
||||
processed+=subpacket_length+3;
|
||||
}
|
||||
@ -176,29 +176,29 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
case OP_Packet: {
|
||||
if(!p->pBuffer || (p->Size() < 4))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_Packet that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_Packet that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
||||
SeqOrder check=CompareSequence(NextInSeq,seq);
|
||||
if (check == SeqFuture) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Future OP_Packet: Expecting Seq=%d, but got Seq=%d" __L, NextInSeq, seq);
|
||||
LogNetcode(_L "Future OP_Packet: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
|
||||
// _raw(NET__DEBUG, seq, p);
|
||||
|
||||
PacketQueue[seq]=p->Copy();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OP_Packet Queue size=%d" __L, PacketQueue.size());
|
||||
LogNetcode(_L "OP_Packet Queue size=[{}]" __L, PacketQueue.size());
|
||||
|
||||
//SendOutOfOrderAck(seq);
|
||||
|
||||
} else if (check == SeqPast) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Duplicate OP_Packet: Expecting Seq=%d, but got Seq=%d" __L, NextInSeq, seq);
|
||||
LogNetcode(_L "Duplicate OP_Packet: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
|
||||
// _raw(NET__DEBUG, seq, p);
|
||||
SendOutOfOrderAck(seq); //we already got this packet but it was out of order
|
||||
} else {
|
||||
// In case we did queue one before as well.
|
||||
EQProtocolPacket *qp=RemoveQueue(seq);
|
||||
if (qp) {
|
||||
Log(Logs::General, Logs::Netcode, "[NET_TRACE] OP_Packet: Removing older queued packet with sequence %d", seq);
|
||||
LogNetcode("[NET_TRACE] OP_Packet: Removing older queued packet with sequence [{}]", seq);
|
||||
delete qp;
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
// Check for an embedded OP_AppCombinded (protocol level 0x19)
|
||||
if (*(p->pBuffer+2)==0x00 && *(p->pBuffer+3)==0x19) {
|
||||
EQProtocolPacket *subp=MakeProtocolPacket(p->pBuffer+2,p->size-2);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "seq %d, Extracting combined packet of length %d" __L, seq, subp->size);
|
||||
LogNetcode(_L "seq [{}], Extracting combined packet of length [{}]" __L, seq, subp->size);
|
||||
// _raw(NET__NET_CREATE_HEX, seq, subp);
|
||||
subp->copyInfo(p);
|
||||
ProcessPacket(subp);
|
||||
@ -226,29 +226,29 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
case OP_Fragment: {
|
||||
if(!p->pBuffer || (p->Size() < 4))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_Fragment that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_Fragment that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
||||
SeqOrder check=CompareSequence(NextInSeq,seq);
|
||||
if (check == SeqFuture) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Future OP_Fragment: Expecting Seq=%d, but got Seq=%d" __L, NextInSeq, seq);
|
||||
LogNetcode(_L "Future OP_Fragment: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
|
||||
// _raw(NET__DEBUG, seq, p);
|
||||
|
||||
PacketQueue[seq]=p->Copy();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OP_Fragment Queue size=%d" __L, PacketQueue.size());
|
||||
LogNetcode(_L "OP_Fragment Queue size=[{}]" __L, PacketQueue.size());
|
||||
|
||||
//SendOutOfOrderAck(seq);
|
||||
|
||||
} else if (check == SeqPast) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Duplicate OP_Fragment: Expecting Seq=%d, but got Seq=%d" __L, NextInSeq, seq);
|
||||
LogNetcode(_L "Duplicate OP_Fragment: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
|
||||
// _raw(NET__DEBUG, seq, p);
|
||||
SendOutOfOrderAck(seq);
|
||||
} else {
|
||||
// In case we did queue one before as well.
|
||||
EQProtocolPacket *qp=RemoveQueue(seq);
|
||||
if (qp) {
|
||||
Log(Logs::General, Logs::Netcode, "[NET_TRACE] OP_Fragment: Removing older queued packet with sequence %d", seq);
|
||||
LogNetcode("[NET_TRACE] OP_Fragment: Removing older queued packet with sequence [{}]", seq);
|
||||
delete qp;
|
||||
}
|
||||
SetNextAckToSend(seq);
|
||||
@ -256,18 +256,18 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
if (oversize_buffer) {
|
||||
memcpy(oversize_buffer+oversize_offset,p->pBuffer+2,p->size-2);
|
||||
oversize_offset+=p->size-2;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Fragment of oversized of length %d, seq %d: now at %d/%d" __L, p->size-2, seq, oversize_offset, oversize_length);
|
||||
LogNetcode(_L "Fragment of oversized of length [{}], seq [{}]: now at [{}]/[{}]" __L, p->size-2, seq, oversize_offset, oversize_length);
|
||||
if (oversize_offset==oversize_length) {
|
||||
if (*(p->pBuffer+2)==0x00 && *(p->pBuffer+3)==0x19) {
|
||||
EQProtocolPacket *subp=MakeProtocolPacket(oversize_buffer,oversize_offset);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "seq %d, Extracting combined oversize packet of length %d" __L, seq, subp->size);
|
||||
LogNetcode(_L "seq [{}], Extracting combined oversize packet of length [{}]" __L, seq, subp->size);
|
||||
//// _raw(NET__NET_CREATE_HEX, subp);
|
||||
subp->copyInfo(p);
|
||||
ProcessPacket(subp);
|
||||
delete subp;
|
||||
} else {
|
||||
EQRawApplicationPacket *ap=MakeApplicationPacket(oversize_buffer,oversize_offset);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "seq %d, completed combined oversize packet of length %d" __L, seq, ap->size);
|
||||
LogNetcode(_L "seq [{}], completed combined oversize packet of length [{}]" __L, seq, ap->size);
|
||||
if (ap) {
|
||||
ap->copyInfo(p);
|
||||
InboundQueuePush(ap);
|
||||
@ -282,20 +282,20 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
oversize_buffer=new unsigned char[oversize_length];
|
||||
memcpy(oversize_buffer,p->pBuffer+6,p->size-6);
|
||||
oversize_offset=p->size-6;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "First fragment of oversized of seq %d: now at %d/%d" __L, seq, oversize_offset, oversize_length);
|
||||
LogNetcode(_L "First fragment of oversized of seq [{}]: now at [{}]/[{}]" __L, seq, oversize_offset, oversize_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_KeepAlive: {
|
||||
NonSequencedPush(new EQProtocolPacket(p->opcode,p->pBuffer,p->size));
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received and queued reply to keep alive" __L);
|
||||
LogNetcode(_L "Received and queued reply to keep alive" __L);
|
||||
}
|
||||
break;
|
||||
case OP_Ack: {
|
||||
if(!p->pBuffer || (p->Size() < 4))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_Ack that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_Ack that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
||||
@ -309,11 +309,11 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
case OP_SessionRequest: {
|
||||
if(p->Size() < sizeof(SessionRequest))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionRequest that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_SessionRequest that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
if (GetState()==ESTABLISHED) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionRequest in ESTABLISHED state (%d) streamactive (%i) attempt (%i)" __L, GetState(),streamactive,sessionAttempts);
|
||||
LogNetcode(_L "Received OP_SessionRequest in ESTABLISHED state ([{}]) streamactive ([{}]) attempt ([{}])" __L, GetState(),streamactive,sessionAttempts);
|
||||
|
||||
// client seems to try a max of 30 times (initial+3 retries) then gives up, giving it a few more attempts just in case
|
||||
// streamactive means we identified the opcode for the stream, we cannot re-establish this connection
|
||||
@ -331,7 +331,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
SessionRequest *Request=(SessionRequest *)p->pBuffer;
|
||||
Session=ntohl(Request->Session);
|
||||
SetMaxLen(ntohl(Request->MaxLength));
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionRequest: session %lu, maxlen %d" __L, (unsigned long)Session, MaxLen);
|
||||
LogNetcode(_L "Received OP_SessionRequest: session [{}], maxlen [{}]" __L, (unsigned long)Session, MaxLen);
|
||||
SetState(ESTABLISHED);
|
||||
Key=0x11223344;
|
||||
SendSessionResponse();
|
||||
@ -340,7 +340,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
case OP_SessionResponse: {
|
||||
if(p->Size() < sizeof(SessionResponse))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionResponse that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_SessionResponse that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -356,7 +356,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
compressed=(Response->Format&FLAG_COMPRESSED);
|
||||
encoded=(Response->Format&FLAG_ENCODED);
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionResponse: session %lu, maxlen %d, key %lu, compressed? %s, encoded? %s" __L, (unsigned long)Session, MaxLen, (unsigned long)Key, compressed?"yes":"no", encoded?"yes":"no");
|
||||
LogNetcode(_L "Received OP_SessionResponse: session [{}], maxlen [{}], key [{}], compressed? [{}], encoded? [{}]" __L, (unsigned long)Session, MaxLen, (unsigned long)Key, compressed?"yes":"no", encoded?"yes":"no");
|
||||
|
||||
// Kinda kludgy, but trie for now
|
||||
if (StreamType==UnknownStream) {
|
||||
@ -379,17 +379,17 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
EQStreamState state = GetState();
|
||||
if(state == ESTABLISHED) {
|
||||
//client initiated disconnect?
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received unsolicited OP_SessionDisconnect. Treating like a client-initiated disconnect." __L);
|
||||
LogNetcode(_L "Received unsolicited OP_SessionDisconnect. Treating like a client-initiated disconnect" __L);
|
||||
_SendDisconnect();
|
||||
SetState(CLOSED);
|
||||
} else if(state == CLOSING) {
|
||||
//we were waiting for this anyways, ignore pending messages, send the reply and be closed.
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionDisconnect when we have a pending close, they beat us to it. Were happy though." __L);
|
||||
LogNetcode(_L "Received OP_SessionDisconnect when we have a pending close, they beat us to it. Were happy though" __L);
|
||||
_SendDisconnect();
|
||||
SetState(CLOSED);
|
||||
} else {
|
||||
//we are expecting this (or have already gotten it, but dont care either way)
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received expected OP_SessionDisconnect. Moving to closed state." __L);
|
||||
LogNetcode(_L "Received expected OP_SessionDisconnect. Moving to closed state" __L);
|
||||
SetState(CLOSED);
|
||||
}
|
||||
}
|
||||
@ -397,14 +397,14 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
case OP_OutOfOrderAck: {
|
||||
if(!p->pBuffer || (p->Size() < 4))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_OutOfOrderAck that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
||||
MOutboundQueue.lock();
|
||||
|
||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Pre-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
LogNetcode(_L "Pre-OOA Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
}
|
||||
|
||||
//if the packet they got out of order is between our last acked packet and the last sent packet, then its valid.
|
||||
@ -414,7 +414,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
|
||||
uint16 sqsize = SequencedQueue.size();
|
||||
uint16 index = seq - SequencedBase;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OP_OutOfOrderAck marking packet acked in queue (queue index = %d, queue size = %d)." __L, index, sqsize);
|
||||
LogNetcode(_L "OP_OutOfOrderAck marking packet acked in queue (queue index = [{}], queue size = [{}])" __L, index, sqsize);
|
||||
if (index < sqsize) {
|
||||
SequencedQueue[index]->acked = true;
|
||||
// flag packets for a resend
|
||||
@ -423,7 +423,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
for (auto sitr = SequencedQueue.begin(); sitr != SequencedQueue.end() && count < index; ++sitr, ++count) {
|
||||
if (!(*sitr)->acked && (*sitr)->sent_time > 0 && (((*sitr)->sent_time + timeout) < Timer::GetCurrentTime())) {
|
||||
(*sitr)->sent_time = 0;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OP_OutOfOrderAck Flagging packet %d for retransmission" __L, SequencedBase + count);
|
||||
LogNetcode(_L "OP_OutOfOrderAck Flagging packet [{}] for retransmission" __L, SequencedBase + count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -432,11 +432,11 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
retransmittimer = Timer::GetCurrentTime();
|
||||
}
|
||||
} else {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck for out-of-window %d. Window (%d->%d)." __L, seq, SequencedBase, NextOutSeq);
|
||||
LogNetcode(_L "Received OP_OutOfOrderAck for out-of-window [{}]. Window ([{}]->[{}])" __L, seq, SequencedBase, NextOutSeq);
|
||||
}
|
||||
|
||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Post-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
LogNetcode(_L "Post-OOA Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
}
|
||||
|
||||
MOutboundQueue.unlock();
|
||||
@ -445,7 +445,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
case OP_SessionStatRequest: {
|
||||
if(p->Size() < sizeof(ClientSessionStats))
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionStatRequest that was of malformed size" __L);
|
||||
LogNetcode(_L "Received OP_SessionStatRequest that was of malformed size" __L);
|
||||
break;
|
||||
}
|
||||
ClientSessionStats *ClientStats=(ClientSessionStats *)p->pBuffer;
|
||||
@ -468,7 +468,7 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
retransmittimeout += 300;
|
||||
if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX)
|
||||
retransmittimeout = RETRANSMIT_TIMEOUT_MAX;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Retransmit timeout recalculated to %dms" __L, retransmittimeout);
|
||||
LogNetcode(_L "Retransmit timeout recalculated to [{}]ms" __L, retransmittimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,11 +485,11 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||
}
|
||||
break;
|
||||
case OP_SessionStatResponse: {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_SessionStatResponse. Ignoring." __L);
|
||||
LogNetcode(_L "Received OP_SessionStatResponse. Ignoring" __L);
|
||||
}
|
||||
break;
|
||||
case OP_OutOfSession: {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfSession. Ignoring." __L);
|
||||
LogNetcode(_L "Received OP_OutOfSession. Ignoring" __L);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -520,7 +520,7 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
|
||||
return;
|
||||
|
||||
if(OpMgr == nullptr || *OpMgr == nullptr) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Packet enqueued into a stream with no opcode manager, dropping." __L);
|
||||
LogNetcode(_L "Packet enqueued into a stream with no opcode manager, dropping" __L);
|
||||
delete pack;
|
||||
return;
|
||||
}
|
||||
@ -559,18 +559,18 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
|
||||
|
||||
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
|
||||
if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2)
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->Size());
|
||||
LogNetcode(_L "Making oversized packet, len [{}]" __L, p->Size());
|
||||
|
||||
auto tmpbuff = new unsigned char[p->size + 3];
|
||||
length=p->serialize(opcode, tmpbuff);
|
||||
if (length != p->Size())
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Packet adjustment, len %d to %d" __L, p->Size(), length);
|
||||
LogNetcode(_L "Packet adjustment, len [{}] to [{}]" __L, p->Size(), length);
|
||||
|
||||
auto out = new EQProtocolPacket(OP_Fragment, nullptr, MaxLen - 4);
|
||||
*(uint32 *)(out->pBuffer+2)=htonl(length);
|
||||
used=MaxLen-10;
|
||||
memcpy(out->pBuffer+6,tmpbuff,used);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "First fragment: used %d/%d. Payload size %d in the packet" __L, used, length, p->size);
|
||||
LogNetcode(_L "First fragment: used [{}]/[{}]. Payload size [{}] in the packet" __L, used, length, p->size);
|
||||
SequencedPush(out);
|
||||
|
||||
|
||||
@ -581,7 +581,7 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
|
||||
out->size=chunksize+2;
|
||||
SequencedPush(out);
|
||||
used+=chunksize;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Subsequent fragment: len %d, used %d/%d." __L, chunksize, used, length);
|
||||
LogNetcode(_L "Subsequent fragment: len [{}], used [{}]/[{}]" __L, chunksize, used, length);
|
||||
}
|
||||
delete p;
|
||||
delete[] tmpbuff;
|
||||
@ -623,7 +623,7 @@ void EQStream::SequencedPush(EQProtocolPacket *p)
|
||||
void EQStream::NonSequencedPush(EQProtocolPacket *p)
|
||||
{
|
||||
MOutboundQueue.lock();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Pushing non-sequenced packet of length %d" __L, p->size);
|
||||
LogNetcode(_L "Pushing non-sequenced packet of length [{}]" __L, p->size);
|
||||
NonSequencedQueue.push(p);
|
||||
MOutboundQueue.unlock();
|
||||
}
|
||||
@ -631,14 +631,14 @@ void EQStream::NonSequencedPush(EQProtocolPacket *p)
|
||||
void EQStream::SendAck(uint16 seq)
|
||||
{
|
||||
uint16 Seq=htons(seq);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Sending ack with sequence %d" __L, seq);
|
||||
LogNetcode(_L "Sending ack with sequence [{}]" __L, seq);
|
||||
SetLastAckSent(seq);
|
||||
NonSequencedPush(new EQProtocolPacket(OP_Ack,(unsigned char *)&Seq,sizeof(uint16)));
|
||||
}
|
||||
|
||||
void EQStream::SendOutOfOrderAck(uint16 seq)
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Sending out of order ack with sequence %d" __L, seq);
|
||||
LogNetcode(_L "Sending out of order ack with sequence [{}]" __L, seq);
|
||||
uint16 Seq=htons(seq);
|
||||
NonSequencedPush(new EQProtocolPacket(OP_OutOfOrderAck,(unsigned char *)&Seq,sizeof(uint16)));
|
||||
}
|
||||
@ -688,24 +688,24 @@ void EQStream::Write(int eq_fd)
|
||||
// If we don't have a packet to try to combine into, use this one as the base
|
||||
// And remove it form the queue
|
||||
p = NonSequencedQueue.front();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Starting combined packet with non-seq packet of len %d" __L, p->size);
|
||||
LogNetcode(_L "Starting combined packet with non-seq packet of len [{}]" __L, p->size);
|
||||
NonSequencedQueue.pop();
|
||||
} else if (!p->combine(NonSequencedQueue.front())) {
|
||||
// Trying to combine this packet with the base didn't work (too big maybe)
|
||||
// So just send the base packet (we'll try this packet again later)
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Combined packet full at len %d, next non-seq packet is len %d" __L, p->size, (NonSequencedQueue.front())->size);
|
||||
LogNetcode(_L "Combined packet full at len [{}], next non-seq packet is len [{}]" __L, p->size, (NonSequencedQueue.front())->size);
|
||||
ReadyToSend.push(p);
|
||||
BytesWritten+=p->size;
|
||||
p=nullptr;
|
||||
|
||||
if (BytesWritten > threshold) {
|
||||
// Sent enough this round, lets stop to be fair
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Exceeded write threshold in nonseq (%d > %d)" __L, BytesWritten, threshold);
|
||||
LogNetcode(_L "Exceeded write threshold in nonseq ([{}] > [{}])" __L, BytesWritten, threshold);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Combine worked, so just remove this packet and it's spot in the queue
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Combined non-seq packet of len %d, yeilding %d combined." __L, (NonSequencedQueue.front())->size, p->size);
|
||||
LogNetcode(_L "Combined non-seq packet of len [{}], yeilding [{}] combined" __L, (NonSequencedQueue.front())->size, p->size);
|
||||
delete NonSequencedQueue.front();
|
||||
NonSequencedQueue.pop();
|
||||
}
|
||||
@ -718,7 +718,7 @@ void EQStream::Write(int eq_fd)
|
||||
uint16 seq_send = SequencedBase + count; //just for logging...
|
||||
|
||||
if(SequencedQueue.empty()) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Tried to write a packet with an empty queue (%d is past next out %d)" __L, seq_send, NextOutSeq);
|
||||
LogNetcode(_L "Tried to write a packet with an empty queue ([{}] is past next out [{}])" __L, seq_send, NextOutSeq);
|
||||
SeqEmpty=true;
|
||||
continue;
|
||||
}
|
||||
@ -728,35 +728,35 @@ void EQStream::Write(int eq_fd)
|
||||
++sitr;
|
||||
++count;
|
||||
if (p) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Final combined packet not full, len %d" __L, p->size);
|
||||
LogNetcode(_L "Final combined packet not full, len [{}]" __L, p->size);
|
||||
ReadyToSend.push(p);
|
||||
BytesWritten += p->size;
|
||||
p = nullptr;
|
||||
}
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Not retransmitting seq packet %d because already marked as acked" __L, seq_send);
|
||||
LogNetcode(_L "Not retransmitting seq packet [{}] because already marked as acked" __L, seq_send);
|
||||
} else if (!p) {
|
||||
// If we don't have a packet to try to combine into, use this one as the base
|
||||
// Copy it first as it will still live until it is acked
|
||||
p=(*sitr)->Copy();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size);
|
||||
LogNetcode(_L "Starting combined packet with seq packet [{}] of len [{}]" __L, seq_send, p->size);
|
||||
(*sitr)->sent_time = Timer::GetCurrentTime();
|
||||
++sitr;
|
||||
++count;
|
||||
} else if (!p->combine(*sitr)) {
|
||||
// Trying to combine this packet with the base didn't work (too big maybe)
|
||||
// So just send the base packet (we'll try this packet again later)
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send + 1, (*sitr)->size);
|
||||
LogNetcode(_L "Combined packet full at len [{}], next seq packet [{}] is len [{}]" __L, p->size, seq_send + 1, (*sitr)->size);
|
||||
ReadyToSend.push(p);
|
||||
BytesWritten+=p->size;
|
||||
p=nullptr;
|
||||
if ((*sitr)->opcode != OP_Fragment && BytesWritten > threshold) {
|
||||
// Sent enough this round, lets stop to be fair
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold);
|
||||
LogNetcode(_L "Exceeded write threshold in seq ([{}] > [{}])" __L, BytesWritten, threshold);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Combine worked
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size);
|
||||
LogNetcode(_L "Combined seq packet [{}] of len [{}], yeilding [{}] combined" __L, seq_send, (*sitr)->size, p->size);
|
||||
(*sitr)->sent_time = Timer::GetCurrentTime();
|
||||
++sitr;
|
||||
++count;
|
||||
@ -766,7 +766,7 @@ void EQStream::Write(int eq_fd)
|
||||
++sitr;
|
||||
++count;
|
||||
if (p) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Final combined packet not full, len %d" __L, p->size);
|
||||
LogNetcode(_L "Final combined packet not full, len [{}]" __L, p->size);
|
||||
ReadyToSend.push(p);
|
||||
BytesWritten += p->size;
|
||||
p = nullptr;
|
||||
@ -776,25 +776,25 @@ void EQStream::Write(int eq_fd)
|
||||
// Copy it first as it will still live until it is acked
|
||||
p=(*sitr)->Copy();
|
||||
(*sitr)->sent_time = Timer::GetCurrentTime();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size);
|
||||
LogNetcode(_L "Starting combined packet with seq packet [{}] of len [{}]" __L, seq_send, p->size);
|
||||
++sitr;
|
||||
++count;
|
||||
} else if (!p->combine(*sitr)) {
|
||||
// Trying to combine this packet with the base didn't work (too big maybe)
|
||||
// So just send the base packet (we'll try this packet again later)
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send, (*sitr)->size);
|
||||
LogNetcode(_L "Combined packet full at len [{}], next seq packet [{}] is len [{}]" __L, p->size, seq_send, (*sitr)->size);
|
||||
ReadyToSend.push(p);
|
||||
BytesWritten+=p->size;
|
||||
p=nullptr;
|
||||
|
||||
if (BytesWritten > threshold) {
|
||||
// Sent enough this round, lets stop to be fair
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold);
|
||||
LogNetcode(_L "Exceeded write threshold in seq ([{}] > [{}])" __L, BytesWritten, threshold);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Combine worked
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Combined seq packet %d of len %d, yielding %d combined." __L, seq_send, (*sitr)->size, p->size);
|
||||
LogNetcode(_L "Combined seq packet [{}] of len [{}], yielding [{}] combined" __L, seq_send, (*sitr)->size, p->size);
|
||||
(*sitr)->sent_time = Timer::GetCurrentTime();
|
||||
++sitr;
|
||||
++count;
|
||||
@ -802,7 +802,7 @@ void EQStream::Write(int eq_fd)
|
||||
}
|
||||
|
||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Post send Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
LogNetcode(_L "Post send Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
}
|
||||
} else {
|
||||
// No more sequenced packets
|
||||
@ -814,7 +814,7 @@ void EQStream::Write(int eq_fd)
|
||||
|
||||
// We have a packet still, must have run out of both seq and non-seq, so send it
|
||||
if (p) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Final combined packet not full, len %d" __L, p->size);
|
||||
LogNetcode(_L "Final combined packet not full, len [{}]" __L, p->size);
|
||||
ReadyToSend.push(p);
|
||||
BytesWritten+=p->size;
|
||||
}
|
||||
@ -831,7 +831,7 @@ void EQStream::Write(int eq_fd)
|
||||
if(SeqEmpty && NonSeqEmpty) {
|
||||
//no more data to send
|
||||
if(CheckState(CLOSING)) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "All outgoing data flushed, closing stream." __L );
|
||||
LogNetcode(_L "All outgoing data flushed, closing stream" __L );
|
||||
//we are waiting for the queues to empty, now we can do our disconnect.
|
||||
//this packet will not actually go out until the next call to Write().
|
||||
_SendDisconnect();
|
||||
@ -910,7 +910,7 @@ void EQStream::SendSessionRequest()
|
||||
Request->Session=htonl(time(nullptr));
|
||||
Request->MaxLength=htonl(512);
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Sending OP_SessionRequest: session %lu, maxlen=%d" __L, (unsigned long)ntohl(Request->Session), ntohl(Request->MaxLength));
|
||||
LogNetcode(_L "Sending OP_SessionRequest: session [{}], maxlen=[{}]" __L, (unsigned long)ntohl(Request->Session), ntohl(Request->MaxLength));
|
||||
|
||||
NonSequencedPush(out);
|
||||
}
|
||||
@ -924,7 +924,7 @@ void EQStream::_SendDisconnect()
|
||||
*(uint32 *)out->pBuffer=htonl(Session);
|
||||
NonSequencedPush(out);
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Sending OP_SessionDisconnect: session %lu" __L, (unsigned long)Session);
|
||||
LogNetcode(_L "Sending OP_SessionDisconnect: session [{}]" __L, (unsigned long)Session);
|
||||
}
|
||||
|
||||
void EQStream::InboundQueuePush(EQRawApplicationPacket *p)
|
||||
@ -976,7 +976,7 @@ EQRawApplicationPacket *p=nullptr;
|
||||
if(OpMgr != nullptr && *OpMgr != nullptr) {
|
||||
EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode);
|
||||
if(emu_op == OP_Unknown) {
|
||||
Log(Logs::General, Logs::Netcode, "Unable to convert EQ opcode 0x%.4x to an Application opcode.", p->opcode);
|
||||
LogNetcode("Unable to convert EQ opcode {:#04x} to an Application opcode", p->opcode);
|
||||
}
|
||||
|
||||
p->SetOpcode(emu_op);
|
||||
@ -1004,7 +1004,7 @@ void EQStream::InboundQueueClear()
|
||||
{
|
||||
EQApplicationPacket *p=nullptr;
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Clearing inbound queue" __L);
|
||||
LogNetcode(_L "Clearing inbound queue" __L);
|
||||
|
||||
MInboundQueue.lock();
|
||||
if (!InboundQueue.empty()) {
|
||||
@ -1047,7 +1047,7 @@ void EQStream::OutboundQueueClear()
|
||||
{
|
||||
EQProtocolPacket *p=nullptr;
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Clearing outbound queue" __L);
|
||||
LogNetcode(_L "Clearing outbound queue" __L);
|
||||
|
||||
MOutboundQueue.lock();
|
||||
while(!NonSequencedQueue.empty()) {
|
||||
@ -1069,7 +1069,7 @@ void EQStream::PacketQueueClear()
|
||||
{
|
||||
EQProtocolPacket *p=nullptr;
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Clearing future packet queue" __L);
|
||||
LogNetcode(_L "Clearing future packet queue" __L);
|
||||
|
||||
if(!PacketQueue.empty()) {
|
||||
std::map<unsigned short,EQProtocolPacket *>::iterator itr;
|
||||
@ -1101,7 +1101,7 @@ void EQStream::Process(const unsigned char *buffer, const uint32 length)
|
||||
delete p;
|
||||
ProcessQueue();
|
||||
} else {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Incoming packet failed checksum" __L);
|
||||
LogNetcode(_L "Incoming packet failed checksum" __L);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1132,23 +1132,23 @@ std::deque<EQProtocolPacket *>::iterator itr, tmp;
|
||||
SeqOrder ord = CompareSequence(SequencedBase, seq);
|
||||
if(ord == SeqInOrder) {
|
||||
//they are not acking anything new...
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received an ack with no window advancement (seq %d)." __L, seq);
|
||||
LogNetcode(_L "Received an ack with no window advancement (seq [{}])" __L, seq);
|
||||
} else if(ord == SeqPast) {
|
||||
//they are nacking blocks going back before our buffer, wtf?
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received an ack with backward window advancement (they gave %d, our window starts at %d). This is bad." __L, seq, SequencedBase);
|
||||
LogNetcode(_L "Received an ack with backward window advancement (they gave [{}], our window starts at [{}]). This is bad" __L, seq, SequencedBase);
|
||||
} else {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Received an ack up through sequence %d. Our base is %d." __L, seq, SequencedBase);
|
||||
LogNetcode(_L "Received an ack up through sequence [{}]. Our base is [{}]" __L, seq, SequencedBase);
|
||||
|
||||
|
||||
//this is a good ack, we get to ack some blocks.
|
||||
seq++; //we stop at the block right after their ack, counting on the wrap of both numbers.
|
||||
while(SequencedBase != seq) {
|
||||
if(SequencedQueue.empty()) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OUT OF PACKETS acked packet with sequence %lu. Next send is %d before this." __L, (unsigned long)SequencedBase, SequencedQueue.size());
|
||||
LogNetcode(_L "OUT OF PACKETS acked packet with sequence [{}]. Next send is [{}] before this" __L, (unsigned long)SequencedBase, SequencedQueue.size());
|
||||
SequencedBase = NextOutSeq;
|
||||
break;
|
||||
}
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Removing acked packet with sequence %lu." __L, (unsigned long)SequencedBase);
|
||||
LogNetcode(_L "Removing acked packet with sequence [{}]" __L, (unsigned long)SequencedBase);
|
||||
//clean out the acked packet
|
||||
delete SequencedQueue.front();
|
||||
SequencedQueue.pop_front();
|
||||
@ -1156,7 +1156,7 @@ std::deque<EQProtocolPacket *>::iterator itr, tmp;
|
||||
SequencedBase++;
|
||||
}
|
||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Post-Ack on %d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, seq, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
LogNetcode(_L "Post-Ack on [{}] Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, seq, SequencedBase, SequencedQueue.size(), NextOutSeq);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1166,7 +1166,7 @@ std::deque<EQProtocolPacket *>::iterator itr, tmp;
|
||||
void EQStream::SetNextAckToSend(uint32 seq)
|
||||
{
|
||||
MAcks.lock();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Set Next Ack To Send to %lu" __L, (unsigned long)seq);
|
||||
LogNetcode(_L "Set Next Ack To Send to [{}]" __L, (unsigned long)seq);
|
||||
NextAckToSend=seq;
|
||||
MAcks.unlock();
|
||||
}
|
||||
@ -1174,7 +1174,7 @@ void EQStream::SetNextAckToSend(uint32 seq)
|
||||
void EQStream::SetLastAckSent(uint32 seq)
|
||||
{
|
||||
MAcks.lock();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Set Last Ack Sent to %lu" __L, (unsigned long)seq);
|
||||
LogNetcode(_L "Set Last Ack Sent to [{}]" __L, (unsigned long)seq);
|
||||
LastAckSent=seq;
|
||||
MAcks.unlock();
|
||||
}
|
||||
@ -1187,10 +1187,10 @@ void EQStream::ProcessQueue()
|
||||
|
||||
EQProtocolPacket *qp=nullptr;
|
||||
while((qp=RemoveQueue(NextInSeq))!=nullptr) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Processing Queued Packet: Seq=%d" __L, NextInSeq);
|
||||
LogNetcode(_L "Processing Queued Packet: Seq=[{}]" __L, NextInSeq);
|
||||
ProcessPacket(qp);
|
||||
delete qp;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OP_Packet Queue size=%d" __L, PacketQueue.size());
|
||||
LogNetcode(_L "OP_Packet Queue size=[{}]" __L, PacketQueue.size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1201,21 +1201,21 @@ EQProtocolPacket *qp=nullptr;
|
||||
if ((itr=PacketQueue.find(seq))!=PacketQueue.end()) {
|
||||
qp=itr->second;
|
||||
PacketQueue.erase(itr);
|
||||
Log(Logs::Detail, Logs::Netcode, _L "OP_Packet Queue size=%d" __L, PacketQueue.size());
|
||||
LogNetcode(_L "OP_Packet Queue size=[{}]" __L, PacketQueue.size());
|
||||
}
|
||||
return qp;
|
||||
}
|
||||
|
||||
void EQStream::SetStreamType(EQStreamType type)
|
||||
{
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Changing stream type from %s to %s" __L, StreamTypeString(StreamType), StreamTypeString(type));
|
||||
LogNetcode(_L "Changing stream type from [{}] to [{}]" __L, StreamTypeString(StreamType), StreamTypeString(type));
|
||||
StreamType=type;
|
||||
switch (StreamType) {
|
||||
case LoginStream:
|
||||
app_opcode_size=1;
|
||||
compressed=false;
|
||||
encoded=false;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Login stream has app opcode size %d, is not compressed or encoded." __L, app_opcode_size);
|
||||
LogNetcode(_L "Login stream has app opcode size [{}], is not compressed or encoded" __L, app_opcode_size);
|
||||
break;
|
||||
case ChatOrMailStream:
|
||||
case ChatStream:
|
||||
@ -1223,7 +1223,7 @@ void EQStream::SetStreamType(EQStreamType type)
|
||||
app_opcode_size=1;
|
||||
compressed=false;
|
||||
encoded=true;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Chat/Mail stream has app opcode size %d, is not compressed, and is encoded." __L, app_opcode_size);
|
||||
LogNetcode(_L "Chat/Mail stream has app opcode size [{}], is not compressed, and is encoded" __L, app_opcode_size);
|
||||
break;
|
||||
case ZoneStream:
|
||||
case WorldStream:
|
||||
@ -1231,7 +1231,7 @@ void EQStream::SetStreamType(EQStreamType type)
|
||||
app_opcode_size=2;
|
||||
compressed=true;
|
||||
encoded=false;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "World/Zone stream has app opcode size %d, is compressed, and is not encoded." __L, app_opcode_size);
|
||||
LogNetcode(_L "World/Zone stream has app opcode size [{}], is compressed, and is not encoded" __L, app_opcode_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1281,7 +1281,7 @@ EQStream::SeqOrder EQStream::CompareSequence(uint16 expected_seq , uint16 seq)
|
||||
|
||||
void EQStream::SetState(EQStreamState state) {
|
||||
MState.lock();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Changing state from %d to %d" __L, State, state);
|
||||
LogNetcode(_L "Changing state from [{}] to [{}]" __L, State, state);
|
||||
State=state;
|
||||
MState.unlock();
|
||||
}
|
||||
@ -1293,29 +1293,29 @@ void EQStream::CheckTimeout(uint32 now, uint32 timeout) {
|
||||
|
||||
EQStreamState orig_state = GetState();
|
||||
if (orig_state == CLOSING && !outgoing_data) {
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Out of data in closing state, disconnecting." __L);
|
||||
LogNetcode(_L "Out of data in closing state, disconnecting" __L);
|
||||
_SendDisconnect();
|
||||
SetState(DISCONNECTING);
|
||||
} else if (LastPacket && (now-LastPacket) > timeout) {
|
||||
switch(orig_state) {
|
||||
case CLOSING:
|
||||
//if we time out in the closing state, they are not acking us, just give up
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Timeout expired in closing state. Moving to closed state." __L);
|
||||
LogNetcode(_L "Timeout expired in closing state. Moving to closed state" __L);
|
||||
_SendDisconnect();
|
||||
SetState(CLOSED);
|
||||
break;
|
||||
case DISCONNECTING:
|
||||
//we timed out waiting for them to send us the disconnect reply, just give up.
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Timeout expired in disconnecting state. Moving to closed state." __L);
|
||||
LogNetcode(_L "Timeout expired in disconnecting state. Moving to closed state" __L);
|
||||
SetState(CLOSED);
|
||||
break;
|
||||
case CLOSED:
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Timeout expired in closed state??" __L);
|
||||
LogNetcode(_L "Timeout expired in closed state??" __L);
|
||||
break;
|
||||
case ESTABLISHED:
|
||||
//we timed out during normal operation. Try to be nice about it.
|
||||
//we will almost certainly time out again waiting for the disconnect reply, but oh well.
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Timeout expired in established state. Closing connection." __L);
|
||||
LogNetcode(_L "Timeout expired in established state. Closing connection" __L);
|
||||
_SendDisconnect();
|
||||
SetState(DISCONNECTING);
|
||||
break;
|
||||
@ -1342,7 +1342,7 @@ void EQStream::Decay()
|
||||
for (auto sitr = SequencedQueue.begin(); sitr != SequencedQueue.end(); ++sitr, count++) {
|
||||
if (!(*sitr)->acked && (*sitr)->sent_time > 0 && ((*sitr)->sent_time + retransmittimeout) < Timer::GetCurrentTime()) {
|
||||
(*sitr)->sent_time = 0;
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Timeout exceeded for seq %d. Flagging packet for retransmission" __L, SequencedBase + count);
|
||||
LogNetcode(_L "Timeout exceeded for seq [{}]. Flagging packet for retransmission" __L, SequencedBase + count);
|
||||
}
|
||||
}
|
||||
MOutboundQueue.unlock();
|
||||
@ -1384,12 +1384,12 @@ void EQStream::AdjustRates(uint32 average_delta)
|
||||
void EQStream::Close() {
|
||||
if(HasOutgoingData()) {
|
||||
//there is pending data, wait for it to go out.
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Stream requested to Close(), but there is pending data, waiting for it." __L);
|
||||
LogNetcode(_L "Stream requested to Close(), but there is pending data, waiting for it" __L);
|
||||
SetState(CLOSING);
|
||||
} else {
|
||||
//otherwise, we are done, we can drop immediately.
|
||||
_SendDisconnect();
|
||||
Log(Logs::Detail, Logs::Netcode, _L "Stream closing immediate due to Close()" __L);
|
||||
LogNetcode(_L "Stream closing immediate due to Close()" __L);
|
||||
SetState(DISCONNECTING);
|
||||
}
|
||||
}
|
||||
@ -1417,19 +1417,19 @@ EQStream::MatchState EQStream::CheckSignature(const Signature *sig) {
|
||||
} else if(p->opcode == sig->first_eq_opcode) {
|
||||
//opcode matches, check length..
|
||||
if(p->size == sig->first_length) {
|
||||
Log(Logs::General, Logs::Netcode, "[IDENT_TRACE] %s:%d: First opcode matched 0x%x and length matched %d", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size);
|
||||
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode matched {:#04x} and length matched [{}]", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size);
|
||||
res = MatchSuccessful;
|
||||
} else if(sig->first_length == 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[IDENT_TRACE] %s:%d: First opcode matched 0x%x and length (%d) is ignored", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size);
|
||||
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode matched {:#04x} and length ([{}]) is ignored", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size);
|
||||
res = MatchSuccessful;
|
||||
} else {
|
||||
//opcode matched but length did not.
|
||||
Log(Logs::General, Logs::Netcode, "[IDENT_TRACE] %s:%d: First opcode matched 0x%x, but length %d did not match expected %d", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size, sig->first_length);
|
||||
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode matched {:#04x}, but length [{}] did not match expected [{}]", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size, sig->first_length);
|
||||
res = MatchFailed;
|
||||
}
|
||||
} else {
|
||||
//first opcode did not match..
|
||||
Log(Logs::General, Logs::Netcode, "[IDENT_TRACE] %s:%d: First opcode 0x%x did not match expected 0x%x", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), p->opcode, sig->first_eq_opcode);
|
||||
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode {:#04x} did not match expected {:#04x}", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), p->opcode, sig->first_eq_opcode);
|
||||
res = MatchFailed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ void EQStreamIdentifier::Process() {
|
||||
|
||||
//first see if this stream has expired
|
||||
if(r.expire.Check(false)) {
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Unable to identify stream from %s:%d before timeout.", r.stream->GetRemoteAddr().c_str(), ntohs(r.stream->GetRemotePort()));
|
||||
LogNetcode("[StreamIdentify] Unable to identify stream from [{}:{}] before timeout", r.stream->GetRemoteAddr().c_str(), ntohs(r.stream->GetRemotePort()));
|
||||
r.stream->Close();
|
||||
|
||||
cur = m_streams.erase(cur);
|
||||
@ -62,23 +62,23 @@ void EQStreamIdentifier::Process() {
|
||||
}
|
||||
if(r.stream->GetState() != ESTABLISHED) {
|
||||
//the stream closed before it was identified.
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Unable to identify stream from %s:%d before it closed.", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()));
|
||||
LogNetcode("[StreamIdentify] Unable to identify stream from [{}:{}] before it closed", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()));
|
||||
switch(r.stream->GetState())
|
||||
{
|
||||
case ESTABLISHED:
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Stream state was Established");
|
||||
LogNetcode("[StreamIdentify] Stream state was Established");
|
||||
break;
|
||||
case CLOSING:
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Stream state was Closing");
|
||||
LogNetcode("[StreamIdentify] Stream state was Closing");
|
||||
break;
|
||||
case DISCONNECTING:
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Stream state was Disconnecting");
|
||||
LogNetcode("[StreamIdentify] Stream state was Disconnecting");
|
||||
break;
|
||||
case CLOSED:
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Stream state was Closed");
|
||||
LogNetcode("[StreamIdentify] Stream state was Closed");
|
||||
break;
|
||||
default:
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Stream state was Unestablished or unknown");
|
||||
LogNetcode("[StreamIdentify] Stream state was Unestablished or unknown");
|
||||
break;
|
||||
}
|
||||
r.stream->ReleaseFromUse();
|
||||
@ -102,13 +102,13 @@ void EQStreamIdentifier::Process() {
|
||||
switch(res) {
|
||||
case EQStreamInterface::MatchNotReady:
|
||||
//the stream has not received enough packets to compare with this signature
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[IDENT_TRACE] %s:%d: Tried patch %s, but stream is not ready for it.", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
|
||||
// Log.LogDebugType(Logs::General, Logs::Netcode, "[StreamIdentify] %s:%d: Tried patch %s, but stream is not ready for it.", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
|
||||
all_ready = false;
|
||||
break;
|
||||
case EQStreamInterface::MatchSuccessful: {
|
||||
//yay, a match.
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Identified stream %s:%d with signature %s", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
|
||||
LogNetcode("[StreamIdentify] Identified stream [{}:{}] with signature [{}]", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
|
||||
|
||||
// before we assign the eqstream to an interface, let the stream recognize it is in use and the session should not be reset any further
|
||||
r.stream->SetActive(true);
|
||||
@ -122,7 +122,7 @@ void EQStreamIdentifier::Process() {
|
||||
}
|
||||
case EQStreamInterface::MatchFailed:
|
||||
//do nothing...
|
||||
Log(Logs::General, Logs::Netcode, "[IDENT_TRACE] %s:%d: Tried patch %s, and it did not match.", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
|
||||
LogNetcode("[StreamIdentify] [{}:{}] Tried patch [{}] and it did not match", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()), p->name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -130,7 +130,7 @@ void EQStreamIdentifier::Process() {
|
||||
//if we checked all patches and did not find a match.
|
||||
if(all_ready && !found_one) {
|
||||
//the stream cannot be identified.
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Unable to identify stream from %s:%d, no match found.", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()));
|
||||
LogNetcode("[StreamIdentify] Unable to identify stream from [{}:{}], no match found", long2ip(r.stream->GetRemoteIP()).c_str(), ntohs(r.stream->GetRemotePort()));
|
||||
r.stream->ReleaseFromUse();
|
||||
}
|
||||
|
||||
|
||||
@ -42,8 +42,8 @@ void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
|
||||
return;
|
||||
|
||||
if (p->GetOpcode() != OP_SpecialMesg) {
|
||||
Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
|
||||
Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
|
||||
Log(Logs::General, Logs::PacketServerClient, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
|
||||
Log(Logs::General, Logs::PacketServerClientWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
|
||||
}
|
||||
|
||||
EQApplicationPacket *newp = p->Copy();
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "eqemu_logsys.h"
|
||||
#include "rulesys.h"
|
||||
#include "platform.h"
|
||||
#include "string_util.h"
|
||||
#include "database.h"
|
||||
@ -86,18 +87,14 @@ namespace Console {
|
||||
*/
|
||||
EQEmuLogSys::EQEmuLogSys()
|
||||
{
|
||||
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
||||
on_log_console_hook = [](uint16 debug_level, uint16 log_type, const std::string &) {};
|
||||
bool file_logs_enabled = false;
|
||||
int log_platform = 0;
|
||||
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
||||
on_log_console_hook = [](uint16 debug_level, uint16 log_type, const std::string &) {};
|
||||
}
|
||||
|
||||
/**
|
||||
* EQEmuLogSys Deconstructor
|
||||
*/
|
||||
EQEmuLogSys::~EQEmuLogSys()
|
||||
{
|
||||
}
|
||||
EQEmuLogSys::~EQEmuLogSys() = default;
|
||||
|
||||
void EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
{
|
||||
@ -105,7 +102,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
* Get Executable platform currently running this code (Zone/World/etc)
|
||||
*/
|
||||
log_platform = GetExecutablePlatformInt();
|
||||
|
||||
|
||||
for (int log_category_id = Logs::AA; log_category_id != Logs::MaxCategoryID; log_category_id++) {
|
||||
log_settings[log_category_id].log_to_console = 0;
|
||||
log_settings[log_category_id].log_to_file = 0;
|
||||
@ -118,15 +115,26 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
/**
|
||||
* Set Defaults
|
||||
*/
|
||||
log_settings[Logs::World_Server].log_to_console = Logs::General;
|
||||
log_settings[Logs::Zone_Server].log_to_console = Logs::General;
|
||||
log_settings[Logs::QS_Server].log_to_console = Logs::General;
|
||||
log_settings[Logs::UCS_Server].log_to_console = Logs::General;
|
||||
log_settings[Logs::Crash].log_to_console = Logs::General;
|
||||
log_settings[Logs::MySQLError].log_to_console = Logs::General;
|
||||
log_settings[Logs::Login_Server].log_to_console = Logs::General;
|
||||
log_settings[Logs::Headless_Client].log_to_console = Logs::General;
|
||||
log_settings[Logs::NPCScaling].log_to_gmsay = Logs::General;
|
||||
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
*/
|
||||
log_settings[Logs::Emergency].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Alert].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Critical].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Notice].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* Set Category enabled status on defaults
|
||||
@ -167,20 +175,41 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
|
||||
{
|
||||
return (
|
||||
log_category == Logs::Emergency ||
|
||||
log_category == Logs::Alert ||
|
||||
log_category == Logs::Critical ||
|
||||
log_category == Logs::Error ||
|
||||
log_category == Logs::Warning ||
|
||||
log_category == Logs::Notice ||
|
||||
log_category == Logs::Info ||
|
||||
log_category == Logs::Debug
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @param in_message
|
||||
* @return
|
||||
*/
|
||||
std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::string &in_message)
|
||||
std::string EQEmuLogSys::FormatOutMessageString(
|
||||
uint16 log_category,
|
||||
const std::string &in_message
|
||||
)
|
||||
{
|
||||
std::string ret;
|
||||
ret.push_back('[');
|
||||
ret.append(Logs::LogCategoryName[log_category]);
|
||||
ret.push_back(']');
|
||||
ret.push_back(' ');
|
||||
ret.append(in_message);
|
||||
return ret;
|
||||
std::string return_string;
|
||||
|
||||
if (IsRfc5424LogCategory(log_category)) {
|
||||
return_string = "[" + GetPlatformName() + "] ";
|
||||
}
|
||||
|
||||
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +217,11 @@ std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message)
|
||||
void EQEmuLogSys::ProcessGMSay(
|
||||
uint16 debug_level,
|
||||
uint16 log_category,
|
||||
const std::string &message
|
||||
)
|
||||
{
|
||||
/**
|
||||
* Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash
|
||||
@ -210,7 +243,11 @@ void EQEmuLogSys::ProcessGMSay(uint16 debug_level, uint16 log_category, const st
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message)
|
||||
void EQEmuLogSys::ProcessLogWrite(
|
||||
uint16 debug_level,
|
||||
uint16 log_category,
|
||||
const std::string &message
|
||||
)
|
||||
{
|
||||
if (log_category == Logs::Crash) {
|
||||
char time_stamp[80];
|
||||
@ -272,6 +309,8 @@ std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
|
||||
case Logs::Normal:
|
||||
return LC_YELLOW;
|
||||
case Logs::MySQLError:
|
||||
case Logs::Warning:
|
||||
case Logs::Critical:
|
||||
case Logs::Error:
|
||||
return LC_RED;
|
||||
case Logs::MySQLQuery:
|
||||
@ -343,6 +382,42 @@ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category,
|
||||
on_log_console_hook(debug_level, log_category, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *str_end(const char *str)
|
||||
{
|
||||
return *str ? str_end(str + 1) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr bool str_slant(const char *str)
|
||||
{
|
||||
return *str == '/' ? true : (*str ? str_slant(str + 1) : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *r_slant(const char *str)
|
||||
{
|
||||
return *str == '/' ? (str + 1) : r_slant(str - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
constexpr const char *base_file_name(const char *str)
|
||||
{
|
||||
return str_slant(str) ? r_slant(str_end(str)) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logging function
|
||||
*
|
||||
@ -351,7 +426,15 @@ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category,
|
||||
* @param message
|
||||
* @param ...
|
||||
*/
|
||||
void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...)
|
||||
void EQEmuLogSys::Out(
|
||||
Logs::DebugLevel debug_level,
|
||||
uint16 log_category,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line,
|
||||
const char *message,
|
||||
...
|
||||
)
|
||||
{
|
||||
bool log_to_console = true;
|
||||
if (log_settings[log_category].log_to_console < debug_level) {
|
||||
@ -373,12 +456,18 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st
|
||||
return;
|
||||
}
|
||||
|
||||
std::string prefix;
|
||||
|
||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
std::string output_message = vStringFormat(message.c_str(), args);
|
||||
std::string output_message = vStringFormat(message, args);
|
||||
va_end(args);
|
||||
|
||||
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, output_message);
|
||||
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
|
||||
|
||||
if (log_to_console) {
|
||||
EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message);
|
||||
@ -414,7 +503,7 @@ void EQEmuLogSys::MakeDirectory(const std::string &directory_name)
|
||||
return;
|
||||
_mkdir(directory_name.c_str());
|
||||
#else
|
||||
struct stat st;
|
||||
struct stat st{};
|
||||
if (stat(directory_name.c_str(), &st) == 0) { // exists
|
||||
return;
|
||||
}
|
||||
@ -455,12 +544,7 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuLogSys::Out(
|
||||
Logs::General,
|
||||
Logs::Status,
|
||||
"Starting File Log 'logs/%s_%i.log'",
|
||||
platform_file_name.c_str(),
|
||||
getpid());
|
||||
LogInfo("Starting File Log [logs/{}_{}.log]", platform_file_name.c_str(), getpid());
|
||||
|
||||
/**
|
||||
* Make directory if not exists
|
||||
@ -480,17 +564,11 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
|
||||
/**
|
||||
* All other processes
|
||||
*/
|
||||
|
||||
if (platform_file_name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuLogSys::Out(
|
||||
Logs::General,
|
||||
Logs::Status,
|
||||
"Starting File Log 'logs/%s_%i.log'",
|
||||
platform_file_name.c_str(),
|
||||
getpid());
|
||||
LogInfo("Starting File Log [logs/{}_{}.log]", platform_file_name.c_str(), getpid());
|
||||
|
||||
/**
|
||||
* Open file pointer
|
||||
|
||||
@ -25,6 +25,14 @@
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef utf16_to_utf8
|
||||
#undef utf16_to_utf8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "types.h"
|
||||
|
||||
namespace Logs {
|
||||
@ -45,7 +53,7 @@ namespace Logs {
|
||||
AI,
|
||||
Aggro,
|
||||
Attack,
|
||||
Client_Server_Packet,
|
||||
PacketClientServer,
|
||||
Combat,
|
||||
Commands,
|
||||
Crash,
|
||||
@ -59,40 +67,46 @@ namespace Logs {
|
||||
Normal,
|
||||
Object,
|
||||
Pathing,
|
||||
QS_Server,
|
||||
QSServer,
|
||||
Quests,
|
||||
Rules,
|
||||
Skills,
|
||||
Spawns,
|
||||
Spells,
|
||||
Status,
|
||||
TCP_Connection,
|
||||
TCPConnection,
|
||||
Tasks,
|
||||
Tradeskills,
|
||||
Trading,
|
||||
Tribute,
|
||||
UCS_Server,
|
||||
WebInterface_Server,
|
||||
World_Server,
|
||||
Zone_Server,
|
||||
UCSServer,
|
||||
WebInterfaceServer,
|
||||
WorldServer,
|
||||
ZoneServer,
|
||||
MySQLError,
|
||||
MySQLQuery,
|
||||
Mercenaries,
|
||||
QuestDebug,
|
||||
Server_Client_Packet,
|
||||
Client_Server_Packet_Unhandled,
|
||||
Server_Client_Packet_With_Dump,
|
||||
Client_Server_Packet_With_Dump,
|
||||
Login_Server,
|
||||
Client_Login,
|
||||
Headless_Client,
|
||||
HP_Update,
|
||||
PacketServerClient,
|
||||
PacketClientServerUnhandled,
|
||||
PacketServerClientWithDump,
|
||||
PacketClientServerWithDump,
|
||||
Loginserver,
|
||||
ClientLogin,
|
||||
HeadlessClient,
|
||||
HPUpdate,
|
||||
FixZ,
|
||||
Food,
|
||||
Traps,
|
||||
NPCRoamBox,
|
||||
NPCScaling,
|
||||
MobAppearance,
|
||||
Info,
|
||||
Warning,
|
||||
Critical,
|
||||
Emergency,
|
||||
Alert,
|
||||
Notice,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@ -152,19 +166,17 @@ namespace Logs {
|
||||
"Traps",
|
||||
"NPC Roam Box",
|
||||
"NPC Scaling",
|
||||
"Mob Appearance"
|
||||
"Mob Appearance",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Critical",
|
||||
"Emergency",
|
||||
"Alert",
|
||||
"Notice"
|
||||
};
|
||||
}
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
LogSys.Out(debug_level, log_category, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogF(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
OutF(LogSys, debug_level, log_category, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
#include "eqemu_logsys_log_aliases.h"
|
||||
|
||||
class EQEmuLogSys {
|
||||
public:
|
||||
@ -177,6 +189,10 @@ public:
|
||||
*/
|
||||
void CloseFileLogs();
|
||||
void LoadLogSettingsDefaults();
|
||||
|
||||
/**
|
||||
* @param directory_name
|
||||
*/
|
||||
void MakeDirectory(const std::string &directory_name);
|
||||
|
||||
/**
|
||||
@ -188,12 +204,25 @@ public:
|
||||
* - This would pipe the same category and debug level to all output formats, but the internal memory reference of log_settings would
|
||||
* be checked against to see if that piped output is set to actually process it for the category and debug level
|
||||
*/
|
||||
void Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...);
|
||||
void Out(
|
||||
Logs::DebugLevel debug_level,
|
||||
uint16 log_category,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line,
|
||||
const char *message,
|
||||
...
|
||||
);
|
||||
|
||||
/**
|
||||
* Used in file logs to prepend a timestamp entry for logs
|
||||
* @param time_stamp
|
||||
*/
|
||||
void SetCurrentTimeStamp(char* time_stamp);
|
||||
|
||||
/**
|
||||
* @param log_name
|
||||
*/
|
||||
void StartFileLogs(const std::string &log_name = "");
|
||||
|
||||
/**
|
||||
@ -218,14 +247,14 @@ public:
|
||||
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
|
||||
* Database loaded via Database::LoadLogSettings(log_settings)
|
||||
*/
|
||||
LogSettings log_settings[Logs::LogCategory::MaxCategoryID];
|
||||
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
|
||||
|
||||
bool file_logs_enabled;
|
||||
bool file_logs_enabled = false;
|
||||
|
||||
/**
|
||||
* Sets Executable platform (Zone/World/UCS) etc.
|
||||
*/
|
||||
int log_platform;
|
||||
int log_platform = 0;
|
||||
|
||||
/**
|
||||
* File name used in writing logs
|
||||
@ -240,7 +269,14 @@ public:
|
||||
*/
|
||||
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
||||
|
||||
/**
|
||||
* @param f
|
||||
*/
|
||||
void SetGMSayHandler(std::function<void(uint16 log_type, const std::string&)> f) { on_log_gmsay_hook = f; }
|
||||
|
||||
/**
|
||||
* @param f
|
||||
*/
|
||||
void SetConsoleHandler(std::function<void(uint16 debug_level, uint16 log_type, const std::string&)> f) { on_log_console_hook = f; }
|
||||
|
||||
private:
|
||||
@ -258,6 +294,7 @@ private:
|
||||
|
||||
/**
|
||||
* Linux console color messages mapped by category
|
||||
*
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
@ -268,11 +305,57 @@ private:
|
||||
*/
|
||||
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
|
||||
/**
|
||||
* @param log_category
|
||||
* @return
|
||||
*/
|
||||
bool IsRfc5424LogCategory(uint16 log_category);
|
||||
};
|
||||
|
||||
extern EQEmuLogSys LogSys;
|
||||
|
||||
/**
|
||||
template<typename... Args>
|
||||
void OutF(
|
||||
EQEmuLogSys &ls,
|
||||
Logs::DebugLevel debug_level,
|
||||
uint16 log_category,
|
||||
const char *file,
|
||||
const char *func,
|
||||
int line,
|
||||
const char *fmt,
|
||||
const Args &... args
|
||||
)
|
||||
{
|
||||
std::string log_str = fmt::format(fmt, args...);
|
||||
ls.Out(debug_level, log_category, file, func, line, log_str.c_str());
|
||||
}
|
||||
**/
|
||||
|
||||
#define OutF(ls, debug_level, log_category, file, func, line, formatStr, ...) \
|
||||
do { \
|
||||
ls.Out(debug_level, log_category, file, func, line, fmt::format(formatStr, ##__VA_ARGS__).c_str()); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
507
common/eqemu_logsys_log_aliases.h
Normal file
507
common/eqemu_logsys_log_aliases.h
Normal file
@ -0,0 +1,507 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_EQEMU_LOGSYS_LOG_ALIASES_H
|
||||
#define EQEMU_EQEMU_LOGSYS_LOG_ALIASES_H
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
*/
|
||||
|
||||
#define LogEmergency(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Emergency].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Emergency, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAlert(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Alert].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Alert, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCritical(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Critical].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Critical, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogError(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Error].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Error, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogWarning(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Warning].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Warning, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNotice(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Notice].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Notice, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogInfo(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Info].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Info, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDebug(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Debug].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Debug, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Category
|
||||
*/
|
||||
|
||||
#define LogAA(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::AA].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::AA, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAADetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::AA].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::AA, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAI(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::AI].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::AI, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAIDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::AI].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::AI, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAggro(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Aggro].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Aggro, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAggroDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Aggro].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Aggro, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAttack(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Attack].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Attack, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogAttackDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Attack].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Attack, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPacketClientServer(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::PacketClientServer].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::PacketClientServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPacketClientServerDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::PacketClientServer].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::PacketClientServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCombat(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Combat].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Combat, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCombatDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Combat].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Combat, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCommands(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Commands].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Commands, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCommandsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Commands].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Commands, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCrash(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Crash].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Crash, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCrashDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Crash].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Crash, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDoors(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Doors].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Doors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDoorsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Doors].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Doors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogGuilds(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Guilds].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogGuildsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Guilds].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogInventory(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Inventory].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Inventory, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogInventoryDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Inventory].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Inventory, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogLauncher(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Launcher].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Launcher, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogLauncherDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Launcher].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Launcher, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNetcode(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Netcode].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Netcode, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNetcodeDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Netcode].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Netcode, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNormal(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Normal].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Normal, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNormalDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Normal].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Normal, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogObject(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Object].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Object, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogObjectDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Object].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Object, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPathing(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Pathing].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Pathing, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPathingDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Pathing].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Pathing, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogQSServer(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::QSServer].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::QSServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogQSServerDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::QSServer].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::QSServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogQuests(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Quests].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Quests, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogQuestsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Quests].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Quests, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogRules(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Rules].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Rules, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogRulesDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Rules].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Rules, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogSkills(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Skills].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Skills, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogSkillsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Skills].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Skills, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogSpawns(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Spawns].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Spawns, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogSpawnsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Spawns].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Spawns, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogSpells(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Spells].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Spells, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogSpellsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Spells].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Spells, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTCPConnection(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::TCPConnection].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::TCPConnection, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTCPConnectionDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::TCPConnection].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::TCPConnection, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTasks(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Tasks].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Tasks, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTasksDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Tasks].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Tasks, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTradeskills(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Tradeskills].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Tradeskills, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTradeskillsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Tradeskills].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Tradeskills, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTrading(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Trading].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Trading, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTradingDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Trading].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Trading, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTribute(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Tribute].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Tribute, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTributeDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Tribute].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Tribute, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMySQLError(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::MySQLError].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::MySQLError, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMySQLErrorDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::MySQLError].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::MySQLError, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMySQLQuery(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::MySQLQuery, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMySQLQueryDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::MySQLQuery, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMercenaries(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Mercenaries].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Mercenaries, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMercenariesDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Mercenaries].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Mercenaries, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogQuestDebug(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::QuestDebug].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::QuestDebug, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogQuestDebugDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::QuestDebug].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::QuestDebug, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogLoginserver(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Loginserver].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Loginserver, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogLoginserverDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Loginserver].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Loginserver, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogClientLogin(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::ClientLogin].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::ClientLogin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogClientLoginDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::ClientLogin].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::ClientLogin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHeadlessClient(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::HeadlessClient].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::HeadlessClient, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHeadlessClientDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::HeadlessClient].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::HeadlessClient, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHPUpdate(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::HPUpdate].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::HPUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHPUpdateDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::HPUpdate].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::HPUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogFixZ(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::FixZ].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::FixZ, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogFixZDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::FixZ].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::FixZ, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogFood(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Food].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Food, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogFoodDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Food].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Food, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTraps(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Traps].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Traps, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogTrapsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Traps].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Traps, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNPCRoamBox(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::NPCRoamBox].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::NPCRoamBox, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNPCRoamBoxDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::NPCRoamBox].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::NPCRoamBox, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNPCScaling(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::NPCScaling].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::NPCScaling, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogNPCScalingDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::NPCScaling].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::NPCScaling, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMobAppearance(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::MobAppearance].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::MobAppearance, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogMobAppearanceDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::MobAppearance].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::MobAppearance, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogStatus(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Status].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Status, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogStatusDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Status].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Status, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Misc
|
||||
*/
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogF(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
OutF(LogSys, debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif //EQEMU_EQEMU_LOGSYS_LOG_ALIASES_H
|
||||
114
common/event/task_scheduler.h
Normal file
114
common/event/task_scheduler.h
Normal file
@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <future>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Event
|
||||
{
|
||||
class TaskScheduler
|
||||
{
|
||||
public:
|
||||
static const int DefaultThreadCount = 4;
|
||||
|
||||
TaskScheduler() : _running(false)
|
||||
{
|
||||
Start(DefaultThreadCount);
|
||||
}
|
||||
|
||||
TaskScheduler(size_t threads) : _running(false)
|
||||
{
|
||||
Start(threads);
|
||||
}
|
||||
|
||||
~TaskScheduler() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Start(size_t threads) {
|
||||
if (true == _running) {
|
||||
return;
|
||||
}
|
||||
|
||||
_running = true;
|
||||
|
||||
for (size_t i = 0; i < threads; ++i) {
|
||||
_threads.push_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
if (false == _running) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_lock);
|
||||
_running = false;
|
||||
}
|
||||
|
||||
_cv.notify_all();
|
||||
|
||||
for (auto &t : _threads) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Fn, typename... Args>
|
||||
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::result_of<Fn(Args...)>::type> {
|
||||
using return_type = typename std::result_of<Fn(Args...)>::type;
|
||||
|
||||
auto task = std::make_shared<std::packaged_task<return_type()>>(
|
||||
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...)
|
||||
);
|
||||
|
||||
std::future<return_type> res = task->get_future();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_lock);
|
||||
|
||||
if (false == _running) {
|
||||
throw std::runtime_error("Enqueue on stopped scheduler.");
|
||||
}
|
||||
|
||||
_tasks.emplace([task]() { (*task)(); });
|
||||
}
|
||||
|
||||
_cv.notify_one();
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
void ProcessWork() {
|
||||
for (;;) {
|
||||
std::function<void()> work;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_lock);
|
||||
_cv.wait(lock, [this] { return !_running || !_tasks.empty(); });
|
||||
|
||||
if (false == _running) {
|
||||
return;
|
||||
}
|
||||
|
||||
work = std::move(_tasks.front());
|
||||
_tasks.pop();
|
||||
}
|
||||
|
||||
work();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool _running = true;
|
||||
std::vector<std::thread> _threads;
|
||||
std::mutex _lock;
|
||||
std::condition_variable _cv;
|
||||
std::queue<std::function<void()>> _tasks;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ bool BaseGuildManager::LoadGuilds() {
|
||||
ClearGuilds();
|
||||
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to load guilds when we have no database object.");
|
||||
LogGuilds("Requested to load guilds when we have no database object");
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -77,13 +77,13 @@ bool BaseGuildManager::LoadGuilds() {
|
||||
uint8 rankn = atoi(row[1]);
|
||||
|
||||
if(rankn > GUILD_MAX_RANK) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Found invalid (too high) rank %d for guild %d, skipping.", rankn, guild_id);
|
||||
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Found rank %d for non-existent guild %d, skipping.", rankn, guild_id);
|
||||
LogGuilds("Found rank [{}] for non-existent guild [{}], skipping", rankn, guild_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ bool BaseGuildManager::LoadGuilds() {
|
||||
|
||||
bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to refresh guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to refresh guild [{}] when we have no database object", guild_id);
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
Log(Logs::Detail, Logs::Guilds, "Unable to find guild %d in the database.", guild_id);
|
||||
LogGuilds("Unable to find guild [{}] in the database", guild_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
uint8 rankn = atoi(row[1]);
|
||||
|
||||
if(rankn > GUILD_MAX_RANK) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Found invalid (too high) rank %d for guild %d, skipping.", rankn, guild_id);
|
||||
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
|
||||
rank.permissions[GUILD_WARPEACE] = (row[10][0] == '1') ? true: false;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Successfully refreshed guild %d from the database.", guild_id);
|
||||
LogGuilds("Successfully refreshed guild [{}] from the database", guild_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -214,14 +214,14 @@ BaseGuildManager::GuildInfo *BaseGuildManager::_CreateGuild(uint32 guild_id, con
|
||||
|
||||
bool BaseGuildManager::_StoreGuildDB(uint32 guild_id) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to store guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to store guild [{}] when we have no database object", guild_id);
|
||||
return(false);
|
||||
}
|
||||
|
||||
std::map<uint32, GuildInfo *>::const_iterator res;
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to store non-existent guild %d", guild_id);
|
||||
LogGuilds("Requested to store non-existent guild [{}]", guild_id);
|
||||
return(false);
|
||||
}
|
||||
GuildInfo *info = res->second;
|
||||
@ -289,14 +289,14 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id) {
|
||||
safe_delete_array(title_esc);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Stored guild %d in the database", guild_id);
|
||||
LogGuilds("Stored guild [{}] in the database", guild_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 BaseGuildManager::_GetFreeGuildID() {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested find a free guild ID when we have no database object.");
|
||||
LogGuilds("Requested find a free guild ID when we have no database object");
|
||||
return(GUILD_NONE);
|
||||
}
|
||||
|
||||
@ -330,12 +330,12 @@ uint32 BaseGuildManager::_GetFreeGuildID() {
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
Log(Logs::Detail, Logs::Guilds, "Located free guild ID %d in the database", index);
|
||||
LogGuilds("Located free guild ID [{}] in the database", index);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Unable to find a free guild ID when requested.");
|
||||
LogGuilds("Unable to find a free guild ID when requested");
|
||||
return GUILD_NONE;
|
||||
}
|
||||
|
||||
@ -505,11 +505,11 @@ uint32 BaseGuildManager::DBCreateGuild(const char* name, uint32 leader) {
|
||||
|
||||
//now store the resulting guild setup into the DB.
|
||||
if(!_StoreGuildDB(new_id)) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Error storing new guild. It may have been partially created which may need manual removal.");
|
||||
LogGuilds("Error storing new guild. It may have been partially created which may need manual removal");
|
||||
return(GUILD_NONE);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Created guild %d in the database.", new_id);
|
||||
LogGuilds("Created guild [{}] in the database", new_id);
|
||||
|
||||
return(new_id);
|
||||
}
|
||||
@ -525,7 +525,7 @@ bool BaseGuildManager::DBDeleteGuild(uint32 guild_id) {
|
||||
}
|
||||
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to delete guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to delete guild [{}] when we have no database object", guild_id);
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -545,14 +545,14 @@ bool BaseGuildManager::DBDeleteGuild(uint32 guild_id) {
|
||||
query = StringFormat("DELETE FROM guild_bank WHERE guildid=%lu", (unsigned long)guild_id);
|
||||
QueryWithLogging(query, "deleting guild bank");
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Deleted guild %d from the database.", guild_id);
|
||||
LogGuilds("Deleted guild [{}] from the database", guild_id);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool BaseGuildManager::DBRenameGuild(uint32 guild_id, const char* name) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to rename guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to rename guild [{}] when we have no database object", guild_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -573,13 +573,13 @@ bool BaseGuildManager::DBRenameGuild(uint32 guild_id, const char* name) {
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
Log(Logs::Detail, Logs::Guilds, "Error renaming guild %d '%s': %s", guild_id, query.c_str(), results.Success());
|
||||
LogGuilds("Error renaming guild [{}] [{}]: [{}]", guild_id, query.c_str(), results.Success());
|
||||
safe_delete_array(esc);
|
||||
return false;
|
||||
}
|
||||
safe_delete_array(esc);
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Renamed guild %s (%d) to %s in database.", info->name.c_str(), guild_id, name);
|
||||
LogGuilds("Renamed guild [{}] ([{}]) to [{}] in database", info->name.c_str(), guild_id, name);
|
||||
|
||||
info->name = name; //update our local record.
|
||||
|
||||
@ -588,7 +588,7 @@ bool BaseGuildManager::DBRenameGuild(uint32 guild_id, const char* name) {
|
||||
|
||||
bool BaseGuildManager::DBSetGuildLeader(uint32 guild_id, uint32 leader) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to set the leader for guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to set the leader for guild [{}] when we have no database object", guild_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -614,7 +614,7 @@ bool BaseGuildManager::DBSetGuildLeader(uint32 guild_id, uint32 leader) {
|
||||
if(!DBSetGuildRank(leader, GUILD_LEADER))
|
||||
return false;
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Set guild leader for guild %d to %d in the database", guild_id, leader);
|
||||
LogGuilds("Set guild leader for guild [{}] to [{}] in the database", guild_id, leader);
|
||||
|
||||
info->leader_char_id = leader; //update our local record.
|
||||
|
||||
@ -623,7 +623,7 @@ bool BaseGuildManager::DBSetGuildLeader(uint32 guild_id, uint32 leader) {
|
||||
|
||||
bool BaseGuildManager::DBSetGuildMOTD(uint32 guild_id, const char* motd, const char *setter) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to set the MOTD for guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to set the MOTD for guild [{}] when we have no database object", guild_id);
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -654,7 +654,7 @@ bool BaseGuildManager::DBSetGuildMOTD(uint32 guild_id, const char* motd, const c
|
||||
safe_delete_array(esc);
|
||||
safe_delete_array(esc_set);
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Set MOTD for guild %d in the database", guild_id);
|
||||
LogGuilds("Set MOTD for guild [{}] in the database", guild_id);
|
||||
|
||||
info->motd = motd; //update our local record.
|
||||
info->motd_setter = setter; //update our local record.
|
||||
@ -688,7 +688,7 @@ bool BaseGuildManager::DBSetGuildURL(uint32 GuildID, const char* URL)
|
||||
}
|
||||
safe_delete_array(esc);
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Set URL for guild %d in the database", GuildID);
|
||||
LogGuilds("Set URL for guild [{}] in the database", GuildID);
|
||||
|
||||
info->url = URL; //update our local record.
|
||||
|
||||
@ -722,7 +722,7 @@ bool BaseGuildManager::DBSetGuildChannel(uint32 GuildID, const char* Channel)
|
||||
}
|
||||
safe_delete_array(esc);
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Set Channel for guild %d in the database", GuildID);
|
||||
LogGuilds("Set Channel for guild [{}] in the database", GuildID);
|
||||
|
||||
info->channel = Channel; //update our local record.
|
||||
|
||||
@ -731,7 +731,7 @@ bool BaseGuildManager::DBSetGuildChannel(uint32 GuildID, const char* Channel)
|
||||
|
||||
bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested to set char to guild %d when we have no database object.", guild_id);
|
||||
LogGuilds("Requested to set char to guild [{}] when we have no database object", guild_id);
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -753,7 +753,7 @@ bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Log(Logs::Detail, Logs::Guilds, "Set char %d to guild %d and rank %d in the database.", charid, guild_id, rank);
|
||||
LogGuilds("Set char [{}] to guild [{}] and rank [{}] in the database", charid, guild_id, rank);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -845,7 +845,7 @@ bool BaseGuildManager::DBSetPublicNote(uint32 charid, const char* note) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Set public not for char %d", charid);
|
||||
LogGuilds("Set public not for char [{}]", charid);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -924,14 +924,14 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vector<CharGuildInfo
|
||||
members.push_back(ci);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Retreived entire guild member list for guild %d from the database", guild_id);
|
||||
LogGuilds("Retreived entire guild member list for guild [{}] from the database", guild_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested char info on %s when we have no database object.", char_name);
|
||||
LogGuilds("Requested char info on [{}] when we have no database object", char_name);
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -953,7 +953,7 @@ bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) {
|
||||
|
||||
auto row = results.begin();
|
||||
ProcessGuildMember(row, into);
|
||||
Log(Logs::Detail, Logs::Guilds, "Retreived guild member info for char %s from the database", char_name);
|
||||
LogGuilds("Retreived guild member info for char [{}] from the database", char_name);
|
||||
|
||||
return true;
|
||||
|
||||
@ -962,7 +962,7 @@ bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) {
|
||||
|
||||
bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
|
||||
if(m_db == nullptr) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Requested char info on %d when we have no database object.", char_id);
|
||||
LogGuilds("Requested char info on [{}] when we have no database object", char_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -983,7 +983,7 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
|
||||
|
||||
auto row = results.begin();
|
||||
ProcessGuildMember(row, into);
|
||||
Log(Logs::Detail, Logs::Guilds, "Retreived guild member info for char %d", char_id);
|
||||
LogGuilds("Retreived guild member info for char [{}]", char_id);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1098,16 +1098,16 @@ bool BaseGuildManager::GuildExists(uint32 guild_id) const {
|
||||
|
||||
bool BaseGuildManager::IsGuildLeader(uint32 guild_id, uint32 char_id) const {
|
||||
if(guild_id == GUILD_NONE) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Check leader for char %d: not a guild.", char_id);
|
||||
LogGuilds("Check leader for char [{}]: not a guild", char_id);
|
||||
return(false);
|
||||
}
|
||||
std::map<uint32, GuildInfo *>::const_iterator res;
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Check leader for char %d: invalid guild.", char_id);
|
||||
LogGuilds("Check leader for char [{}]: invalid guild", char_id);
|
||||
return(false); //invalid guild
|
||||
}
|
||||
Log(Logs::Detail, Logs::Guilds, "Check leader for guild %d, char %d: leader id=%d", guild_id, char_id, res->second->leader_char_id);
|
||||
LogGuilds("Check leader for guild [{}], char [{}]: leader id=[{}]", guild_id, char_id, res->second->leader_char_id);
|
||||
return(char_id == res->second->leader_char_id);
|
||||
}
|
||||
|
||||
@ -1137,20 +1137,20 @@ uint8 BaseGuildManager::GetDisplayedRank(uint32 guild_id, uint8 rank, uint32 cha
|
||||
|
||||
bool BaseGuildManager::CheckGMStatus(uint32 guild_id, uint8 status) const {
|
||||
if(status >= 250) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Check permission on guild %d with user status %d > 250, granted.", guild_id, status);
|
||||
LogGuilds("Check permission on guild [{}] with user status [{}] > 250, granted", guild_id, status);
|
||||
return(true); //250+ as allowed anything
|
||||
}
|
||||
|
||||
std::map<uint32, GuildInfo *>::const_iterator res;
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Check permission on guild %d with user status %d, no such guild, denied.", guild_id, status);
|
||||
LogGuilds("Check permission on guild [{}] with user status [{}], no such guild, denied", guild_id, status);
|
||||
return(false); //invalid guild
|
||||
}
|
||||
|
||||
bool granted = (res->second->minstatus <= status);
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Check permission on guild %s (%d) with user status %d. Min status %d: %s",
|
||||
LogGuilds("Check permission on guild [{}] ([{}]) with user status [{}]. Min status [{}]: [{}]",
|
||||
res->second->name.c_str(), guild_id, status, res->second->minstatus, granted?"granted":"denied");
|
||||
|
||||
return(granted);
|
||||
@ -1158,21 +1158,21 @@ bool BaseGuildManager::CheckGMStatus(uint32 guild_id, uint8 status) const {
|
||||
|
||||
bool BaseGuildManager::CheckPermission(uint32 guild_id, uint8 rank, GuildAction act) const {
|
||||
if(rank > GUILD_MAX_RANK) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Check permission on guild %d and rank %d for action %s (%d): Invalid rank, denied.",
|
||||
LogGuilds("Check permission on guild [{}] and rank [{}] for action [{}] ([{}]): Invalid rank, denied",
|
||||
guild_id, rank, GuildActionNames[act], act);
|
||||
return(false); //invalid rank
|
||||
}
|
||||
std::map<uint32, GuildInfo *>::const_iterator res;
|
||||
res = m_guilds.find(guild_id);
|
||||
if(res == m_guilds.end()) {
|
||||
Log(Logs::Detail, Logs::Guilds, "Check permission on guild %d and rank %d for action %s (%d): Invalid guild, denied.",
|
||||
LogGuilds("Check permission on guild [{}] and rank [{}] for action [{}] ([{}]): Invalid guild, denied",
|
||||
guild_id, rank, GuildActionNames[act], act);
|
||||
return(false); //invalid guild
|
||||
}
|
||||
|
||||
bool granted = res->second->ranks[rank].permissions[act];
|
||||
|
||||
Log(Logs::Detail, Logs::Guilds, "Check permission on guild %s (%d) and rank %s (%d) for action %s (%d): %s",
|
||||
LogGuilds("Check permission on guild [{}] ([{}]) and rank [{}] ([{}]) for action [{}] ([{}]): [{}]",
|
||||
res->second->name.c_str(), guild_id,
|
||||
res->second->ranks[rank].name.c_str(), rank,
|
||||
GuildActionNames[act], act,
|
||||
|
||||
2694
common/http/httplib.h
Normal file
2694
common/http/httplib.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1381,7 +1381,7 @@ int16 EQEmu::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
|
||||
}
|
||||
|
||||
if (result == INVALID_INDEX) {
|
||||
Log(Logs::General, Logs::Error, "InventoryProfile::_PutItem: Invalid slot_id specified (%i) with parent slot id (%i)", slot_id, parentSlot);
|
||||
LogError("InventoryProfile::_PutItem: Invalid slot_id specified ({}) with parent slot id ({})", slot_id, parentSlot);
|
||||
InventoryProfile::MarkDirty(inst); // Slot not found, clean up
|
||||
}
|
||||
|
||||
|
||||
72
common/ip_util.cpp
Normal file
72
common/ip_util.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ip_util.h"
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
uint32_t IpUtil::IPToUInt(const std::string &ip)
|
||||
{
|
||||
int a, b, c, d;
|
||||
uint32_t addr = 0;
|
||||
|
||||
if (sscanf(ip.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d) != 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr = a << 24;
|
||||
addr |= b << 16;
|
||||
addr |= c << 8;
|
||||
addr |= d;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @param network
|
||||
* @param mask
|
||||
* @return
|
||||
*/
|
||||
bool IpUtil::IsIpInRange(const std::string &ip, const std::string &network, const std::string &mask)
|
||||
{
|
||||
uint32_t ip_addr = IpUtil::IPToUInt(ip);
|
||||
uint32_t network_addr = IpUtil::IPToUInt(network);
|
||||
uint32_t mask_addr = IpUtil::IPToUInt(mask);
|
||||
|
||||
uint32_t net_lower = (network_addr & mask_addr);
|
||||
uint32_t net_upper = (net_lower | (~mask_addr));
|
||||
|
||||
return ip_addr >= net_lower && ip_addr <= net_upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
|
||||
{
|
||||
return (
|
||||
IpUtil::IsIpInRange(ip, "10.0.0.0", "255.0.0.0") ||
|
||||
IpUtil::IsIpInRange(ip, "172.16.0.0", "255.240.0.0") ||
|
||||
IpUtil::IsIpInRange(ip, "192.168.0.0", "255.255.0.0")
|
||||
);
|
||||
}
|
||||
@ -16,15 +16,21 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef EQEMU_IP_UTIL_H
|
||||
#define EQEMU_IP_UTIL_H
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "types.h"
|
||||
#include "iostream"
|
||||
|
||||
template <typename... Args>
|
||||
void OutF(EQEmuLogSys &ls, Logs::DebugLevel debug_level, uint16 log_category, const char *fmt, const Args&... args)
|
||||
{
|
||||
std::string log_str = fmt::format(fmt, args...);
|
||||
ls.Out(debug_level, log_category, log_str);
|
||||
}
|
||||
class IpUtil {
|
||||
public:
|
||||
|
||||
static uint32_t IPToUInt(const std::string &ip);
|
||||
static bool IsIpInRange(const std::string &ip, const std::string &network, const std::string &mask);
|
||||
static bool IsIpInPrivateRfc1918(const std::string &ip);
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_IP_UTIL_H
|
||||
@ -1,26 +1,29 @@
|
||||
#include "json_config.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
EQ::JsonConfigFile::JsonConfigFile()
|
||||
{
|
||||
}
|
||||
EQ::JsonConfigFile::JsonConfigFile() = default;
|
||||
|
||||
EQ::JsonConfigFile::JsonConfigFile(const Json::Value &value)
|
||||
{
|
||||
m_root = value;
|
||||
}
|
||||
|
||||
EQ::JsonConfigFile::~JsonConfigFile()
|
||||
{
|
||||
}
|
||||
EQ::JsonConfigFile::~JsonConfigFile() = default;
|
||||
|
||||
EQ::JsonConfigFile EQ::JsonConfigFile::Load(const std::string &filename)
|
||||
/**
|
||||
* @param file_name
|
||||
* @return
|
||||
*/
|
||||
EQ::JsonConfigFile EQ::JsonConfigFile::Load(
|
||||
const std::string &file_name
|
||||
)
|
||||
{
|
||||
JsonConfigFile ret;
|
||||
ret.m_root = Json::Value();
|
||||
|
||||
std::ifstream ifs;
|
||||
ifs.open(filename, std::ifstream::in);
|
||||
ifs.open(file_name, std::ifstream::in);
|
||||
|
||||
if (!ifs.good()) {
|
||||
return ret;
|
||||
@ -36,7 +39,43 @@ EQ::JsonConfigFile EQ::JsonConfigFile::Load(const std::string &filename)
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string EQ::JsonConfigFile::GetVariableString(const std::string &title, const std::string ¶meter, const std::string &default_value) {
|
||||
/**
|
||||
* @param file_name
|
||||
* @return
|
||||
*/
|
||||
void EQ::JsonConfigFile::Save(
|
||||
const std::string &file_name
|
||||
)
|
||||
{
|
||||
std::ofstream opened_config_file;
|
||||
opened_config_file.open(file_name);
|
||||
|
||||
/**
|
||||
* Grab and build config contents
|
||||
*/
|
||||
Json::StreamWriterBuilder write_builder;
|
||||
write_builder["indentation"] = " ";
|
||||
std::string document = Json::writeString(write_builder, m_root);
|
||||
|
||||
/**
|
||||
* Write current contents and close
|
||||
*/
|
||||
opened_config_file << document;
|
||||
opened_config_file.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title
|
||||
* @param parameter
|
||||
* @param default_value
|
||||
* @return
|
||||
*/
|
||||
std::string EQ::JsonConfigFile::GetVariableString(
|
||||
const std::string &title,
|
||||
const std::string ¶meter,
|
||||
const std::string &default_value
|
||||
)
|
||||
{
|
||||
try {
|
||||
if (m_root.isMember(title) && m_root[title].isMember(parameter)) {
|
||||
return m_root[title][parameter].asString();
|
||||
@ -49,7 +88,18 @@ std::string EQ::JsonConfigFile::GetVariableString(const std::string &title, cons
|
||||
return default_value;
|
||||
}
|
||||
|
||||
int EQ::JsonConfigFile::GetVariableInt(const std::string &title, const std::string ¶meter, const int default_value) {
|
||||
/**
|
||||
* @param title
|
||||
* @param parameter
|
||||
* @param default_value
|
||||
* @return
|
||||
*/
|
||||
int EQ::JsonConfigFile::GetVariableInt(
|
||||
const std::string &title,
|
||||
const std::string ¶meter,
|
||||
const int default_value
|
||||
)
|
||||
{
|
||||
try {
|
||||
if (m_root.isMember(title) && m_root[title].isMember(parameter)) {
|
||||
return m_root[title][parameter].asInt();
|
||||
@ -62,7 +112,18 @@ int EQ::JsonConfigFile::GetVariableInt(const std::string &title, const std::stri
|
||||
return default_value;
|
||||
}
|
||||
|
||||
bool EQ::JsonConfigFile::GetVariableBool(const std::string &title, const std::string ¶meter, const bool default_value) {
|
||||
/**
|
||||
* @param title
|
||||
* @param parameter
|
||||
* @param default_value
|
||||
* @return
|
||||
*/
|
||||
bool EQ::JsonConfigFile::GetVariableBool(
|
||||
const std::string &title,
|
||||
const std::string ¶meter,
|
||||
const bool default_value
|
||||
)
|
||||
{
|
||||
try {
|
||||
if (m_root.isMember(title) && m_root[title].isMember(parameter)) {
|
||||
return m_root[title][parameter].asBool();
|
||||
@ -75,7 +136,18 @@ bool EQ::JsonConfigFile::GetVariableBool(const std::string &title, const std::st
|
||||
return default_value;
|
||||
}
|
||||
|
||||
double EQ::JsonConfigFile::GetVariableDouble(const std::string &title, const std::string ¶meter, const double default_value) {
|
||||
/**
|
||||
* @param title
|
||||
* @param parameter
|
||||
* @param default_value
|
||||
* @return
|
||||
*/
|
||||
double EQ::JsonConfigFile::GetVariableDouble(
|
||||
const std::string &title,
|
||||
const std::string ¶meter,
|
||||
const double default_value
|
||||
)
|
||||
{
|
||||
try {
|
||||
if (m_root.isMember(title) && m_root[title].isMember(parameter)) {
|
||||
return m_root[title][parameter].asDouble();
|
||||
|
||||
@ -7,10 +7,12 @@ namespace EQ
|
||||
class JsonConfigFile
|
||||
{
|
||||
public:
|
||||
JsonConfigFile();
|
||||
JsonConfigFile(const Json::Value &value);
|
||||
~JsonConfigFile();
|
||||
|
||||
static JsonConfigFile Load(const std::string &filename);
|
||||
static JsonConfigFile Load(const std::string &file_name);
|
||||
void Save(const std::string &file_name);
|
||||
|
||||
std::string GetVariableString(const std::string &title, const std::string ¶meter, const std::string &default_value);
|
||||
int GetVariableInt(const std::string &title, const std::string ¶meter, const int default_value);
|
||||
@ -19,7 +21,6 @@ namespace EQ
|
||||
|
||||
Json::Value& RawHandle() { return m_root; }
|
||||
private:
|
||||
JsonConfigFile();
|
||||
Json::Value m_root;
|
||||
};
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
#define VERIFY_PACKET_LENGTH(OPCode, Packet, StructName) \
|
||||
if(Packet->size != sizeof(StructName)) \
|
||||
{ \
|
||||
Log(Logs::Detail, Logs::Netcode, "Size mismatch in " #OPCode " expected %i got %i", sizeof(StructName), Packet->size); \
|
||||
LogNetcode("Size mismatch in " #OPCode " expected [{}] got [{}]", sizeof(StructName), Packet->size); \
|
||||
DumpPacket(Packet); \
|
||||
return; \
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "eqstream.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../eqemu_logsys_fmt.h"
|
||||
|
||||
EQ::Net::EQStreamManager::EQStreamManager(const EQStreamManagerInterfaceOptions &options) : EQStreamManagerInterface(options), m_daybreak(options.daybreak_options)
|
||||
{
|
||||
@ -185,23 +184,23 @@ EQStreamInterface::MatchState EQ::Net::EQStream::CheckSignature(const Signature
|
||||
|
||||
if (opcode == sig->first_eq_opcode) {
|
||||
if (length == sig->first_length) {
|
||||
LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} and length matched {3}",
|
||||
LogF(Logs::General, Logs::Netcode, "[StreamIdentify] {0}:{1}: First opcode matched {2:#x} and length matched {3}",
|
||||
m_connection->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length);
|
||||
return MatchSuccessful;
|
||||
}
|
||||
else if (length == 0) {
|
||||
LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} and length is ignored.",
|
||||
LogF(Logs::General, Logs::Netcode, "[StreamIdentify] {0}:{1}: First opcode matched {2:#x} and length is ignored.",
|
||||
m_connection->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode);
|
||||
return MatchSuccessful;
|
||||
}
|
||||
else {
|
||||
LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode matched {2:#x} but length {3} did not match expected {4}",
|
||||
LogF(Logs::General, Logs::Netcode, "[StreamIdentify] {0}:{1}: First opcode matched {2:#x} but length {3} did not match expected {4}",
|
||||
m_connection->RemoteEndpoint(), m_connection->RemotePort(), sig->first_eq_opcode, length, sig->first_length);
|
||||
return MatchFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogF(Logs::General, Logs::Netcode, "[IDENT_TRACE] {0}:{1}: First opcode {1:#x} did not match expected {2:#x}",
|
||||
LogF(Logs::General, Logs::Netcode, "[StreamIdentify] {0}:{1}: First opcode {1:#x} did not match expected {2:#x}",
|
||||
m_connection->RemoteEndpoint(), m_connection->RemotePort(), opcode, sig->first_eq_opcode);
|
||||
return MatchFailed;
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "servertalk_client_connection.h"
|
||||
#include "dns.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../eqemu_logsys_fmt.h"
|
||||
|
||||
EQ::Net::ServertalkClient::ServertalkClient(const std::string &addr, int port, bool ipv6, const std::string &identifier, const std::string &credentials)
|
||||
: m_timer(std::unique_ptr<EQ::Timer>(new EQ::Timer(100, true, std::bind(&EQ::Net::ServertalkClient::Connect, this))))
|
||||
@ -79,15 +78,15 @@ void EQ::Net::ServertalkClient::Connect()
|
||||
m_connecting = true;
|
||||
EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
if (connection == nullptr) {
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
LogF(Logs::General, Logs::TCPConnection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connecting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Connected to {0}:{1}", m_addr, m_port);
|
||||
LogF(Logs::General, Logs::TCPConnection, "Connected to {0}:{1}", m_addr, m_port);
|
||||
m_connection = connection;
|
||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_encrypted = false;
|
||||
m_connection.reset();
|
||||
});
|
||||
@ -214,7 +213,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
LogError("Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -226,7 +225,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
LogError("Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
@ -253,7 +252,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
|
||||
LogError("Error parsing hello from server: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
|
||||
if (m_on_connect_cb) {
|
||||
@ -276,7 +275,7 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Error decrypting message from server");
|
||||
LogError("Error decrypting message from server");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
@ -324,7 +323,7 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing message from server: {0}", ex.what());
|
||||
LogError("Error parsing message from server: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "servertalk_legacy_client_connection.h"
|
||||
#include "dns.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../eqemu_logsys_fmt.h"
|
||||
|
||||
EQ::Net::ServertalkLegacyClient::ServertalkLegacyClient(const std::string &addr, int port, bool ipv6)
|
||||
: m_timer(std::unique_ptr<EQ::Timer>(new EQ::Timer(100, true, std::bind(&EQ::Net::ServertalkLegacyClient::Connect, this))))
|
||||
@ -59,15 +58,15 @@ void EQ::Net::ServertalkLegacyClient::Connect()
|
||||
m_connecting = true;
|
||||
EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
|
||||
if (connection == nullptr) {
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
LogF(Logs::General, Logs::TCPConnection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connecting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Connected to {0}:{1}", m_addr, m_port);
|
||||
LogF(Logs::General, Logs::TCPConnection, "Connected to {0}:{1}", m_addr, m_port);
|
||||
m_connection = connection;
|
||||
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
|
||||
m_connection.reset();
|
||||
});
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "servertalk_server_connection.h"
|
||||
#include "servertalk_server.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
#include "../eqemu_logsys_fmt.h"
|
||||
#include "../util/uuid.h"
|
||||
|
||||
EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<EQ::Net::TCPConnection> c, EQ::Net::ServertalkServer *parent, bool encrypted, bool allow_downgrade)
|
||||
@ -202,8 +201,8 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
{
|
||||
#ifdef ENABLE_SECURITY
|
||||
if (downgrade_security && m_allow_downgrade && m_encrypted) {
|
||||
LogF(Logs::General, Logs::TCP_Connection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
||||
LogF(Logs::General, Logs::TCPConnection, "Downgraded encrypted connection to plaintext because otherside didn't support encryption {0}:{1}",
|
||||
m_connection->RemoteIP(), m_connection->RemotePort());
|
||||
m_encrypted = false;
|
||||
}
|
||||
|
||||
@ -221,7 +220,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
|
||||
LogError("Error decrypting handshake from client, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
@ -230,7 +229,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
@ -240,7 +239,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
@ -250,7 +249,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
@ -258,7 +257,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
m_parent->ConnectionIdentified(this);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
}
|
||||
@ -268,7 +267,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
auto credentials = p.GetCString(m_identifier.length() + 1);
|
||||
|
||||
if (!m_parent->CheckCredentials(credentials)) {
|
||||
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
|
||||
m_connection->Disconnect();
|
||||
return;
|
||||
}
|
||||
@ -276,7 +275,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
|
||||
m_parent->ConnectionIdentified(this);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
|
||||
LogError("Error parsing handshake from client: {0}", ex.what());
|
||||
m_connection->Disconnect();
|
||||
}
|
||||
#endif
|
||||
@ -296,7 +295,7 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
|
||||
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Error decrypting message from client");
|
||||
LogError("Error decrypting message from client");
|
||||
(*(uint64_t*)&m_nonce_theirs[0])++;
|
||||
return;
|
||||
}
|
||||
@ -344,6 +343,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
LogF(Logs::General, Logs::Error, "Error parsing message from client: {0}", ex.what());
|
||||
LogError("Error parsing message from client: {0}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ OpcodeManager::OpcodeManager() {
|
||||
bool OpcodeManager::LoadOpcodesFile(const char *filename, OpcodeSetStrategy *s, bool report_errors) {
|
||||
FILE *opf = fopen(filename, "r");
|
||||
if(opf == nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Unable to open opcodes file '%s'", filename);
|
||||
LogError("Unable to open opcodes file [{}]", filename);
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ namespace RoF
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -108,7 +108,7 @@ namespace RoF
|
||||
signature.first_length = sizeof(structs::ClientZoneEntry_Struct);
|
||||
signature.first_eq_opcode = opcodes->EmuToEQ(OP_ZoneEntry);
|
||||
into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy);
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
LogNetcode("[StreamIdentify] Registered patch [{}]", name);
|
||||
}
|
||||
|
||||
void Reload()
|
||||
@ -125,10 +125,10 @@ namespace RoF
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Reloaded opcodes for patch %s", name);
|
||||
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +350,7 @@ namespace RoF
|
||||
|
||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -589,7 +589,7 @@ namespace RoF
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0, ItemPacketCharInventory);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "RoF::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
LogNetcode("RoF::ENCODE(OP_CharInventory) Serialization failed on item slot [{}] during OP_CharInventory. Item skipped", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -1521,7 +1521,7 @@ namespace RoF
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0, old_item_pkt->PacketType);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "RoF::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
LogNetcode("RoF::ENCODE(OP_ItemPacket) Serialization failed on item slot [{}]", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2602,7 +2602,7 @@ namespace RoF
|
||||
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Player Profile Packet is %i bytes", outapp->GetWritePosition());
|
||||
LogNetcode("[STRUCTS] Player Profile Packet is [{}] bytes", outapp->GetWritePosition());
|
||||
|
||||
auto NewBuffer = new unsigned char[outapp->GetWritePosition()];
|
||||
memcpy(NewBuffer, outapp->pBuffer, outapp->GetWritePosition());
|
||||
@ -3453,7 +3453,7 @@ namespace RoF
|
||||
|
||||
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -3804,7 +3804,7 @@ namespace RoF
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(Spawn_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -4052,7 +4052,7 @@ namespace RoF
|
||||
Buffer += 29;
|
||||
if (Buffer != (BufferStart + PacketSize))
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[ERROR] SPAWN ENCODE LOGIC PROBLEM: Buffer pointer is now %i from end", Buffer - (BufferStart + PacketSize));
|
||||
LogNetcode("[ERROR] SPAWN ENCODE LOGIC PROBLEM: Buffer pointer is now [{}] from end", Buffer - (BufferStart + PacketSize));
|
||||
}
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending zone spawn for %s packet is %i bytes", emu->name, outapp->size);
|
||||
//Log.Hex(Logs::Netcode, outapp->pBuffer, outapp->size);
|
||||
@ -4621,7 +4621,7 @@ namespace RoF
|
||||
return;
|
||||
}
|
||||
default:
|
||||
Log(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action");
|
||||
LogNetcode("Unhandled OP_GuildBank action");
|
||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */
|
||||
return;
|
||||
}
|
||||
@ -5678,7 +5678,7 @@ namespace RoF
|
||||
RoFSlot = server_corpse_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to RoF Corpse Main Slot %i", server_corpse_slot, RoFSlot);
|
||||
LogNetcode("Convert Server Corpse Slot [{}] to RoF Corpse Main Slot [{}]", server_corpse_slot, RoFSlot);
|
||||
|
||||
return RoFSlot;
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ namespace RoF2
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,7 @@ namespace RoF2
|
||||
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
LogNetcode("[StreamIdentify] Registered patch [{}]", name);
|
||||
}
|
||||
|
||||
void Reload()
|
||||
@ -128,10 +128,10 @@ namespace RoF2
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Reloaded opcodes for patch %s", name);
|
||||
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ namespace RoF2
|
||||
|
||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -657,7 +657,7 @@ namespace RoF2
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0, ItemPacketCharInventory);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "RoF2::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
LogNetcode("RoF2::ENCODE(OP_CharInventory) Serialization failed on item slot [{}] during OP_CharInventory. Item skipped", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -1589,7 +1589,7 @@ namespace RoF2
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0, old_item_pkt->PacketType);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "RoF2::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
LogNetcode("RoF2::ENCODE(OP_ItemPacket) Serialization failed on item slot [{}]", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2688,7 +2688,7 @@ namespace RoF2
|
||||
// Think we need 1 byte of padding at the end
|
||||
outapp->WriteUInt8(0); // Unknown
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Player Profile Packet is %i bytes", outapp->GetWritePosition());
|
||||
LogNetcode("[STRUCTS] Player Profile Packet is [{}] bytes", outapp->GetWritePosition());
|
||||
|
||||
auto NewBuffer = new unsigned char[outapp->GetWritePosition()];
|
||||
memcpy(NewBuffer, outapp->pBuffer, outapp->GetWritePosition());
|
||||
@ -3520,7 +3520,7 @@ namespace RoF2
|
||||
|
||||
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -3630,7 +3630,7 @@ namespace RoF2
|
||||
|
||||
OUT(TraderID);
|
||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||
Log(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderDelItem): TraderID %d, SerialNumber: %d", emu->TraderID, emu->ItemID);
|
||||
LogTrading("ENCODE(OP_TraderDelItem): TraderID [{}], SerialNumber: [{}]", emu->TraderID, emu->ItemID);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -3661,7 +3661,7 @@ namespace RoF2
|
||||
eq->Traders2 = emu->Traders;
|
||||
eq->Items2 = emu->Items;
|
||||
|
||||
Log(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): BazaarWelcome_Struct Code %d, Traders %d, Items %d",
|
||||
LogTrading("ENCODE(OP_TraderShop): BazaarWelcome_Struct Code [{}], Traders [{}], Items [{}]",
|
||||
eq->Code, eq->Traders, eq->Items);
|
||||
|
||||
FINISH_ENCODE();
|
||||
@ -3684,14 +3684,14 @@ namespace RoF2
|
||||
OUT(Quantity);
|
||||
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||
|
||||
Log(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||
LogTrading("ENCODE(OP_TraderShop): Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, emu->ItemName);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Encode Size Unknown (%d)", psize);
|
||||
LogTrading("ENCODE(OP_TraderShop): Encode Size Unknown ([{}])", psize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3946,7 +3946,7 @@ namespace RoF2
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(Spawn_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -4278,7 +4278,7 @@ namespace RoF2
|
||||
Buffer += 29;
|
||||
if (Buffer != (BufferStart + PacketSize))
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[ERROR] SPAWN ENCODE LOGIC PROBLEM: Buffer pointer is now %i from end", Buffer - (BufferStart + PacketSize));
|
||||
LogNetcode("[ERROR] SPAWN ENCODE LOGIC PROBLEM: Buffer pointer is now [{}] from end", Buffer - (BufferStart + PacketSize));
|
||||
}
|
||||
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending zone spawn for %s packet is %i bytes", emu->name, outapp->size);
|
||||
//Log.Hex(Logs::Netcode, outapp->pBuffer, outapp->size);
|
||||
@ -4859,7 +4859,7 @@ namespace RoF2
|
||||
return;
|
||||
}
|
||||
default:
|
||||
Log(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action");
|
||||
LogNetcode("Unhandled OP_GuildBank action");
|
||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */
|
||||
return;
|
||||
}
|
||||
@ -5012,7 +5012,7 @@ namespace RoF2
|
||||
emu->to_slot = RoF2ToServerSlot(eq->to_slot);
|
||||
IN(number_in_stack);
|
||||
|
||||
//Log(Logs::General, Logs::Netcode, "[RoF2] MoveItem Slot from %u to %u, Number %u", emu->from_slot, emu->to_slot, emu->number_in_stack);
|
||||
//LogNetcode("[RoF2] MoveItem Slot from [{}] to [{}], Number [{}]", emu->from_slot, emu->to_slot, emu->number_in_stack);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
@ -5245,7 +5245,7 @@ namespace RoF2
|
||||
IN(Code);
|
||||
IN(TraderID);
|
||||
IN(Approval);
|
||||
Log(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderClick_Struct Code %d, TraderID %d, Approval %d",
|
||||
LogTrading("DECODE(OP_TraderShop): TraderClick_Struct Code [{}], TraderID [{}], Approval [{}]",
|
||||
eq->Code, eq->TraderID, eq->Approval);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
@ -5259,7 +5259,7 @@ namespace RoF2
|
||||
emu->Beginning.Action = eq->Code;
|
||||
IN(Traders);
|
||||
IN(Items);
|
||||
Log(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): BazaarWelcome_Struct Code %d, Traders %d, Items %d",
|
||||
LogTrading("DECODE(OP_TraderShop): BazaarWelcome_Struct Code [{}], Traders [{}], Items [{}]",
|
||||
eq->Code, eq->Traders, eq->Items);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
@ -5276,20 +5276,20 @@ namespace RoF2
|
||||
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||
IN(ItemID);
|
||||
IN(Quantity);
|
||||
Log(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d",
|
||||
LogTrading("DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 [{}], Unknown008 [{}], Unknown012 [{}], Unknown076 [{}], Unknown276 [{}]",
|
||||
eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276);
|
||||
Log(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||
LogTrading("DECODE(OP_TraderShop): TraderBuy_Struct Buy Action [{}], Price [{}], Trader [{}], ItemID [{}], Quantity [{}], ItemName, [{}]",
|
||||
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
else if (psize == 4)
|
||||
{
|
||||
Log(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Forwarding packet as-is with size 4");
|
||||
LogTrading("DECODE(OP_TraderShop): Forwarding packet as-is with size 4");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Unknown (%d)", psize);
|
||||
LogTrading("DECODE(OP_TraderShop): Decode Size Unknown ([{}])", psize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5966,7 +5966,7 @@ namespace RoF2
|
||||
RoF2Slot = server_corpse_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to RoF2 Corpse Main Slot %i", server_corpse_slot, RoF2Slot);
|
||||
LogNetcode("Convert Server Corpse Slot [{}] to RoF2 Corpse Main Slot [{}]", server_corpse_slot, RoF2Slot);
|
||||
|
||||
return RoF2Slot;
|
||||
}
|
||||
@ -6149,7 +6149,7 @@ namespace RoF2
|
||||
ServerSlot = rof2_corpse_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert RoF2 Corpse Main Slot %i to Server Corpse Slot %i", rof2_corpse_slot, ServerSlot);
|
||||
LogNetcode("Convert RoF2 Corpse Main Slot [{}] to Server Corpse Slot [{}]", rof2_corpse_slot, ServerSlot);
|
||||
|
||||
return ServerSlot;
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ namespace SoD
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -105,7 +105,7 @@ namespace SoD
|
||||
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
LogNetcode("[StreamIdentify] Registered patch [{}]", name);
|
||||
}
|
||||
|
||||
void Reload()
|
||||
@ -122,10 +122,10 @@ namespace SoD
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Reloaded opcodes for patch %s", name);
|
||||
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ namespace SoD
|
||||
|
||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -400,7 +400,7 @@ namespace SoD
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "SoD::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
LogNetcode("SoD::ENCODE(OP_CharInventory) Serialization failed on item slot [{}] during OP_CharInventory. Item skipped", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -1069,7 +1069,7 @@ namespace SoD
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "SoD::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
LogNetcode("SoD::ENCODE(OP_ItemPacket) Serialization failed on item slot [{}]", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2198,7 +2198,7 @@ namespace SoD
|
||||
|
||||
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2435,7 +2435,7 @@ namespace SoD
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(Spawn_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -3848,7 +3848,7 @@ namespace SoD
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to SoD Slot %i", serverSlot, SoDSlot);
|
||||
LogNetcode("Convert Server Slot [{}] to SoD Slot [{}]", serverSlot, SoDSlot);
|
||||
|
||||
return SoDSlot;
|
||||
}
|
||||
@ -3865,7 +3865,7 @@ namespace SoD
|
||||
SoDSlot = server_corpse_slot - 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to SoD Corpse Slot %i", server_corpse_slot, SoDSlot);
|
||||
LogNetcode("Convert Server Corpse Slot [{}] to SoD Corpse Slot [{}]", server_corpse_slot, SoDSlot);
|
||||
|
||||
return SoDSlot;
|
||||
}
|
||||
@ -3930,7 +3930,7 @@ namespace SoD
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert SoD Slot %i to Server Slot %i", sod_slot, server_slot);
|
||||
LogNetcode("Convert SoD Slot [{}] to Server Slot [{}]", sod_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
@ -3947,7 +3947,7 @@ namespace SoD
|
||||
server_slot = sod_corpse_slot + 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert SoD Corpse Slot %i to Server Corpse Slot %i", sod_corpse_slot, server_slot);
|
||||
LogNetcode("Convert SoD Corpse Slot [{}] to Server Corpse Slot [{}]", sod_corpse_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ namespace SoF
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -103,7 +103,7 @@ namespace SoF
|
||||
signature.first_eq_opcode = opcodes->EmuToEQ(OP_ZoneEntry);
|
||||
into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy);
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
LogNetcode("[StreamIdentify] Registered patch [{}]", name);
|
||||
}
|
||||
|
||||
void Reload()
|
||||
@ -120,10 +120,10 @@ namespace SoF
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Reloaded opcodes for patch %s", name);
|
||||
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,7 +380,7 @@ namespace SoF
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "SoF::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
LogNetcode("SoF::ENCODE(OP_CharInventory) Serialization failed on item slot [{}] during OP_CharInventory. Item skipped", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -864,7 +864,7 @@ namespace SoF
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "SoF::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
LogNetcode("SoF::ENCODE(OP_ItemPacket) Serialization failed on item slot [{}]", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -1827,7 +1827,7 @@ namespace SoF
|
||||
|
||||
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -1989,7 +1989,7 @@ namespace SoF
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(Spawn_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -3244,7 +3244,7 @@ namespace SoF
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to SoF Slot %i", server_slot, sof_slot);
|
||||
LogNetcode("Convert Server Slot [{}] to SoF Slot [{}]", server_slot, sof_slot);
|
||||
|
||||
return sof_slot;
|
||||
}
|
||||
@ -3330,7 +3330,7 @@ namespace SoF
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert SoF Slot %i to Server Slot %i", sof_slot, server_slot);
|
||||
LogNetcode("Convert SoF Slot [{}] to Server Slot [{}]", sof_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
@ -87,14 +87,14 @@
|
||||
//check length of packet before decoding. Call before setup.
|
||||
#define ENCODE_LENGTH_EXACT(struct_) \
|
||||
if((*p)->size != sizeof(struct_)) { \
|
||||
Log(Logs::Detail, Logs::Netcode, "Wrong size on outbound %s (" #struct_ "): Got %d, expected %d", opcodes->EmuToName((*p)->GetOpcode()), (*p)->size, sizeof(struct_)); \
|
||||
LogNetcode("Wrong size on outbound [{}] (" #struct_ "): Got [{}], expected [{}]", opcodes->EmuToName((*p)->GetOpcode()), (*p)->size, sizeof(struct_)); \
|
||||
delete *p; \
|
||||
*p = nullptr; \
|
||||
return; \
|
||||
}
|
||||
#define ENCODE_LENGTH_ATLEAST(struct_) \
|
||||
if((*p)->size < sizeof(struct_)) { \
|
||||
Log(Logs::Detail, Logs::Netcode, "Wrong size on outbound %s (" #struct_ "): Got %d, expected at least %d", opcodes->EmuToName((*p)->GetOpcode()), (*p)->size, sizeof(struct_)); \
|
||||
LogNetcode("Wrong size on outbound [{}] (" #struct_ "): Got [{}], expected at least [{}]", opcodes->EmuToName((*p)->GetOpcode()), (*p)->size, sizeof(struct_)); \
|
||||
delete *p; \
|
||||
*p = nullptr; \
|
||||
return; \
|
||||
@ -153,13 +153,13 @@
|
||||
//check length of packet before decoding. Call before setup.
|
||||
#define DECODE_LENGTH_EXACT(struct_) \
|
||||
if(__packet->size != sizeof(struct_)) { \
|
||||
Log(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
||||
LogNetcode("Wrong size on incoming [{}] (" #struct_ "): Got [{}], expected [{}]", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \
|
||||
return; \
|
||||
}
|
||||
#define DECODE_LENGTH_ATLEAST(struct_) \
|
||||
if(__packet->size < sizeof(struct_)) { \
|
||||
Log(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected at least %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
||||
LogNetcode("Wrong size on incoming [{}] (" #struct_ "): Got [{}], expected at least [{}]", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \
|
||||
return; \
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ namespace Titanium
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -104,7 +104,7 @@ namespace Titanium
|
||||
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
LogNetcode("[StreamIdentify] Registered patch [{}]", name);
|
||||
}
|
||||
|
||||
void Reload()
|
||||
@ -121,10 +121,10 @@ namespace Titanium
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Reloaded opcodes for patch %s", name);
|
||||
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,7 +337,7 @@ namespace Titanium
|
||||
for (int r = 0; r < itemcount; r++, eq++) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, ServerToTitaniumSlot(eq->slot_id), 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "Titanium::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
LogNetcode("Titanium::ENCODE(OP_CharInventory) Serialization failed on item slot [{}] during OP_CharInventory. Item skipped", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -822,7 +822,7 @@ namespace Titanium
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, ServerToTitaniumSlot(int_struct->slot_id), 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "Titanium::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
LogNetcode("Titanium::ENCODE(OP_ItemPacket) Serialization failed on item slot [{}]", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -1510,7 +1510,7 @@ namespace Titanium
|
||||
|
||||
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -1628,7 +1628,7 @@ namespace Titanium
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(Spawn_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2540,7 +2540,7 @@ namespace Titanium
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to Titanium Slot %i", server_slot, titanium_slot);
|
||||
LogNetcode("Convert Server Slot [{}] to Titanium Slot [{}]", server_slot, titanium_slot);
|
||||
|
||||
return titanium_slot;
|
||||
}
|
||||
@ -2627,7 +2627,7 @@ namespace Titanium
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Titanium Slot %i to Server Slot %i", titanium_slot, server_slot);
|
||||
LogNetcode("Convert Titanium Slot [{}] to Server Slot [{}]", titanium_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
@ -2648,7 +2648,7 @@ namespace Titanium
|
||||
server_slot = titanium_corpse_slot + 4;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Titanium Corpse Slot %i to Server Corpse Slot %i", titanium_corpse_slot, server_slot);
|
||||
LogNetcode("Convert Titanium Corpse Slot [{}] to Server Corpse Slot [{}]", titanium_corpse_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ namespace UF
|
||||
//TODO: figure out how to support shared memory with multiple patches...
|
||||
opcodes = new RegularOpcodeManager();
|
||||
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -105,7 +105,7 @@ namespace UF
|
||||
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
LogNetcode("[StreamIdentify] Registered patch [{}]", name);
|
||||
}
|
||||
|
||||
void Reload()
|
||||
@ -122,10 +122,10 @@ namespace UF
|
||||
opfile += name;
|
||||
opfile += ".conf";
|
||||
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
||||
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
||||
return;
|
||||
}
|
||||
Log(Logs::General, Logs::Netcode, "[OPCODES] Reloaded opcodes for patch %s", name);
|
||||
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,7 +330,7 @@ namespace UF
|
||||
|
||||
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -520,7 +520,7 @@ namespace UF
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "UF::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
LogNetcode("UF::ENCODE(OP_CharInventory) Serialization failed on item slot [{}] during OP_CharInventory. Item skipped", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -1277,7 +1277,7 @@ namespace UF
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "UF::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
LogNetcode("UF::ENCODE(OP_ItemPacket) Serialization failed on item slot [{}]", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2472,7 +2472,7 @@ namespace UF
|
||||
|
||||
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -2704,7 +2704,7 @@ namespace UF
|
||||
//determine and verify length
|
||||
int entrycount = in->size / sizeof(Spawn_Struct);
|
||||
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -4206,7 +4206,7 @@ namespace UF
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to UF Slot %i", serverSlot, UFSlot);
|
||||
LogNetcode("Convert Server Slot [{}] to UF Slot [{}]", serverSlot, UFSlot);
|
||||
|
||||
return UFSlot;
|
||||
}
|
||||
@ -4223,7 +4223,7 @@ namespace UF
|
||||
UFSlot = serverCorpseSlot - 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to UF Corpse Slot %i", serverCorpseSlot, UFSlot);
|
||||
LogNetcode("Convert Server Corpse Slot [{}] to UF Corpse Slot [{}]", serverCorpseSlot, UFSlot);
|
||||
|
||||
return UFSlot;
|
||||
}
|
||||
@ -4288,7 +4288,7 @@ namespace UF
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert UF Slot %i to Server Slot %i", ufSlot, ServerSlot);
|
||||
LogNetcode("Convert UF Slot [{}] to Server Slot [{}]", ufSlot, ServerSlot);
|
||||
|
||||
return ServerSlot;
|
||||
}
|
||||
@ -4305,7 +4305,7 @@ namespace UF
|
||||
ServerSlot = ufCorpseSlot + 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert UF Corpse Slot %i to Server Corpse Slot %i", ufCorpseSlot, ServerSlot);
|
||||
LogNetcode("Convert UF Corpse Slot [{}] to Server Corpse Slot [{}]", ufCorpseSlot, ServerSlot);
|
||||
|
||||
return ServerSlot;
|
||||
}
|
||||
|
||||
@ -1,3 +1,23 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
EQEmuExePlatform exe_platform = ExePlatformNone;
|
||||
@ -10,6 +30,44 @@ const EQEmuExePlatform& GetExecutablePlatform() {
|
||||
return exe_platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
int GetExecutablePlatformInt(){
|
||||
return exe_platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns platform name by string
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetPlatformName()
|
||||
{
|
||||
switch (GetExecutablePlatformInt()) {
|
||||
case EQEmuExePlatform::ExePlatformWorld:
|
||||
return "WorldServer";
|
||||
case EQEmuExePlatform::ExePlatformQueryServ:
|
||||
return "QueryServer";
|
||||
case EQEmuExePlatform::ExePlatformZone:
|
||||
return "ZoneServer";
|
||||
case EQEmuExePlatform::ExePlatformUCS:
|
||||
return "UCS";
|
||||
case EQEmuExePlatform::ExePlatformLogin:
|
||||
return "LoginServer";
|
||||
case EQEmuExePlatform::ExePlatformSocket_Server:
|
||||
return "SocketServer";
|
||||
case EQEmuExePlatform::ExePlatformSharedMemory:
|
||||
return "SharedMemory";
|
||||
case EQEmuExePlatform::ExePlatformClientImport:
|
||||
return "ClientImport";
|
||||
case EQEmuExePlatform::ExePlatformClientExport:
|
||||
return "ClientExport";
|
||||
case EQEmuExePlatform::ExePlatformLaunch:
|
||||
return "Launch";
|
||||
case EQEmuExePlatform::ExePlatformHC:
|
||||
return "HC";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,28 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_PLATFORM_H
|
||||
#define EQEMU_PLATFORM_H
|
||||
|
||||
#include "iostream"
|
||||
|
||||
enum EQEmuExePlatform
|
||||
{
|
||||
ExePlatformNone = 0,
|
||||
@ -20,5 +42,6 @@ enum EQEmuExePlatform
|
||||
void RegisterExecutablePlatform(EQEmuExePlatform p);
|
||||
const EQEmuExePlatform& GetExecutablePlatform();
|
||||
int GetExecutablePlatformInt();
|
||||
std::string GetPlatformName();
|
||||
|
||||
#endif
|
||||
|
||||
@ -134,7 +134,6 @@ bool PersistentTimer::Load(Database *db) {
|
||||
(unsigned long)_char_id, _type);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Error in PersistentTimer::Load, error: %s", results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -165,9 +164,6 @@ bool PersistentTimer::Store(Database *db) {
|
||||
#endif
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
#if EQDEBUG > 5
|
||||
Log(Logs::General, Logs::Error, "Error in PersistentTimer::Store, error: %s", results.ErrorMessage().c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -185,9 +181,6 @@ bool PersistentTimer::Clear(Database *db) {
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
#if EQDEBUG > 5
|
||||
Log(Logs::General, Logs::Error, "Error in PersistentTimer::Clear, error: %s", results.ErrorMessage().c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -198,7 +191,7 @@ bool PersistentTimer::Clear(Database *db) {
|
||||
/* This function checks if the timer triggered */
|
||||
bool PersistentTimer::Expired(Database *db, bool iReset) {
|
||||
if (this == nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Null timer during ->Check()!?\n");
|
||||
LogError("Null timer during ->Check()!?\n");
|
||||
return(true);
|
||||
}
|
||||
uint32 current_time = get_current_time();
|
||||
@ -289,9 +282,6 @@ bool PTimerList::Load(Database *db) {
|
||||
(unsigned long)_char_id);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
#if EQDEBUG > 5
|
||||
Log(Logs::General, Logs::Error, "Error in PersistentTimer::Load, error: %s", results.ErrorMessage().c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -348,9 +338,6 @@ bool PTimerList::Clear(Database *db) {
|
||||
#endif
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
#if EQDEBUG > 5
|
||||
Log(Logs::General, Logs::Error, "Error in PersistentTimer::Clear, error: %s", results.ErrorMessage().c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -440,9 +427,6 @@ bool PTimerList::ClearOffline(Database *db, uint32 char_id, pTimerType type) {
|
||||
#endif
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
#if EQDEBUG > 5
|
||||
Log(Logs::General, Logs::Error, "Error in PTimerList::ClearOffline, error: %s", results.ErrorMessage().c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "string_util.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
|
||||
/*
|
||||
Commands:
|
||||
@ -45,14 +46,14 @@ const char *RuleManager::s_categoryNames[_CatCount+1] = {
|
||||
|
||||
const RuleManager::RuleInfo RuleManager::s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount+1] = {
|
||||
/* this is done in three steps so we can reliably get to them by index*/
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, IntRule, Int__##rule },
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, IntRule, Int__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, RealRule, Real__##rule },
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, RealRule, Real__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, BoolRule, Bool__##rule },
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, BoolRule, Bool__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
{ "Invalid Rule", _CatCount, IntRule }
|
||||
};
|
||||
@ -145,11 +146,11 @@ bool RuleManager::SetRule(const char *rule_name, const char *rule_value, Databas
|
||||
switch(type) {
|
||||
case IntRule:
|
||||
m_RuleIntValues[index] = atoi(rule_value);
|
||||
Log(Logs::Detail, Logs::Rules, "Set rule %s to value %d", rule_name, m_RuleIntValues[index]);
|
||||
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleIntValues[index]);
|
||||
break;
|
||||
case RealRule:
|
||||
m_RuleRealValues[index] = atof(rule_value);
|
||||
Log(Logs::Detail, Logs::Rules, "Set rule %s to value %.13f", rule_name, m_RuleRealValues[index]);
|
||||
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleRealValues[index]);
|
||||
break;
|
||||
case BoolRule:
|
||||
uint32 val = 0;
|
||||
@ -157,7 +158,7 @@ bool RuleManager::SetRule(const char *rule_name, const char *rule_value, Databas
|
||||
val = 1;
|
||||
|
||||
m_RuleBoolValues[index] = val;
|
||||
Log(Logs::Detail, Logs::Rules, "Set rule %s to value %s", rule_name, m_RuleBoolValues[index] == 1 ? "true" : "false");
|
||||
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleBoolValues[index] == 1 ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -178,11 +179,11 @@ void RuleManager::ResetRules(bool reload) {
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Resetting running rules to default values");
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
m_RuleIntValues[ Int__##rule ] = default_value;
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
m_RuleRealValues[ Real__##rule ] = default_value;
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
m_RuleBoolValues[ Bool__##rule ] = default_value;
|
||||
#include "ruletypes.h"
|
||||
|
||||
@ -214,19 +215,101 @@ bool RuleManager::_FindRule(const char *rule_name, RuleType &type_into, uint16 &
|
||||
//assumes index is valid!
|
||||
const char *RuleManager::_GetRuleName(RuleType type, uint16 index) {
|
||||
switch (type) {
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].name);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index + _IntRuleCount].name);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index + _IntRuleCount + _RealRuleCount].name);
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].name);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount].name);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].name);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//should never happen
|
||||
return("InvalidRule??");
|
||||
return(s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount].name); // no need to create a string when one already exists...
|
||||
}
|
||||
|
||||
//assumes index is valid!
|
||||
const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) {
|
||||
switch (type) {
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].notes);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount].notes);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].notes);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//should never happen
|
||||
return(s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount].notes);
|
||||
}
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
|
||||
return (false);
|
||||
}
|
||||
|
||||
m_activeRuleset = ruleset_id;
|
||||
m_activeName = ruleset_name;
|
||||
|
||||
/* Load default ruleset values first if we're loading something other than default */
|
||||
if (strcasecmp(ruleset_name, "default") != 0) {
|
||||
|
||||
std::string default_ruleset_name = "default";
|
||||
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
|
||||
|
||||
if (default_ruleset_id < 0) {
|
||||
Log(Logs::Detail,
|
||||
Logs::Rules,
|
||||
"Failed to find default ruleset '%s' for load operation. Canceling.",
|
||||
default_ruleset_name.c_str()
|
||||
);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Processing rule set '%s' (%d) load...", default_ruleset_name.c_str(), default_ruleset_id);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT `rule_name`, `rule_value` FROM `rule_values` WHERE `ruleset_id` = '%d'",
|
||||
default_ruleset_id
|
||||
);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload)) {
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for '%s'", row[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Processing rule set '%s' (%d) load...", ruleset_name, ruleset_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `rule_name`, `rule_value` FROM `rule_values` WHERE `ruleset_id` = '%d'", ruleset_id);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload)) {
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for '%s'", row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
|
||||
|
||||
if (ruleset_name != nullptr) {
|
||||
//saving to a specific name
|
||||
if (m_activeName != ruleset_name) {
|
||||
@ -257,56 +340,6 @@ void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
}
|
||||
}
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
|
||||
return (false);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", ruleset_name, ruleset_id);
|
||||
|
||||
m_activeRuleset = ruleset_id;
|
||||
m_activeName = ruleset_name;
|
||||
|
||||
/* Load default ruleset values first if we're loading something other than default */
|
||||
if (strcasecmp(ruleset_name, "default") != 0) {
|
||||
std::string default_ruleset_name = "default";
|
||||
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
|
||||
if (default_ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.",
|
||||
default_ruleset_name.c_str());
|
||||
return (false);
|
||||
}
|
||||
Log(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name.c_str(), default_ruleset_id);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d",
|
||||
default_ruleset_id
|
||||
);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload))
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
|
||||
}
|
||||
|
||||
std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id);
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload))
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
char value_string[100];
|
||||
|
||||
@ -328,17 +361,241 @@ void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO rule_values "
|
||||
"(ruleset_id, rule_name, rule_value) "
|
||||
" VALUES(%d, '%s', '%s')",
|
||||
"REPLACE INTO `rule_values`"
|
||||
"(`ruleset_id`, `rule_name`, `rule_value`, `notes`)"
|
||||
" VALUES('%d', '%s', '%s', '%s')",
|
||||
m_activeRuleset,
|
||||
_GetRuleName(type, index),
|
||||
value_string
|
||||
value_string,
|
||||
EscapeString(_GetRuleNotes(type, index)).c_str()
|
||||
);
|
||||
|
||||
database->QueryDatabase(query);
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bool quiet_update)
|
||||
{
|
||||
std::vector<std::string> database_data;
|
||||
std::map<std::string, std::pair<std::string, const std::string *>> rule_data;
|
||||
std::vector<std::tuple<int, std::string, std::string, std::string>> injected_rule_entries;
|
||||
|
||||
if (ruleset_name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ruleset_id = GetRulesetID(db, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load database rule names
|
||||
std::string query(StringFormat("SELECT `rule_name` FROM `rule_values` WHERE `ruleset_id` = '%i'", ruleset_id));
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build database data entries
|
||||
for (auto row : results) {
|
||||
database_data.push_back(std::string(row[0]));
|
||||
}
|
||||
|
||||
// build rule data entries
|
||||
for (const auto &ri_iter : s_RuleInfo) {
|
||||
if (strcasecmp(ri_iter.name, "Invalid Rule") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char buffer[100];
|
||||
|
||||
switch (ri_iter.type) {
|
||||
case IntRule:
|
||||
sprintf(buffer, "%d", m_RuleIntValues[ri_iter.rule_index]);
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
case RealRule:
|
||||
sprintf(buffer, "%.13f", m_RuleRealValues[ri_iter.rule_index]);
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
case BoolRule:
|
||||
sprintf(buffer, "%s", (m_RuleBoolValues[ri_iter.rule_index] ? "true" : "false"));
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// build injected entries
|
||||
for (const auto &rd_iter : rule_data) {
|
||||
|
||||
const auto &dd_iter = std::find(database_data.begin(), database_data.end(), rd_iter.first);
|
||||
if (dd_iter == database_data.end()) {
|
||||
|
||||
injected_rule_entries.push_back(
|
||||
std::tuple<int, std::string, std::string, std::string>(
|
||||
ruleset_id, // `ruleset_id`
|
||||
rd_iter.first, // `rule_name`
|
||||
rd_iter.second.first, // `rule_value`
|
||||
EscapeString(*rd_iter.second.second) // `notes`
|
||||
)
|
||||
);
|
||||
|
||||
if (!quiet_update) {
|
||||
LogInfo(
|
||||
"Adding new rule [{}] ruleset [{}] ({}) value [{}]",
|
||||
rd_iter.first.c_str(),
|
||||
ruleset_name,
|
||||
ruleset_id,
|
||||
rd_iter.second.first.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (injected_rule_entries.size()) {
|
||||
|
||||
std::string query(
|
||||
fmt::format(
|
||||
"REPLACE INTO `rule_values`(`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}",
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_tuple(",", std::pair<char, char>('\'', '\''), injected_rule_entries)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"[{}] New rule(s) added to ruleset [{}] [{}]",
|
||||
injected_rule_entries.size(),
|
||||
ruleset_name,
|
||||
ruleset_id
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update)
|
||||
{
|
||||
std::vector<std::string> rule_data;
|
||||
std::vector<std::string> orphaned_rule_entries;
|
||||
|
||||
// load database rule names
|
||||
std::string query("SELECT `rule_name` FROM `rule_values` GROUP BY `rule_name`");
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build rule data entries
|
||||
for (const auto &ri_iter : s_RuleInfo) {
|
||||
if (strcasecmp(ri_iter.name, "Invalid Rule") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rule_data.push_back(ri_iter.name);
|
||||
}
|
||||
|
||||
// build orphaned entries
|
||||
for (auto row : results) {
|
||||
|
||||
const auto &rd_iter = std::find(rule_data.begin(), rule_data.end(), row[0]);
|
||||
if (rd_iter == rule_data.end()) {
|
||||
|
||||
orphaned_rule_entries.push_back(std::string(row[0]));
|
||||
|
||||
if (!quiet_update) {
|
||||
LogInfo(
|
||||
"Rule [{}] no longer exists... Deleting orphaned entry from `rule_values` table...",
|
||||
row[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (orphaned_rule_entries.size()) {
|
||||
|
||||
std::string query (
|
||||
fmt::format(
|
||||
"DELETE FROM `rule_values` WHERE `rule_name` IN ({})",
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned_rule_entries)
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo("[{}] Orphaned Rule(s) Deleted from [All Rulesets] (-1)", orphaned_rule_entries.size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuleManager::RestoreRuleNotes(Database *db)
|
||||
{
|
||||
std::string query("SELECT `ruleset_id`, `rule_name`, `notes` FROM `rule_values`");
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int update_count = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
auto rule = [](const char *rule_name) {
|
||||
|
||||
for (auto rule_iter : s_RuleInfo) {
|
||||
if (strcasecmp(rule_iter.name, rule_name) == 0) {
|
||||
return rule_iter;
|
||||
}
|
||||
}
|
||||
|
||||
return s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount];
|
||||
}(row[1]);
|
||||
|
||||
if (strcasecmp(rule.name, row[1]) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (row[2] != nullptr && rule.notes.compare(row[2]) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string query(
|
||||
fmt::format(
|
||||
"UPDATE `rule_values` SET `notes` = '{}' WHERE `ruleset_id` = '{}' AND `rule_name` = '{}'",
|
||||
EscapeString(rule.notes),
|
||||
row[0],
|
||||
row[1]
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++update_count;
|
||||
}
|
||||
|
||||
if (update_count > 0) {
|
||||
LogInfo("[{}] Rule Note [{}] Restored", update_count, (update_count == 1 ? "" : "s"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int RuleManager::GetRulesetID(Database *database, const char *ruleset_name) {
|
||||
|
||||
|
||||
@ -49,21 +49,21 @@ class RuleManager {
|
||||
public:
|
||||
//generate our rule enums:
|
||||
typedef enum {
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
Int__##rule,
|
||||
#include "ruletypes.h"
|
||||
_IntRuleCount
|
||||
} IntType;
|
||||
|
||||
typedef enum {
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
Real__##rule,
|
||||
#include "ruletypes.h"
|
||||
_RealRuleCount
|
||||
} RealType;
|
||||
|
||||
typedef enum {
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
Bool__##rule,
|
||||
#include "ruletypes.h"
|
||||
_BoolRuleCount
|
||||
@ -97,6 +97,9 @@ public:
|
||||
static const char *GetRuleName(IntType t) { return(s_RuleInfo[t].name); }
|
||||
static const char *GetRuleName(RealType t) { return(s_RuleInfo[t+_IntRuleCount].name); }
|
||||
static const char *GetRuleName(BoolType t) { return(s_RuleInfo[t+_IntRuleCount+_RealRuleCount].name); }
|
||||
static const std::string &GetRuleNotes(IntType t) { return(s_RuleInfo[t].notes); }
|
||||
static const std::string &GetRuleNotes(RealType t) { return(s_RuleInfo[t+_IntRuleCount].notes); }
|
||||
static const std::string &GetRuleNotes(BoolType t) { return(s_RuleInfo[t+_IntRuleCount+_RealRuleCount].notes); }
|
||||
static uint32 CountRules() { return(_RulesCount); }
|
||||
static CategoryType FindCategory(const char *catname);
|
||||
bool ListRules(const char *catname, std::vector<const char *> &into);
|
||||
@ -113,6 +116,9 @@ public:
|
||||
void ResetRules(bool reload = false);
|
||||
bool LoadRules(Database *db, const char *ruleset = nullptr, bool reload = false);
|
||||
void SaveRules(Database *db, const char *ruleset = nullptr);
|
||||
bool UpdateInjectedRules(Database *db, const char *ruleset_name, bool quiet_update = false);
|
||||
bool UpdateOrphanedRules(Database *db, bool quiet_update = false);
|
||||
bool RestoreRuleNotes(Database *db);
|
||||
|
||||
private:
|
||||
RuleManager();
|
||||
@ -137,15 +143,17 @@ private:
|
||||
|
||||
static bool _FindRule(const char *rule_name, RuleType &type_into, uint16 &index_into);
|
||||
static const char *_GetRuleName(RuleType type, uint16 index);
|
||||
static const std::string &_GetRuleNotes(RuleType type, uint16 index);
|
||||
static int _FindOrCreateRuleset(Database *db, const char *ruleset);
|
||||
void _SaveRule(Database *db, RuleType type, uint16 index);
|
||||
|
||||
|
||||
static const char *s_categoryNames[];
|
||||
typedef struct {
|
||||
const char *name;
|
||||
CategoryType category;
|
||||
RuleType type;
|
||||
uint16 rule_index; //index into its 'type' array
|
||||
const std::string notes;
|
||||
} RuleInfo;
|
||||
static const RuleInfo s_RuleInfo[];
|
||||
|
||||
|
||||
1228
common/ruletypes.h
1228
common/ruletypes.h
File diff suppressed because it is too large
Load Diff
@ -100,8 +100,8 @@ const std::string &EQEmu::SayLinkEngine::GenerateLink()
|
||||
if ((m_Link.length() == 0) || (m_Link.length() > (EQEmu::constants::SAY_LINK_MAXIMUM_SIZE))) {
|
||||
m_Error = true;
|
||||
m_Link = "<LINKER ERROR>";
|
||||
Log(Logs::General, Logs::Error, "SayLinkEngine::GenerateLink() failed to generate a useable say link");
|
||||
Log(Logs::General, Logs::Error, ">> LinkType: %i, Lengths: {link: %u(%u), body: %u(%u), text: %u(%u)}",
|
||||
LogError("SayLinkEngine::GenerateLink() failed to generate a useable say link");
|
||||
LogError(">> LinkType: {}, Lengths: {link: {}({}), body: {}({}), text: {}({})}",
|
||||
m_LinkType,
|
||||
m_Link.length(),
|
||||
EQEmu::constants::SAY_LINK_MAXIMUM_SIZE,
|
||||
@ -110,8 +110,8 @@ const std::string &EQEmu::SayLinkEngine::GenerateLink()
|
||||
m_LinkText.length(),
|
||||
EQEmu::constants::SAY_LINK_TEXT_SIZE
|
||||
);
|
||||
Log(Logs::General, Logs::Error, ">> LinkBody: %s", m_LinkBody.c_str());
|
||||
Log(Logs::General, Logs::Error, ">> LinkText: %s", m_LinkText.c_str());
|
||||
LogError(">> LinkBody: {}", m_LinkBody.c_str());
|
||||
LogError(">> LinkText: {}", m_LinkText.c_str());
|
||||
}
|
||||
|
||||
return m_Link;
|
||||
@ -316,7 +316,7 @@ std::string EQEmu::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text,
|
||||
|
||||
results = database.QueryDatabase(insert_query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Error in saylink phrase queries %s", results.ErrorMessage().c_str());
|
||||
LogError("Error in saylink phrase queries {}", results.ErrorMessage().c_str());
|
||||
}
|
||||
else {
|
||||
saylink_id = results.LastInsertedID();
|
||||
|
||||
@ -143,14 +143,15 @@
|
||||
#define ServerOP_ClientVersionSummary 0x0215
|
||||
#define ServerOP_LSInfo 0x1000
|
||||
#define ServerOP_LSStatus 0x1001
|
||||
#define ServerOP_LSClientAuth 0x1002
|
||||
#define ServerOP_LSClientAuthLeg 0x1002
|
||||
#define ServerOP_LSFatalError 0x1003
|
||||
#define ServerOP_SystemwideMessage 0x1005
|
||||
#define ServerOP_ListWorlds 0x1006
|
||||
#define ServerOP_PeerConnect 0x1007
|
||||
#define ServerOP_NewLSInfo 0x1008
|
||||
#define ServerOP_LSRemoteAddr 0x1009
|
||||
#define ServerOP_LSAccountUpdate 0x100A
|
||||
#define ServerOP_LSAccountUpdate 0x100A
|
||||
#define ServerOP_LSClientAuth 0x100B
|
||||
|
||||
#define ServerOP_EncapPacket 0x2007 // Packet within a packet
|
||||
#define ServerOP_WorldListUpdate 0x2008
|
||||
@ -171,8 +172,10 @@
|
||||
#define ServerOP_LSPlayerJoinWorld 0x3007
|
||||
#define ServerOP_LSPlayerZoneChange 0x3008
|
||||
|
||||
#define ServerOP_UsertoWorldReq 0xAB00
|
||||
#define ServerOP_UsertoWorldResp 0xAB01
|
||||
#define ServerOP_UsertoWorldReqLeg 0xAB00
|
||||
#define ServerOP_UsertoWorldRespLeg 0xAB01
|
||||
#define ServerOP_UsertoWorldReq 0xAB02
|
||||
#define ServerOP_UsertoWorldResp 0xAB03
|
||||
|
||||
#define ServerOP_LauncherConnectInfo 0x3000
|
||||
#define ServerOP_LauncherZoneRequest 0x3001
|
||||
@ -469,15 +472,15 @@ struct ServerLSInfo_Struct {
|
||||
};
|
||||
|
||||
struct ServerNewLSInfo_Struct {
|
||||
char name[201]; // name the worldserver wants
|
||||
char shortname[50]; // shortname the worldserver wants
|
||||
char remote_address[125]; // DNS address of the server
|
||||
char local_address[125]; // DNS address of the server
|
||||
char account[31]; // account name for the worldserver
|
||||
char password[31]; // password for the name
|
||||
char protocolversion[25]; // Major protocol version number
|
||||
char serverversion[64]; // minor server software version number
|
||||
uint8 servertype; // 0=world, 1=chat, 2=login, 3=MeshLogin
|
||||
char server_long_name[201]; // name the worldserver wants
|
||||
char server_short_name[50]; // shortname the worldserver wants
|
||||
char remote_ip_address[125]; // DNS address of the server
|
||||
char local_ip_address[125]; // DNS address of the server
|
||||
char account_name[31]; // account name for the worldserver
|
||||
char account_password[31]; // password for the name
|
||||
char protocol_version[25]; // Major protocol version number
|
||||
char server_version[64]; // minor server software version number
|
||||
uint8 server_process_type; // 0=world, 1=chat, 2=login, 3=MeshLogin
|
||||
};
|
||||
|
||||
struct ServerLSAccountUpdate_Struct { // for updating info on login server
|
||||
@ -486,7 +489,7 @@ struct ServerLSAccountUpdate_Struct { // for updating info on login server
|
||||
uint32 useraccountid; // player account ID
|
||||
char useraccount[31]; // player account name
|
||||
char userpassword[51]; // player account password
|
||||
char useremail[101]; // player account email address
|
||||
char user_email[101]; // player account email address
|
||||
};
|
||||
|
||||
struct ServerLSStatus_Struct {
|
||||
@ -533,18 +536,35 @@ struct ServerLSPlayerZoneChange_Struct {
|
||||
};
|
||||
|
||||
struct ClientAuth_Struct {
|
||||
uint32 lsaccount_id; // ID# in login server's db
|
||||
char name[30]; // username in login server's db
|
||||
uint32 loginserver_account_id; // ID# in login server's db
|
||||
char loginserver_name[64];
|
||||
char account_name[30]; // username in login server's db
|
||||
char key[30]; // the Key the client will present
|
||||
uint8 lsadmin; // login server admin level
|
||||
int16 worldadmin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
||||
int16 is_world_admin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
||||
uint32 ip;
|
||||
uint8 local; // 1 if the client is from the local network
|
||||
uint8 is_client_from_local_network; // 1 if the client is from the local network
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(lsaccount_id, name, key, lsadmin, worldadmin, ip, local);
|
||||
ar(loginserver_account_id, loginserver_name, account_name, key, lsadmin, is_world_admin, ip, is_client_from_local_network);
|
||||
}
|
||||
};
|
||||
|
||||
struct ClientAuthLegacy_Struct {
|
||||
uint32 loginserver_account_id; // ID# in login server's db
|
||||
char loginserver_account_name[30]; // username in login server's db
|
||||
char key[30]; // the Key the client will present
|
||||
uint8 loginserver_admin_level; // login server admin level
|
||||
int16 is_world_admin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
||||
uint32 ip;
|
||||
uint8 is_client_from_local_network; // 1 if the client is from the local network
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(loginserver_account_id, loginserver_account_name, key, loginserver_admin_level, is_world_admin, ip, is_client_from_local_network);
|
||||
}
|
||||
};
|
||||
|
||||
@ -672,7 +692,7 @@ struct ServerSyncWorldList_Struct {
|
||||
bool placeholder;
|
||||
};
|
||||
|
||||
struct UsertoWorldRequest_Struct {
|
||||
struct UsertoWorldRequestLegacy_Struct {
|
||||
uint32 lsaccountid;
|
||||
uint32 worldid;
|
||||
uint32 FromID;
|
||||
@ -680,12 +700,30 @@ struct UsertoWorldRequest_Struct {
|
||||
char IPAddr[64];
|
||||
};
|
||||
|
||||
struct UsertoWorldResponse_Struct {
|
||||
struct UsertoWorldRequest_Struct {
|
||||
uint32 lsaccountid;
|
||||
uint32 worldid;
|
||||
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
||||
uint32 FromID;
|
||||
uint32 ToID;
|
||||
char IPAddr[64];
|
||||
char login[64];
|
||||
};
|
||||
|
||||
struct UsertoWorldResponseLegacy_Struct {
|
||||
uint32 lsaccountid;
|
||||
uint32 worldid;
|
||||
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
||||
uint32 FromID;
|
||||
uint32 ToID;
|
||||
};
|
||||
|
||||
struct UsertoWorldResponse_Struct {
|
||||
uint32 lsaccountid;
|
||||
uint32 worldid;
|
||||
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
||||
uint32 FromID;
|
||||
uint32 ToID;
|
||||
char login[64];
|
||||
};
|
||||
|
||||
// generic struct to be used for alot of simple zone->world questions
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
#include <algorithm>
|
||||
@ -123,7 +124,7 @@ void SharedDatabase::SetMailKey(int CharID, int IPAddress, int MailKey)
|
||||
MailKeyString, CharID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
Log(Logs::General, Logs::Error, "SharedDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str());
|
||||
LogError("SharedDatabase::SetMailKey({}, {}) : {}", CharID, MailKeyString, results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
@ -466,8 +467,6 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQEmu::InventoryProfile *inv, bool
|
||||
id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Database::GetSharedBank(uint32 account_id): %s",
|
||||
results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -487,8 +486,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQEmu::InventoryProfile *inv, bool
|
||||
const EQEmu::ItemData *item = GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
Log(Logs::General, Logs::Error,
|
||||
"Warning: %s %i has an invalid item_id %i in inventory slot %i",
|
||||
LogError("Warning: [{}] [{}] has an invalid item_id [{}] in inventory slot [{}]",
|
||||
((is_charid == true) ? "charid" : "acctid"), id, item_id, slot_id);
|
||||
continue;
|
||||
}
|
||||
@ -536,8 +534,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQEmu::InventoryProfile *inv, bool
|
||||
if (put_slot_id != INVALID_INDEX)
|
||||
continue;
|
||||
|
||||
Log(Logs::General, Logs::Error,
|
||||
"Warning: Invalid slot_id for item in shared bank inventory: %s=%i, item_id=%i, slot_id=%i",
|
||||
LogError("Warning: Invalid slot_id for item in shared bank inventory: [{}]=[{}], item_id=[{}], slot_id=[{}]",
|
||||
((is_charid == true) ? "charid" : "acctid"), id, item_id, slot_id);
|
||||
|
||||
if (is_charid)
|
||||
@ -561,7 +558,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
char_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "If you got an error related to the 'instnodrop' field, run the "
|
||||
LogError("If you got an error related to the 'instnodrop' field, run the "
|
||||
"following SQL Queries:\nalter table inventory add instnodrop "
|
||||
"tinyint(1) unsigned default 0 not null;\n");
|
||||
return false;
|
||||
@ -625,8 +622,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
const EQEmu::ItemData *item = GetItem(item_id);
|
||||
|
||||
if (!item) {
|
||||
Log(Logs::General, Logs::Error,
|
||||
"Warning: charid %i has an invalid item_id %i in inventory slot %i", char_id, item_id,
|
||||
LogError("Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]", char_id, item_id,
|
||||
slot_id);
|
||||
continue;
|
||||
}
|
||||
@ -699,8 +695,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
} else if (slot_id >= 3111 && slot_id <= 3179) {
|
||||
// Admins: please report any occurrences of this error
|
||||
Log(Logs::General, Logs::Error, "Warning: Defunct location for item in inventory: "
|
||||
"charid=%i, item_id=%i, slot_id=%i .. pushing to cursor...",
|
||||
LogError("Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
||||
char_id, item_id, slot_id);
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
} else {
|
||||
@ -711,8 +706,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
|
||||
// Save ptr to item in inventory
|
||||
if (put_slot_id == INVALID_INDEX) {
|
||||
Log(Logs::General, Logs::Error,
|
||||
"Warning: Invalid slot_id for item in inventory: charid=%i, item_id=%i, slot_id=%i",
|
||||
LogError("Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
||||
char_id, item_id, slot_id);
|
||||
}
|
||||
}
|
||||
@ -720,8 +714,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
if (cv_conflict) {
|
||||
char char_name[64] = "";
|
||||
GetCharName(char_id, char_name);
|
||||
Log(Logs::General, Logs::Error,
|
||||
"ClientVersion/Expansion conflict during inventory load at zone entry for '%s' (charid: %u, inver: %s, gmi: %s)",
|
||||
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||
char_name,
|
||||
char_id,
|
||||
EQEmu::versions::MobVersionName(inv->InventoryVersion()),
|
||||
@ -746,7 +739,7 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQEmu::Inventor
|
||||
name, account_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "If you got an error related to the 'instnodrop' field, run the "
|
||||
LogError("If you got an error related to the 'instnodrop' field, run the "
|
||||
"following SQL Queries:\nalter table inventory add instnodrop "
|
||||
"tinyint(1) unsigned default 0 not null;\n");
|
||||
return false;
|
||||
@ -834,8 +827,7 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQEmu::Inventor
|
||||
|
||||
// Save ptr to item in inventory
|
||||
if (put_slot_id == INVALID_INDEX)
|
||||
Log(Logs::General, Logs::Error, "Warning: Invalid slot_id for item in inventory: name=%s, "
|
||||
"acctid=%i, item_id=%i, slot_id=%i",
|
||||
LogError("Warning: Invalid slot_id for item in inventory: name={}, acctid={}, item_id={}, slot_id={}",
|
||||
name, account_id, item_id, slot_id);
|
||||
}
|
||||
|
||||
@ -911,7 +903,7 @@ bool SharedDatabase::LoadItems(const std::string &prefix) {
|
||||
items_hash = std::unique_ptr<EQEmu::FixedMemoryHashSet<EQEmu::ItemData>>(new EQEmu::FixedMemoryHashSet<EQEmu::ItemData>(reinterpret_cast<uint8*>(items_mmf->Get()), items_mmf->Size()));
|
||||
mutex.Unlock();
|
||||
} catch(std::exception& ex) {
|
||||
Log(Logs::General, Logs::Error, "Error Loading Items: %s", ex.what());
|
||||
LogError("Error Loading Items: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1172,7 +1164,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
|
||||
try {
|
||||
hash.insert(item.ID, item);
|
||||
} catch (std::exception &ex) {
|
||||
Log(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what());
|
||||
LogError("Database::LoadItems: {}", ex.what());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1229,7 +1221,7 @@ std::string SharedDatabase::GetBook(const char *txtfile, int16 *language)
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
Log(Logs::General, Logs::Error, "No book to send, (%s)", txtfile);
|
||||
LogError("No book to send, ({})", txtfile);
|
||||
txtout.assign(" ",1);
|
||||
return txtout;
|
||||
}
|
||||
@ -1334,7 +1326,7 @@ bool SharedDatabase::LoadNPCFactionLists(const std::string &prefix) {
|
||||
faction_hash = std::unique_ptr<EQEmu::FixedMemoryHashSet<NPCFactionList>>(new EQEmu::FixedMemoryHashSet<NPCFactionList>(reinterpret_cast<uint8*>(faction_mmf->Get()), faction_mmf->Size()));
|
||||
mutex.Unlock();
|
||||
} catch(std::exception& ex) {
|
||||
Log(Logs::General, Logs::Error, "Error Loading npc factions: %s", ex.what());
|
||||
LogError("Error Loading npc factions: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1352,8 +1344,8 @@ EQEmu::ItemInstance* SharedDatabase::CreateItem(uint32 item_id, int16 charges, u
|
||||
inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Error: valid item data returned a null reference for EQEmu::ItemInstance creation in SharedDatabase::CreateItem()");
|
||||
Log(Logs::General, Logs::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
|
||||
LogError("Error: valid item data returned a null reference for EQEmu::ItemInstance creation in SharedDatabase::CreateItem()");
|
||||
LogError("Item Data = ID: {}, Name: {}, Charges: {}", item->ID, item->Name, charges);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1378,8 +1370,8 @@ EQEmu::ItemInstance* SharedDatabase::CreateItem(const EQEmu::ItemData* item, int
|
||||
inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Error: valid item data returned a null reference for EQEmu::ItemInstance creation in SharedDatabase::CreateItem()");
|
||||
Log(Logs::General, Logs::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
|
||||
LogError("Error: valid item data returned a null reference for EQEmu::ItemInstance creation in SharedDatabase::CreateItem()");
|
||||
LogError("Item Data = ID: {}, Name: {}, Charges: {}", item->ID, item->Name, charges);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1409,8 +1401,8 @@ EQEmu::ItemInstance* SharedDatabase::CreateBaseItem(const EQEmu::ItemData* item,
|
||||
inst = new EQEmu::ItemInstance(item, charges);
|
||||
|
||||
if (inst == nullptr) {
|
||||
Log(Logs::General, Logs::Error, "Error: valid item data returned a null reference for EQEmu::ItemInstance creation in SharedDatabase::CreateBaseItem()");
|
||||
Log(Logs::General, Logs::Error, "Item Data = ID: %u, Name: %s, Charges: %i", item->ID, item->Name, charges);
|
||||
LogError("Error: valid item data returned a null reference for EQEmu::ItemInstance creation in SharedDatabase::CreateBaseItem()");
|
||||
LogError("Item Data = ID: {}, Name: {}, Charges: {}", item->ID, item->Name, charges);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1469,6 +1461,55 @@ bool SharedDatabase::GetCommandSettings(std::map<std::string, std::pair<uint8, s
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected)
|
||||
{
|
||||
if (injected.size()) {
|
||||
|
||||
std::string query = fmt::format(
|
||||
"REPLACE INTO `command_settings`(`command`, `access`) VALUES {}",
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_pair(",", std::pair<char, char>('\'', '\''), injected)
|
||||
)
|
||||
);
|
||||
|
||||
if (!QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"[{0}] New Command(s) Added",
|
||||
injected.size()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned)
|
||||
{
|
||||
if (orphaned.size()) {
|
||||
|
||||
std::string query = fmt::format(
|
||||
"DELETE FROM `command_settings` WHERE `command` IN ({})",
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned)
|
||||
);
|
||||
|
||||
if (!QueryDatabase(query).Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"{} Orphaned Command{} Deleted",
|
||||
orphaned.size(),
|
||||
(orphaned.size() == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
|
||||
skill_caps_mmf.reset(nullptr);
|
||||
|
||||
@ -1485,7 +1526,7 @@ bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
|
||||
skill_caps_mmf = std::unique_ptr<EQEmu::MemoryMappedFile>(new EQEmu::MemoryMappedFile(file_name));
|
||||
mutex.Unlock();
|
||||
} catch(std::exception &ex) {
|
||||
Log(Logs::General, Logs::Error, "Error loading skill caps: %s", ex.what());
|
||||
LogError("Error loading skill caps: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1501,7 +1542,7 @@ void SharedDatabase::LoadSkillCaps(void *data) {
|
||||
const std::string query = "SELECT skillID, class, level, cap FROM skill_caps ORDER BY skillID, class, level";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Log(Logs::General, Logs::Error, "Error loading skill caps from database: %s", results.ErrorMessage().c_str());
|
||||
LogError("Error loading skill caps from database: {}", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1645,7 +1686,7 @@ bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const
|
||||
mutex.Unlock();
|
||||
}
|
||||
catch(std::exception& ex) {
|
||||
Log(Logs::General, Logs::Error, "Error Loading Spells: %s", ex.what());
|
||||
LogError("Error Loading Spells: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1662,7 +1703,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
}
|
||||
|
||||
if(results.ColumnCount() <= SPELL_LOAD_FIELD_COUNT) {
|
||||
Log(Logs::Detail, Logs::Spells, "Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT(%u)", SPELL_LOAD_FIELD_COUNT);
|
||||
LogSpells("Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT([{}])", SPELL_LOAD_FIELD_COUNT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1672,7 +1713,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
tempid = atoi(row[0]);
|
||||
if(tempid >= max_spells) {
|
||||
Log(Logs::Detail, Logs::Spells, "Non fatal error: spell.id >= max_spells, ignoring.");
|
||||
LogSpells("Non fatal error: spell.id >= max_spells, ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1849,7 +1890,7 @@ bool SharedDatabase::LoadBaseData(const std::string &prefix) {
|
||||
base_data_mmf = std::unique_ptr<EQEmu::MemoryMappedFile>(new EQEmu::MemoryMappedFile(file_name));
|
||||
mutex.Unlock();
|
||||
} catch(std::exception& ex) {
|
||||
Log(Logs::General, Logs::Error, "Error Loading Base Data: %s", ex.what());
|
||||
LogError("Error Loading Base Data: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1873,22 +1914,22 @@ void SharedDatabase::LoadBaseData(void *data, int max_level) {
|
||||
cl = atoi(row[1]);
|
||||
|
||||
if(lvl <= 0) {
|
||||
Log(Logs::General, Logs::Error, "Non fatal error: base_data.level <= 0, ignoring.");
|
||||
LogError("Non fatal error: base_data.level <= 0, ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lvl >= max_level) {
|
||||
Log(Logs::General, Logs::Error, "Non fatal error: base_data.level >= max_level, ignoring.");
|
||||
LogError("Non fatal error: base_data.level >= max_level, ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(cl <= 0) {
|
||||
Log(Logs::General, Logs::Error, "Non fatal error: base_data.cl <= 0, ignoring.");
|
||||
LogError("Non fatal error: base_data.cl <= 0, ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(cl > 16) {
|
||||
Log(Logs::General, Logs::Error, "Non fatal error: base_data.class > 16, ignoring.");
|
||||
LogError("Non fatal error: base_data.class > 16, ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2096,7 +2137,7 @@ bool SharedDatabase::LoadLoot(const std::string &prefix) {
|
||||
loot_drop_mmf->Size()));
|
||||
mutex.Unlock();
|
||||
} catch(std::exception &ex) {
|
||||
Log(Logs::General, Logs::Error, "Error loading loot: %s", ex.what());
|
||||
LogError("Error loading loot: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2112,7 +2153,7 @@ const LootTable_Struct* SharedDatabase::GetLootTable(uint32 loottable_id) {
|
||||
return &loot_table_hash->at(loottable_id);
|
||||
}
|
||||
} catch(std::exception &ex) {
|
||||
Log(Logs::General, Logs::Error, "Could not get loot table: %s", ex.what());
|
||||
LogError("Could not get loot table: {}", ex.what());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -2126,7 +2167,7 @@ const LootDrop_Struct* SharedDatabase::GetLootDrop(uint32 lootdrop_id) {
|
||||
return &loot_drop_hash->at(lootdrop_id);
|
||||
}
|
||||
} catch(std::exception &ex) {
|
||||
Log(Logs::General, Logs::Error, "Could not get loot drop: %s", ex.what());
|
||||
LogError("Could not get loot drop: {}", ex.what());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -71,6 +71,8 @@ class SharedDatabase : public Database
|
||||
void LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message);
|
||||
void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message);
|
||||
bool GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &command_settings);
|
||||
bool UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected);
|
||||
bool UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned);
|
||||
uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID);
|
||||
void SetMailKey(int CharID, int IPAddress, int MailKey);
|
||||
std::string GetMailKey(int CharID, bool key_only = false);
|
||||
|
||||
@ -850,7 +850,7 @@ DmgShieldType GetDamageShieldType(uint16 spell_id, int32 DSType)
|
||||
// If we have a DamageShieldType for this spell from the damageshieldtypes table, return that,
|
||||
// else, make a guess, based on the resist type. Default return value is DS_THORNS
|
||||
if (IsValidSpell(spell_id)) {
|
||||
Log(Logs::Detail, Logs::Spells, "DamageShieldType for spell %i (%s) is %X\n", spell_id,
|
||||
LogSpells("DamageShieldType for spell [{}] ([{}]) is [{}]", spell_id,
|
||||
spells[spell_id].name, spells[spell_id].DamageShieldType);
|
||||
|
||||
if (spells[spell_id].DamageShieldType)
|
||||
|
||||
@ -262,6 +262,18 @@ void find_replace(std::string &string_subject, const std::string &search_string,
|
||||
|
||||
}
|
||||
|
||||
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver)
|
||||
{
|
||||
auto split = SplitString(s, ':');
|
||||
if (split.size() == 2) {
|
||||
loginserver = split[0];
|
||||
account = split[1];
|
||||
}
|
||||
else if(split.size() == 1) {
|
||||
account = split[0];
|
||||
}
|
||||
}
|
||||
|
||||
//Const char based
|
||||
|
||||
// normal strncpy doesnt put a null term on copied strings, this one does
|
||||
@ -514,4 +526,4 @@ bool isAlphaNumeric(const char *text)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
#include <tuple>
|
||||
|
||||
#ifndef _WIN32
|
||||
// this doesn't appear to affect linux-based systems..need feedback for _WIN64
|
||||
#include <fmt/format.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
@ -31,6 +37,93 @@ std::vector<std::string> split(std::string str_to_split, char delimiter);
|
||||
const std::string StringFormat(const char* format, ...);
|
||||
const std::string vStringFormat(const char* format, va_list args);
|
||||
std::string implode(std::string glue, std::vector<std::string> src);
|
||||
|
||||
template <typename T>
|
||||
std::string implode(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
|
||||
for (const T &src_iter : src) {
|
||||
oss << encapsulation.first << src_iter << encapsulation.second << glue;
|
||||
}
|
||||
|
||||
std::string output(oss.str());
|
||||
output.resize(output.size() - glue.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
|
||||
template <typename T1, typename T2>
|
||||
std::vector<std::string> join_pair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::pair<T1, T2>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::pair<T1, T2> &src_iter : src) {
|
||||
output.push_back(
|
||||
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
src_iter.first,
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
src_iter.second,
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
std::vector<std::string> join_tuple(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::tuple<T1, T2, T3, T4>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::tuple<T1, T2, T3, T4> &src_iter : src) {
|
||||
|
||||
output.push_back(
|
||||
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
std::get<0>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<1>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<2>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<3>(src_iter),
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &s, char delim);
|
||||
std::string EscapeString(const char *src, size_t sz);
|
||||
std::string EscapeString(const std::string &s);
|
||||
@ -39,6 +132,7 @@ void ToLowerString(std::string &s);
|
||||
void ToUpperString(std::string &s);
|
||||
std::string JoinString(const std::vector<std::string>& ar, const std::string &delim);
|
||||
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string);
|
||||
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver);
|
||||
|
||||
//const char based
|
||||
|
||||
|
||||
@ -41,13 +41,13 @@ void StructStrategy::ErrorEncoder(EQApplicationPacket **in_p, std::shared_ptr<EQ
|
||||
EQApplicationPacket *p = *in_p;
|
||||
*in_p = nullptr;
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Error encoding opcode %s: no encoder provided. Dropping.", OpcodeManager::EmuToName(p->GetOpcode()));
|
||||
LogNetcode("[STRUCTS] Error encoding opcode [{}]: no encoder provided. Dropping", OpcodeManager::EmuToName(p->GetOpcode()));
|
||||
|
||||
delete p;
|
||||
}
|
||||
|
||||
void StructStrategy::ErrorDecoder(EQApplicationPacket *p) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Error decoding opcode %s: no decoder provided. Invalidating.", OpcodeManager::EmuToName(p->GetOpcode()));
|
||||
LogNetcode("[STRUCTS] Error decoding opcode [{}]: no decoder provided. Invalidating", OpcodeManager::EmuToName(p->GetOpcode()));
|
||||
p->SetOpcode(OP_Unknown);
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ ThreadReturnType BaseTCPServer::TCPServerLoop(void* tmp) {
|
||||
BaseTCPServer* tcps = (BaseTCPServer*) tmp;
|
||||
|
||||
#ifndef WIN32
|
||||
Log(Logs::Detail, Logs::None, "Starting TCPServerLoop with thread ID %d", pthread_self());
|
||||
LogDebug( "Starting TCPServerLoop with thread ID [{}]", pthread_self());
|
||||
#endif
|
||||
|
||||
tcps->MLoopRunning.lock();
|
||||
@ -79,7 +79,7 @@ ThreadReturnType BaseTCPServer::TCPServerLoop(void* tmp) {
|
||||
tcps->MLoopRunning.unlock();
|
||||
|
||||
#ifndef WIN32
|
||||
Log(Logs::Detail, Logs::None, "Ending TCPServerLoop with thread ID %d", pthread_self());
|
||||
LogDebug( "Ending TCPServerLoop with thread ID [{}]", pthread_self());
|
||||
#endif
|
||||
|
||||
THREAD_RETURN(nullptr);
|
||||
|
||||
@ -42,9 +42,6 @@ void TimeoutManager::CheckTimeouts() {
|
||||
for(; cur != end; ++cur) {
|
||||
Timeoutable *it = *cur;
|
||||
if(it->next_check.Check()) {
|
||||
#ifdef TIMEOUT_DEBUG
|
||||
Log(Logs::General, Logs::None,, "Checking timeout on 0x%x\n", it);
|
||||
#endif
|
||||
it->CheckTimeout();
|
||||
}
|
||||
}
|
||||
@ -57,15 +54,9 @@ void TimeoutManager::AddMember(Timeoutable *who) {
|
||||
|
||||
DeleteMember(who); //just in case... prolly not needed.
|
||||
members.push_back(who);
|
||||
#ifdef TIMEOUT_DEBUG
|
||||
Log(Logs::General, Logs::None,, "Adding timeoutable 0x%x\n", who);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TimeoutManager::DeleteMember(Timeoutable *who) {
|
||||
#ifdef TIMEOUT_DEBUG
|
||||
Log(Logs::General, Logs::None,, "Removing timeoutable 0x%x\n", who);
|
||||
#endif
|
||||
std::vector<Timeoutable *>::iterator cur,end;
|
||||
cur = members.begin();
|
||||
end = members.end();
|
||||
|
||||
@ -1,318 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
Original file by Yves Berquin.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
#ifndef TIXML_USE_STL
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "tinystr.h"
|
||||
|
||||
// TiXmlString constructor, based on a C string
|
||||
TiXmlString::TiXmlString (const char* instring)
|
||||
{
|
||||
size_t newlen;
|
||||
char * newstring;
|
||||
|
||||
if (!instring)
|
||||
{
|
||||
allocated = 0;
|
||||
cstring = nullptr;
|
||||
current_length = 0;
|
||||
return;
|
||||
}
|
||||
newlen = strlen (instring) + 1;
|
||||
newstring = new char [newlen];
|
||||
memcpy (newstring, instring, newlen);
|
||||
// strcpy (newstring, instring);
|
||||
allocated = newlen;
|
||||
cstring = newstring;
|
||||
current_length = newlen - 1;
|
||||
}
|
||||
|
||||
// TiXmlString copy constructor
|
||||
TiXmlString::TiXmlString (const TiXmlString& copy)
|
||||
{
|
||||
size_t newlen;
|
||||
char * newstring;
|
||||
|
||||
// Prevent copy to self!
|
||||
if ( © == this )
|
||||
return;
|
||||
|
||||
if (! copy . allocated)
|
||||
{
|
||||
allocated = 0;
|
||||
cstring = nullptr;
|
||||
current_length = 0;
|
||||
return;
|
||||
}
|
||||
newlen = copy . length () + 1;
|
||||
newstring = new char [newlen];
|
||||
// strcpy (newstring, copy . cstring);
|
||||
memcpy (newstring, copy . cstring, newlen);
|
||||
allocated = newlen;
|
||||
cstring = newstring;
|
||||
current_length = newlen - 1;
|
||||
}
|
||||
|
||||
// TiXmlString = operator. Safe when assign own content
|
||||
void TiXmlString ::operator = (const char * content)
|
||||
{
|
||||
size_t newlen;
|
||||
char * newstring;
|
||||
|
||||
if (! content)
|
||||
{
|
||||
empty_it ();
|
||||
return;
|
||||
}
|
||||
newlen = strlen (content) + 1;
|
||||
newstring = new char [newlen];
|
||||
// strcpy (newstring, content);
|
||||
memcpy (newstring, content, newlen);
|
||||
empty_it ();
|
||||
allocated = newlen;
|
||||
cstring = newstring;
|
||||
current_length = newlen - 1;
|
||||
}
|
||||
|
||||
// = operator. Safe when assign own content
|
||||
void TiXmlString ::operator = (const TiXmlString & copy)
|
||||
{
|
||||
size_t newlen;
|
||||
char * newstring;
|
||||
|
||||
if (! copy . length ())
|
||||
{
|
||||
empty_it ();
|
||||
return;
|
||||
}
|
||||
newlen = copy . length () + 1;
|
||||
newstring = new char [newlen];
|
||||
// strcpy (newstring, copy . c_str ());
|
||||
memcpy (newstring, copy . c_str (), newlen);
|
||||
empty_it ();
|
||||
allocated = newlen;
|
||||
cstring = newstring;
|
||||
current_length = newlen - 1;
|
||||
}
|
||||
|
||||
|
||||
// append a const char * to an existing TiXmlString
|
||||
void TiXmlString::append( const char* str, size_t len )
|
||||
{
|
||||
char * new_string;
|
||||
size_t new_alloc, new_size, size_suffix;
|
||||
|
||||
// don't use strlen - it can overrun the len passed in!
|
||||
const char* p = str;
|
||||
size_suffix = 0;
|
||||
|
||||
while ( *p && size_suffix < (unsigned)len )
|
||||
{
|
||||
++p;
|
||||
++size_suffix;
|
||||
}
|
||||
if ( !size_suffix)
|
||||
return;
|
||||
|
||||
new_size = length () + size_suffix + 1;
|
||||
// check if we need to expand
|
||||
if (new_size > allocated)
|
||||
{
|
||||
// compute new size
|
||||
new_alloc = assign_new_size (new_size);
|
||||
|
||||
// allocate new buffer
|
||||
new_string = new char [new_alloc];
|
||||
new_string [0] = 0;
|
||||
|
||||
// copy the previous allocated buffer into this one
|
||||
if (allocated && cstring)
|
||||
// strcpy (new_string, cstring);
|
||||
memcpy (new_string, cstring, length ());
|
||||
|
||||
// append the suffix. It does exist, otherwize we wouldn't be expanding
|
||||
// strncat (new_string, str, len);
|
||||
memcpy (new_string + length (),
|
||||
str,
|
||||
size_suffix);
|
||||
|
||||
// return previsously allocated buffer if any
|
||||
if (allocated && cstring)
|
||||
delete [] cstring;
|
||||
|
||||
// update member variables
|
||||
cstring = new_string;
|
||||
allocated = new_alloc;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we know we can safely append the new string
|
||||
// strncat (cstring, str, len);
|
||||
memcpy (cstring + length (),
|
||||
str,
|
||||
size_suffix);
|
||||
}
|
||||
current_length = new_size - 1;
|
||||
cstring [current_length] = 0;
|
||||
}
|
||||
|
||||
|
||||
// append a const char * to an existing TiXmlString
|
||||
void TiXmlString::append( const char * suffix )
|
||||
{
|
||||
char * new_string;
|
||||
size_t new_alloc, new_size;
|
||||
|
||||
new_size = length () + strlen (suffix) + 1;
|
||||
// check if we need to expand
|
||||
if (new_size > allocated)
|
||||
{
|
||||
// compute new size
|
||||
new_alloc = assign_new_size (new_size);
|
||||
|
||||
// allocate new buffer
|
||||
new_string = new char [new_alloc];
|
||||
new_string [0] = 0;
|
||||
|
||||
// copy the previous allocated buffer into this one
|
||||
if (allocated && cstring)
|
||||
memcpy (new_string, cstring, 1 + length ());
|
||||
// strcpy (new_string, cstring);
|
||||
|
||||
// append the suffix. It does exist, otherwize we wouldn't be expanding
|
||||
// strcat (new_string, suffix);
|
||||
memcpy (new_string + length (),
|
||||
suffix,
|
||||
strlen (suffix) + 1);
|
||||
|
||||
// return previsously allocated buffer if any
|
||||
if (allocated && cstring)
|
||||
delete [] cstring;
|
||||
|
||||
// update member variables
|
||||
cstring = new_string;
|
||||
allocated = new_alloc;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we know we can safely append the new string
|
||||
// strcat (cstring, suffix);
|
||||
memcpy (cstring + length (),
|
||||
suffix,
|
||||
strlen (suffix) + 1);
|
||||
}
|
||||
current_length = new_size - 1;
|
||||
}
|
||||
|
||||
// Check for TiXmlString equuivalence
|
||||
//bool TiXmlString::operator == (const TiXmlString & compare) const
|
||||
//{
|
||||
// return (! strcmp (c_str (), compare . c_str ()));
|
||||
//}
|
||||
|
||||
//unsigned TiXmlString::length () const
|
||||
//{
|
||||
// if (allocated)
|
||||
// // return strlen (cstring);
|
||||
// return current_length;
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
|
||||
unsigned TiXmlString::find (char tofind, unsigned offset) const
|
||||
{
|
||||
char * lookup;
|
||||
|
||||
if (offset >= length ())
|
||||
return (unsigned) notfound;
|
||||
for (lookup = cstring + offset; * lookup; lookup++)
|
||||
if (* lookup == tofind)
|
||||
return (unsigned)(lookup - cstring);
|
||||
return (unsigned) notfound;
|
||||
}
|
||||
|
||||
|
||||
bool TiXmlString::operator == (const TiXmlString & compare) const
|
||||
{
|
||||
if ( allocated && compare.allocated )
|
||||
{
|
||||
assert( cstring );
|
||||
assert( compare.cstring );
|
||||
return ( strcmp( cstring, compare.cstring ) == 0 );
|
||||
}
|
||||
else if ( length() == 0 && compare.length() == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TiXmlString::operator == (const char* compare) const
|
||||
{
|
||||
if ( allocated && compare && *compare )
|
||||
{
|
||||
assert( cstring );
|
||||
return ( strcmp( cstring, compare ) == 0 );
|
||||
}
|
||||
else if ( length() == 0 && (!compare || !*compare ) ) // this is a little dubious, but try to duplicate behavior in other operator==
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TiXmlString::operator < (const TiXmlString & compare) const
|
||||
{
|
||||
if ( allocated && compare.allocated )
|
||||
{
|
||||
assert( cstring );
|
||||
assert( compare.cstring );
|
||||
return ( strcmp( cstring, compare.cstring ) > 0 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool TiXmlString::operator > (const TiXmlString & compare) const
|
||||
{
|
||||
if ( allocated && compare.allocated )
|
||||
{
|
||||
assert( cstring );
|
||||
assert( compare.cstring );
|
||||
return ( strcmp( cstring, compare.cstring ) < 0 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif // TIXML_USE_STL
|
||||
@ -1,250 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
Original file by Yves Berquin.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
|
||||
#ifndef TIXML_USE_STL
|
||||
|
||||
#ifndef TIXML_STRING_INCLUDED
|
||||
#define TIXML_STRING_INCLUDED
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4530 )
|
||||
#pragma warning( disable : 4786 )
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
TiXmlString is an emulation of the std::string template.
|
||||
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
|
||||
Only the member functions relevant to the TinyXML project have been implemented.
|
||||
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
|
||||
a string and there's no more room, we allocate a buffer twice as big as we need.
|
||||
*/
|
||||
class TiXmlString
|
||||
{
|
||||
public :
|
||||
// TiXmlString constructor, based on a string, mark explicit to force
|
||||
// us to find unnecessary casting.
|
||||
explicit TiXmlString (const char * instring);
|
||||
|
||||
// TiXmlString empty constructor
|
||||
TiXmlString ()
|
||||
{
|
||||
allocated = 0;
|
||||
cstring = nullptr;
|
||||
current_length = 0;
|
||||
}
|
||||
|
||||
// TiXmlString copy constructor
|
||||
explicit TiXmlString (const TiXmlString& copy);
|
||||
|
||||
// TiXmlString destructor
|
||||
~ TiXmlString ()
|
||||
{
|
||||
empty_it ();
|
||||
}
|
||||
|
||||
// Convert a TiXmlString into a classical char *
|
||||
const char * c_str () const
|
||||
{
|
||||
if (allocated)
|
||||
return cstring;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Return the length of a TiXmlString
|
||||
size_t length () const
|
||||
{
|
||||
return ( allocated ) ? current_length : 0;
|
||||
}
|
||||
|
||||
// TiXmlString = operator
|
||||
void operator = (const char * content);
|
||||
|
||||
// = operator
|
||||
void operator = (const TiXmlString & copy);
|
||||
|
||||
// += operator. Maps to append
|
||||
TiXmlString& operator += (const char * suffix)
|
||||
{
|
||||
append (suffix);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// += operator. Maps to append
|
||||
TiXmlString& operator += (char single)
|
||||
{
|
||||
append (single);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// += operator. Maps to append
|
||||
TiXmlString& operator += (TiXmlString & suffix)
|
||||
{
|
||||
append (suffix);
|
||||
return *this;
|
||||
}
|
||||
bool operator == (const TiXmlString & compare) const;
|
||||
bool operator == (const char* compare) const;
|
||||
bool operator < (const TiXmlString & compare) const;
|
||||
bool operator > (const TiXmlString & compare) const;
|
||||
|
||||
// Checks if a TiXmlString is empty
|
||||
bool empty () const
|
||||
{
|
||||
return length () ? false : true;
|
||||
}
|
||||
|
||||
// single char extraction
|
||||
const char& at (unsigned index) const
|
||||
{
|
||||
assert( index < length ());
|
||||
return cstring [index];
|
||||
}
|
||||
|
||||
// find a char in a string. Return TiXmlString::notfound if not found
|
||||
unsigned find (char lookup) const
|
||||
{
|
||||
return find (lookup, 0);
|
||||
}
|
||||
|
||||
// find a char in a string from an offset. Return TiXmlString::notfound if not found
|
||||
unsigned find (char tofind, unsigned offset) const;
|
||||
|
||||
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
|
||||
function clears the content of the TiXmlString if any exists.
|
||||
*/
|
||||
void reserve (unsigned size)
|
||||
{
|
||||
empty_it ();
|
||||
if (size)
|
||||
{
|
||||
allocated = size;
|
||||
cstring = new char [size];
|
||||
cstring [0] = 0;
|
||||
current_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// [] operator
|
||||
char& operator [] (unsigned index) const
|
||||
{
|
||||
assert( index < length ());
|
||||
return cstring [index];
|
||||
}
|
||||
|
||||
// Error value for find primitive
|
||||
enum { notfound = 0xffffffff,
|
||||
npos = notfound };
|
||||
|
||||
void append (const char *str, size_t len );
|
||||
|
||||
protected :
|
||||
|
||||
// The base string
|
||||
char * cstring;
|
||||
// Number of chars allocated
|
||||
size_t allocated;
|
||||
// Current string size
|
||||
size_t current_length;
|
||||
|
||||
// New size computation. It is simplistic right now : it returns twice the amount
|
||||
// we need
|
||||
size_t assign_new_size (size_t minimum_to_allocate)
|
||||
{
|
||||
return minimum_to_allocate * 2;
|
||||
}
|
||||
|
||||
// Internal function that clears the content of a TiXmlString
|
||||
void empty_it ()
|
||||
{
|
||||
if (cstring)
|
||||
delete [] cstring;
|
||||
cstring = nullptr;
|
||||
allocated = 0;
|
||||
current_length = 0;
|
||||
}
|
||||
|
||||
void append (const char *suffix );
|
||||
|
||||
// append function for another TiXmlString
|
||||
void append (const TiXmlString & suffix)
|
||||
{
|
||||
append (suffix . c_str ());
|
||||
}
|
||||
|
||||
// append for a single char.
|
||||
void append (char single)
|
||||
{
|
||||
if ( cstring && current_length < (allocated-1) )
|
||||
{
|
||||
cstring[ current_length ] = single;
|
||||
++current_length;
|
||||
cstring[ current_length ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char smallstr [2];
|
||||
smallstr [0] = single;
|
||||
smallstr [1] = 0;
|
||||
append (smallstr);
|
||||
}
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
/*
|
||||
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
|
||||
Only the operators that we need for TinyXML have been developped.
|
||||
*/
|
||||
class TiXmlOutStream : public TiXmlString
|
||||
{
|
||||
public :
|
||||
TiXmlOutStream () : TiXmlString () {}
|
||||
|
||||
// TiXmlOutStream << operator. Maps to TiXmlString::append
|
||||
TiXmlOutStream & operator << (const char * in)
|
||||
{
|
||||
append (in);
|
||||
return (* this);
|
||||
}
|
||||
|
||||
// TiXmlOutStream << operator. Maps to TiXmlString::append
|
||||
TiXmlOutStream & operator << (const TiXmlString & in)
|
||||
{
|
||||
append (in . c_str ());
|
||||
return (* this);
|
||||
}
|
||||
} ;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( default : 4530 )
|
||||
#pragma warning( default : 4786 )
|
||||
#endif
|
||||
|
||||
#endif // TIXML_STRING_INCLUDED
|
||||
#endif // TIXML_USE_STL
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
// The goal of the seperate error file is to make the first
|
||||
// step towards localization. tinyxml (currently) only supports
|
||||
// latin-1, but at least the error messages could now be translated.
|
||||
//
|
||||
// It also cleans up the code a bit.
|
||||
//
|
||||
|
||||
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
|
||||
{
|
||||
"No error",
|
||||
"Error",
|
||||
"Failed to open file",
|
||||
"Memory allocation failed.",
|
||||
"Error parsing Element.",
|
||||
"Failed to read Element name",
|
||||
"Error reading Element value.",
|
||||
"Error reading Attributes.",
|
||||
"Error: empty tag.",
|
||||
"Error reading end tag.",
|
||||
"Error parsing Unknown.",
|
||||
"Error parsing Comment.",
|
||||
"Error parsing Declaration.",
|
||||
"Error document empty.",
|
||||
"Error null (0) or unexpected EOF found in input stream.",
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@ -31,10 +31,10 @@
|
||||
*/
|
||||
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9141
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9143
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9025
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
@ -44,7 +44,7 @@ bool WorldConnection::SendPacket(ServerPacket* pack) {
|
||||
|
||||
void WorldConnection::OnConnected() {
|
||||
const EQEmuConfig *Config=EQEmuConfig::get();
|
||||
Log(Logs::General, Logs::Netcode, "[WORLD] Connected to World: %s:%d", Config->WorldIP.c_str(), Config->WorldTCPPort);
|
||||
LogNetcode("[WORLD] Connected to World: [{}]:[{}]", Config->WorldIP.c_str(), Config->WorldTCPPort);
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_ZAAuth, 16);
|
||||
MD5::Generate((const uchar*) m_password.c_str(), m_password.length(), pack->pBuffer);
|
||||
@ -76,7 +76,7 @@ bool WorldConnection::Connect() {
|
||||
if (tcpc.Connect(Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf)) {
|
||||
return true;
|
||||
} else {
|
||||
Log(Logs::General, Logs::Netcode, "[WORLD] WorldConnection connect: Connecting to the server %s:%d failed: %s", Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf);
|
||||
LogNetcode("[WORLD] WorldConnection connect: Connecting to the server [{}]:[{}] failed: [{}]", Config->WorldIP.c_str(), Config->WorldTCPPort, errbuf);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "global_define.h"
|
||||
#include "xml_parser.h"
|
||||
|
||||
XMLParser::XMLParser() {
|
||||
ParseOkay = false;
|
||||
}
|
||||
|
||||
bool XMLParser::ParseFile(const char *file, const char *root_ele) {
|
||||
std::map<std::string,ElementHandler>::iterator handler;
|
||||
TiXmlDocument doc( file );
|
||||
if(!doc.LoadFile()) {
|
||||
printf("Unable to load '%s': %s\n", file, doc.ErrorDesc());
|
||||
return(false);
|
||||
}
|
||||
|
||||
TiXmlElement *root = doc.FirstChildElement( root_ele );
|
||||
if(root == nullptr) {
|
||||
printf("Unable to find root '%s' in %s\n",root_ele, file);
|
||||
return(false);
|
||||
}
|
||||
|
||||
ParseOkay=true;
|
||||
|
||||
TiXmlNode *main_element = nullptr;
|
||||
while( (main_element = root->IterateChildren( main_element )) ) {
|
||||
if(main_element->Type() != TiXmlNode::ELEMENT)
|
||||
continue; //skip crap we dont care about
|
||||
TiXmlElement *ele = (TiXmlElement *) main_element;
|
||||
|
||||
handler=Handlers.find(ele->Value());
|
||||
if (handler!=Handlers.end() && handler->second) {
|
||||
ElementHandler h=handler->second;
|
||||
|
||||
/*
|
||||
*
|
||||
* This is kinda a sketchy operation here, since all of these
|
||||
* element handler methods will be functions in child classes.
|
||||
* This essentially causes us to do an un-checkable (and hence
|
||||
* un-handle-properly-able) cast down to the child class. This
|
||||
* WILL BREAK if any children classes do multiple inheritance.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
(this->*h)(ele);
|
||||
} else {
|
||||
//unhandled element.... do nothing for now
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(ParseOkay);
|
||||
}
|
||||
|
||||
const char *XMLParser::ParseTextBlock(TiXmlNode *within, const char *name, bool optional) {
|
||||
TiXmlElement * txt = within->FirstChildElement(name);
|
||||
if(txt == nullptr) {
|
||||
if(!optional) {
|
||||
printf("Unable to find a '%s' element on %s element at line %d\n", name, within->Value(), within->Row());
|
||||
ParseOkay=false;
|
||||
}
|
||||
return(nullptr);
|
||||
}
|
||||
TiXmlNode *contents = txt->FirstChild();
|
||||
if(contents == nullptr || contents->Type() != TiXmlNode::TEXT) {
|
||||
if(!optional)
|
||||
printf("Node '%s' was expected to be a text element in %s element at line %d\n", name, txt->Value(), txt->Row());
|
||||
return(nullptr);
|
||||
}
|
||||
return(contents->Value());
|
||||
}
|
||||
|
||||
const char *XMLParser::GetText(TiXmlNode *within, bool optional) {
|
||||
TiXmlNode *contents = within->FirstChild();
|
||||
if(contents == nullptr || contents->Type() != TiXmlNode::TEXT) {
|
||||
if(!optional) {
|
||||
printf("Node was expected to be a text element in %s element at line %d\n", within->Value(), within->Row());
|
||||
ParseOkay=false;
|
||||
}
|
||||
return(nullptr);
|
||||
}
|
||||
return(contents->Value());
|
||||
}
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef XMLParser_H
|
||||
#define XMLParser_H
|
||||
|
||||
#include "global_define.h"
|
||||
#include "tinyxml/tinyxml.h"
|
||||
#include "../common/types.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
/*
|
||||
* See note in XMLParser::ParseFile() before inheriting this class.
|
||||
*/
|
||||
class XMLParser {
|
||||
public:
|
||||
typedef void (XMLParser::*ElementHandler)(TiXmlElement *ele);
|
||||
|
||||
XMLParser();
|
||||
virtual ~XMLParser() {}
|
||||
|
||||
bool ParseFile(const char *file, const char *root_ele);
|
||||
bool ParseStatus() const { return ParseOkay; }
|
||||
|
||||
protected:
|
||||
const char *ParseTextBlock(TiXmlNode *within, const char *name, bool optional = false);
|
||||
const char *GetText(TiXmlNode *within, bool optional = false);
|
||||
|
||||
std::map<std::string,ElementHandler> Handlers;
|
||||
|
||||
bool ParseOkay;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,25 +1,26 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
|
||||
SET(eqlogin_sources
|
||||
account_management.cpp
|
||||
client.cpp
|
||||
client_manager.cpp
|
||||
config.cpp
|
||||
database_mysql.cpp
|
||||
database_postgresql.cpp
|
||||
database.cpp
|
||||
encryption.cpp
|
||||
loginserver_command_handler.cpp
|
||||
loginserver_webserver.cpp
|
||||
main.cpp
|
||||
server_manager.cpp
|
||||
world_server.cpp
|
||||
)
|
||||
|
||||
SET(eqlogin_headers
|
||||
account_management.h
|
||||
client.h
|
||||
client_manager.h
|
||||
config.h
|
||||
database.h
|
||||
database_mysql.h
|
||||
database_postgresql.h
|
||||
encryption.h
|
||||
loginserver_command_handler.h
|
||||
loginserver_webserver.h
|
||||
login_server.h
|
||||
login_structures.h
|
||||
options.h
|
||||
|
||||
365
loginserver/account_management.cpp
Normal file
365
loginserver/account_management.cpp
Normal file
@ -0,0 +1,365 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "account_management.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/event/task_scheduler.h"
|
||||
#include "../common/event/event_loop.h"
|
||||
#include "../common/net/dns.h"
|
||||
|
||||
extern LoginServer server;
|
||||
EQ::Event::TaskScheduler task_runner;
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param email
|
||||
* @param source_loginserver
|
||||
* @param login_account_id
|
||||
* @return
|
||||
*/
|
||||
int32 AccountManagement::CreateLoginServerAccount(
|
||||
std::string username,
|
||||
std::string password,
|
||||
std::string email,
|
||||
const std::string &source_loginserver,
|
||||
uint32 login_account_id
|
||||
)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
auto hash = eqcrypt_hash(username, password, mode);
|
||||
|
||||
LogInfo(
|
||||
"Attempting to create local login account for user [{0}] encryption algorithm [{1}] ({2})",
|
||||
username,
|
||||
GetEncryptionByModeId(mode),
|
||||
mode
|
||||
);
|
||||
|
||||
unsigned int db_id = 0;
|
||||
if (server.db->DoesLoginServerAccountExist(username, hash, source_loginserver, 1)) {
|
||||
LogWarning(
|
||||
"Attempting to create local login account for user [{0}] login [{1}] but already exists!",
|
||||
username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 created_account_id = 0;
|
||||
if (login_account_id > 0) {
|
||||
created_account_id = server.db->CreateLoginDataWithID(username, hash, source_loginserver, login_account_id);
|
||||
} else {
|
||||
created_account_id = server.db->CreateLoginAccount(username, hash, source_loginserver, email);
|
||||
}
|
||||
|
||||
if (created_account_id > 0) {
|
||||
LogInfo(
|
||||
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) id: [{3}]",
|
||||
username,
|
||||
GetEncryptionByModeId(mode),
|
||||
mode,
|
||||
created_account_id
|
||||
);
|
||||
|
||||
return (int32) created_account_id;
|
||||
}
|
||||
|
||||
LogError("Failed to create local login account for user [{0}]!", username);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
bool AccountManagement::CreateLoginserverWorldAdminAccount(
|
||||
const std::string &username,
|
||||
const std::string &password,
|
||||
const std::string &email,
|
||||
const std::string &first_name,
|
||||
const std::string &last_name,
|
||||
const std::string &ip_address
|
||||
)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
auto hash = eqcrypt_hash(username, password, mode);
|
||||
|
||||
LogInfo(
|
||||
"Attempting to create world admin account | username [{0}] encryption algorithm [{1}] ({2})",
|
||||
username,
|
||||
GetEncryptionByModeId(mode),
|
||||
mode
|
||||
);
|
||||
|
||||
if (server.db->DoesLoginserverWorldAdminAccountExist(username)) {
|
||||
LogWarning(
|
||||
"Attempting to create world admin account for user [{0}] but already exists!",
|
||||
username
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 created_world_admin_id = server.db->CreateLoginserverWorldAdminAccount(
|
||||
username,
|
||||
hash,
|
||||
first_name,
|
||||
last_name,
|
||||
email,
|
||||
ip_address
|
||||
);
|
||||
|
||||
if (created_world_admin_id > 0) {
|
||||
LogInfo(
|
||||
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) new admin id [{3}]",
|
||||
username,
|
||||
GetEncryptionByModeId(mode),
|
||||
mode,
|
||||
created_world_admin_id
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
LogError("Failed to create world admin account account for user [{0}]!", username);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
uint32 AccountManagement::CheckLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password,
|
||||
const std::string &source_loginserver
|
||||
)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_admin = server.db->GetLoginServerAccountByAccountName(
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
if (!login_server_admin.loaded) {
|
||||
LogError(
|
||||
"CheckLoginUserCredentials account [{0}] source_loginserver [{1}] not found!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validated_credentials = eqcrypt_verify_hash(
|
||||
in_account_username,
|
||||
in_account_password,
|
||||
login_server_admin.account_password,
|
||||
mode
|
||||
);
|
||||
|
||||
if (!validated_credentials) {
|
||||
LogError(
|
||||
"CheckLoginUserCredentials account [{0}] source_loginserver [{1}] invalid credentials!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"CheckLoginUserCredentials account [{0}] source_loginserver [{1}] credentials validated success!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
return login_server_admin.id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
bool AccountManagement::UpdateLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password,
|
||||
const std::string &source_loginserver
|
||||
)
|
||||
{
|
||||
auto mode = server.options.GetEncryptionMode();
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
if (!login_server_account.loaded) {
|
||||
LogError(
|
||||
"ChangeLoginserverUserCredentials account [{0}] source_loginserver [{1}] not found!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
server.db->UpdateLoginserverAccountPasswordHash(
|
||||
in_account_username,
|
||||
source_loginserver,
|
||||
eqcrypt_hash(
|
||||
in_account_username,
|
||||
in_account_password,
|
||||
mode
|
||||
)
|
||||
);
|
||||
|
||||
LogInfo(
|
||||
"ChangeLoginserverUserCredentials account [{0}] source_loginserver [{1}] credentials updated!",
|
||||
in_account_username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password
|
||||
)
|
||||
{
|
||||
auto res = task_runner.Enqueue(
|
||||
[&]() -> uint32 {
|
||||
bool running = true;
|
||||
uint32 ret = 0;
|
||||
|
||||
EQ::Net::DaybreakConnectionManager mgr;
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
||||
|
||||
mgr.OnNewConnection(
|
||||
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
|
||||
c = connection;
|
||||
}
|
||||
);
|
||||
|
||||
mgr.OnConnectionStateChange(
|
||||
[&](
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
|
||||
EQ::Net::DbProtocolStatus from,
|
||||
EQ::Net::DbProtocolStatus to
|
||||
) {
|
||||
if (EQ::Net::StatusConnected == to) {
|
||||
EQ::Net::DynamicPacket p;
|
||||
p.PutUInt16(0, 1); //OP_SessionReady
|
||||
p.PutUInt32(2, 2);
|
||||
c->QueuePacket(p);
|
||||
}
|
||||
else if (EQ::Net::StatusDisconnected == to) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
mgr.OnPacketRecv(
|
||||
[&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
|
||||
auto opcode = p.GetUInt16(0);
|
||||
switch (opcode) {
|
||||
case 0x0017: //OP_ChatMessage
|
||||
{
|
||||
size_t buffer_len =
|
||||
in_account_username.length() + in_account_password.length() + 2;
|
||||
|
||||
std::unique_ptr<char[]> buffer(new char[buffer_len]);
|
||||
|
||||
strcpy(&buffer[0], in_account_username.c_str());
|
||||
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
|
||||
|
||||
size_t encrypted_len = buffer_len;
|
||||
|
||||
if (encrypted_len % 8 > 0) {
|
||||
encrypted_len = ((encrypted_len / 8) + 1) * 8;
|
||||
}
|
||||
|
||||
EQ::Net::DynamicPacket p;
|
||||
p.Resize(12 + encrypted_len);
|
||||
p.PutUInt16(0, 2); //OP_Login
|
||||
p.PutUInt32(2, 3);
|
||||
|
||||
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
|
||||
c->QueuePacket(p);
|
||||
break;
|
||||
}
|
||||
case 0x0018: {
|
||||
auto encrypt_size = p.Length() - 12;
|
||||
if (encrypt_size % 8 > 0) {
|
||||
encrypt_size = (encrypt_size / 8) * 8;
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
|
||||
|
||||
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
|
||||
|
||||
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
|
||||
auto response_error = sp.GetUInt16(1);
|
||||
auto m_dbid = sp.GetUInt32(8);
|
||||
|
||||
{
|
||||
ret = (response_error <= 101 ? m_dbid : 0);
|
||||
running = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
EQ::Net::DNSLookup(
|
||||
"login.eqemulator.net", 5999, false, [&](const std::string &addr) {
|
||||
if (addr.empty()) {
|
||||
ret = 0;
|
||||
running = false;
|
||||
}
|
||||
|
||||
mgr.Connect(addr, 5999);
|
||||
}
|
||||
);
|
||||
|
||||
auto &loop = EQ::EventLoop::Get();
|
||||
while (running) {
|
||||
loop.Process();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
return res.get();
|
||||
}
|
||||
94
loginserver/account_management.h
Normal file
94
loginserver/account_management.h
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef EQEMU_ACCOUNT_MANAGEMENT_H
|
||||
#define EQEMU_ACCOUNT_MANAGEMENT_H
|
||||
|
||||
#include "iostream"
|
||||
#include "../common/types.h"
|
||||
|
||||
class AccountManagement {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param email
|
||||
* @param source_loginserver
|
||||
* @param login_account_id
|
||||
* @return
|
||||
*/
|
||||
static int32 CreateLoginServerAccount(
|
||||
std::string username,
|
||||
std::string password,
|
||||
std::string email = "",
|
||||
const std::string &source_loginserver = "local",
|
||||
uint32 login_account_id = 0
|
||||
);
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* @param password
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
static bool CreateLoginserverWorldAdminAccount(
|
||||
const std::string &username,
|
||||
const std::string &password,
|
||||
const std::string &email,
|
||||
const std::string &first_name = "",
|
||||
const std::string &last_name = "",
|
||||
const std::string &ip_address = ""
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static uint32 CheckLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password,
|
||||
const std::string &source_loginserver = "local"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static bool UpdateLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password,
|
||||
const std::string &source_loginserver = "local"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param in_account_username
|
||||
* @param in_account_password
|
||||
* @return
|
||||
*/
|
||||
static uint32 CheckExternalLoginserverUserCredentials(
|
||||
const std::string &in_account_username,
|
||||
const std::string &in_account_password
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_ACCOUNT_MANAGEMENT_H
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,137 +1,233 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_CLIENT_H
|
||||
#define EQEMU_CLIENT_H
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/random.h"
|
||||
|
||||
#include <memory>
|
||||
#include "../common/eq_stream_intf.h"
|
||||
#include "../common/net/dns.h"
|
||||
#include "../common/net/daybreak_connection.h"
|
||||
#include "login_structures.h"
|
||||
#include <memory>
|
||||
|
||||
enum LSClientVersion
|
||||
{
|
||||
enum LSClientVersion {
|
||||
cv_titanium,
|
||||
cv_sod
|
||||
};
|
||||
|
||||
enum LSClientStatus
|
||||
{
|
||||
enum LSClientStatus {
|
||||
cs_not_sent_session_ready,
|
||||
cs_waiting_for_login,
|
||||
cs_creating_account,
|
||||
cs_failed_to_login,
|
||||
cs_logged_in
|
||||
};
|
||||
|
||||
/**
|
||||
* Client class, controls a single client and it's
|
||||
* connection to the login server.
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
* Client class, controls a single client and it's connection to the login server
|
||||
*/
|
||||
class Client {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor, sets our connection to c and version to v
|
||||
*/
|
||||
* Constructor, sets our connection to c and version to v
|
||||
*
|
||||
* @param c
|
||||
* @param v
|
||||
*/
|
||||
Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Client() { }
|
||||
* Destructor
|
||||
*/
|
||||
~Client() {}
|
||||
|
||||
/**
|
||||
* Processes the client's connection and does various actions.
|
||||
*/
|
||||
* Processes the client's connection and does various actions
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
bool Process();
|
||||
|
||||
/**
|
||||
* Sends our reply to session ready packet.
|
||||
*/
|
||||
void Handle_SessionReady(const char* data, unsigned int size);
|
||||
* Sends our reply to session ready packet
|
||||
*
|
||||
* @param data
|
||||
* @param size
|
||||
*/
|
||||
void Handle_SessionReady(const char *data, unsigned int size);
|
||||
|
||||
/**
|
||||
* Verifies login and send a reply.
|
||||
*/
|
||||
void Handle_Login(const char* data, unsigned int size);
|
||||
* Verifies login and send a reply
|
||||
*
|
||||
* @param data
|
||||
* @param size
|
||||
*/
|
||||
void Handle_Login(const char *data, unsigned int size);
|
||||
|
||||
/**
|
||||
* Sends a packet to the requested server to see if the client is allowed or not.
|
||||
*/
|
||||
void Handle_Play(const char* data);
|
||||
* Sends a packet to the requested server to see if the client is allowed or not
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void Handle_Play(const char *data);
|
||||
|
||||
/**
|
||||
* Sends a server list packet to the client.
|
||||
*/
|
||||
* Sends a server list packet to the client
|
||||
*
|
||||
* @param seq
|
||||
*/
|
||||
void SendServerListPacket(uint32 seq);
|
||||
|
||||
/**
|
||||
* Sends the input packet to the client and clears our play response states.
|
||||
*/
|
||||
* Sends the input packet to the client and clears our play response states
|
||||
*
|
||||
* @param outapp
|
||||
*/
|
||||
void SendPlayResponse(EQApplicationPacket *outapp);
|
||||
|
||||
/**
|
||||
* Generates a random login key for the client during login.
|
||||
*/
|
||||
* Generates a random login key for the client during login
|
||||
*/
|
||||
void GenerateKey();
|
||||
|
||||
/**
|
||||
* Gets the account id of this client.
|
||||
*/
|
||||
* Gets the account id of this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetAccountID() const { return account_id; }
|
||||
|
||||
/**
|
||||
* Gets the account name of this client.
|
||||
*/
|
||||
* Gets the loginserver name of this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetLoginServerName() const { return loginserver_name; }
|
||||
|
||||
/**
|
||||
* Gets the account name of this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetAccountName() const { return account_name; }
|
||||
|
||||
/**
|
||||
* Gets the key generated at login for this client.
|
||||
*/
|
||||
* Gets the key generated at login for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetKey() const { return key; }
|
||||
|
||||
/**
|
||||
* Gets the server selected to be played on for this client.
|
||||
*/
|
||||
* Gets the server selected to be played on for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetPlayServerID() const { return play_server_id; }
|
||||
|
||||
/**
|
||||
* Gets the play sequence state for this client.
|
||||
*/
|
||||
* Gets the play sequence state for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetPlaySequence() const { return play_sequence_id; }
|
||||
|
||||
/**
|
||||
* Gets the connection for this client.
|
||||
*/
|
||||
* Gets the connection for this client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<EQStreamInterface> GetConnection() { return connection; }
|
||||
|
||||
EQEmu::Random random;
|
||||
private:
|
||||
std::shared_ptr<EQStreamInterface> connection;
|
||||
LSClientVersion version;
|
||||
LSClientStatus status;
|
||||
/**
|
||||
* Attempts to create a login account
|
||||
*
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param loginserver
|
||||
*/
|
||||
void AttemptLoginAccountCreation(const std::string &user, const std::string &pass, const std::string &loginserver);
|
||||
|
||||
std::string account_name;
|
||||
/**
|
||||
* Does a failed login
|
||||
*/
|
||||
void DoFailedLogin();
|
||||
|
||||
/**
|
||||
* Verifies a login hash, will also attempt to update a login hash if needed
|
||||
*
|
||||
* @param account_username
|
||||
* @param source_loginserver
|
||||
* @param account_password
|
||||
* @param password_hash
|
||||
* @return
|
||||
*/
|
||||
bool VerifyLoginHash(
|
||||
const std::string &account_username,
|
||||
const std::string &source_loginserver,
|
||||
const std::string &account_password,
|
||||
const std::string &password_hash
|
||||
);
|
||||
|
||||
void DoSuccessfulLogin(const std::string in_account_name, int db_account_id, const std::string &db_loginserver);
|
||||
void CreateLocalAccount(const std::string &username, const std::string &password);
|
||||
void CreateEQEmuAccount(const std::string &in_account_name, const std::string &in_account_password, unsigned int loginserver_account_id);
|
||||
|
||||
private:
|
||||
EQEmu::Random random;
|
||||
std::shared_ptr<EQStreamInterface> connection;
|
||||
LSClientVersion version;
|
||||
LSClientStatus status;
|
||||
|
||||
std::string account_name;
|
||||
unsigned int account_id;
|
||||
std::string loginserver_name;
|
||||
unsigned int play_server_id;
|
||||
unsigned int play_sequence_id;
|
||||
std::string key;
|
||||
std::string key;
|
||||
|
||||
std::unique_ptr<EQ::Net::DaybreakConnectionManager> login_connection_manager;
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> login_connection;
|
||||
LoginLoginRequest_Struct llrs;
|
||||
|
||||
std::string stored_user;
|
||||
std::string stored_pass;
|
||||
void LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection);
|
||||
void LoginOnStatusChange(
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
|
||||
EQ::Net::DbProtocolStatus from,
|
||||
EQ::Net::DbProtocolStatus to
|
||||
);
|
||||
void LoginOnStatusChangeIgnored(
|
||||
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
|
||||
EQ::Net::DbProtocolStatus from,
|
||||
EQ::Net::DbProtocolStatus to
|
||||
);
|
||||
void LoginOnPacketRecv(std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p);
|
||||
void LoginSendSessionReady();
|
||||
void LoginSendLogin();
|
||||
void LoginProcessLoginResponse(const EQ::Net::Packet &p);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,87 +1,119 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "client_manager.h"
|
||||
#include "login_server.h"
|
||||
|
||||
extern LoginServer server;
|
||||
extern bool run_server;
|
||||
extern bool run_server;
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/eqemu_logsys_fmt.h"
|
||||
|
||||
ClientManager::ClientManager()
|
||||
{
|
||||
int titanium_port = atoi(server.config->GetVariable("Titanium", "port").c_str());
|
||||
int titanium_port = server.config.GetVariableInt("client_configuration", "titanium_port", 5998);
|
||||
|
||||
EQStreamManagerInterfaceOptions titanium_opts(titanium_port, false, false);
|
||||
|
||||
titanium_stream = new EQ::Net::EQStreamManager(titanium_opts);
|
||||
titanium_ops = new RegularOpcodeManager;
|
||||
if (!titanium_ops->LoadOpcodes(server.config->GetVariable("Titanium", "opcodes").c_str()))
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "ClientManager fatal error: couldn't load opcodes for Titanium file %s.",
|
||||
server.config->GetVariable("Titanium", "opcodes").c_str());
|
||||
titanium_ops = new RegularOpcodeManager;
|
||||
if (!titanium_ops->LoadOpcodes(
|
||||
server.config.GetVariableString(
|
||||
"client_configuration",
|
||||
"titanium_opcodes",
|
||||
"login_opcodes.conf"
|
||||
).c_str())) {
|
||||
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
|
||||
server.config.GetVariableString("client_configuration", "titanium_opcodes", "login_opcodes.conf")
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
titanium_stream->OnNewConnection([this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogF(Logs::General, Logs::Login_Server, "New Titanium client connection from {0}:{1}", stream->GetRemoteIP(), stream->GetRemotePort());
|
||||
stream->SetOpcodeManager(&titanium_ops);
|
||||
Client *c = new Client(stream, cv_titanium);
|
||||
clients.push_back(c);
|
||||
});
|
||||
titanium_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New Titanium client connection from {0}:{1}",
|
||||
stream->GetRemoteIP(),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&titanium_ops);
|
||||
Client *c = new Client(stream, cv_titanium);
|
||||
clients.push_back(c);
|
||||
}
|
||||
);
|
||||
|
||||
int sod_port = server.config.GetVariableInt("client_configuration", "sod_port", 5999);
|
||||
|
||||
int sod_port = atoi(server.config->GetVariable("SoD", "port").c_str());
|
||||
EQStreamManagerInterfaceOptions sod_opts(sod_port, false, false);
|
||||
sod_stream = new EQ::Net::EQStreamManager(sod_opts);
|
||||
sod_ops = new RegularOpcodeManager;
|
||||
if (!sod_ops->LoadOpcodes(server.config->GetVariable("SoD", "opcodes").c_str()))
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "ClientManager fatal error: couldn't load opcodes for SoD file %s.",
|
||||
server.config->GetVariable("SoD", "opcodes").c_str());
|
||||
sod_ops = new RegularOpcodeManager;
|
||||
if (
|
||||
!sod_ops->LoadOpcodes(
|
||||
server.config.GetVariableString(
|
||||
"client_configuration",
|
||||
"sod_opcodes",
|
||||
"login_opcodes.conf"
|
||||
).c_str()
|
||||
)) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
|
||||
server.config.GetVariableString("client_configuration", "sod_opcodes", "login_opcodes.conf").c_str()
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
sod_stream->OnNewConnection([this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogF(Logs::General, Logs::Login_Server, "New SoD client connection from {0}:{1}", stream->GetRemoteIP(), stream->GetRemotePort());
|
||||
stream->SetOpcodeManager(&sod_ops);
|
||||
Client *c = new Client(stream, cv_sod);
|
||||
clients.push_back(c);
|
||||
});
|
||||
sod_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New SoD client connection from {0}:{1}",
|
||||
stream->GetRemoteIP(),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&sod_ops);
|
||||
Client *c = new Client(stream, cv_sod);
|
||||
clients.push_back(c);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ClientManager::~ClientManager()
|
||||
{
|
||||
if (titanium_stream)
|
||||
{
|
||||
if (titanium_stream) {
|
||||
delete titanium_stream;
|
||||
}
|
||||
|
||||
if (titanium_ops)
|
||||
{
|
||||
if (titanium_ops) {
|
||||
delete titanium_ops;
|
||||
}
|
||||
|
||||
if (sod_stream)
|
||||
{
|
||||
if (sod_stream) {
|
||||
delete sod_stream;
|
||||
}
|
||||
|
||||
if (sod_ops)
|
||||
{
|
||||
if (sod_ops) {
|
||||
delete sod_ops;
|
||||
}
|
||||
}
|
||||
@ -91,16 +123,13 @@ void ClientManager::Process()
|
||||
ProcessDisconnect();
|
||||
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end())
|
||||
{
|
||||
if ((*iter)->Process() == false)
|
||||
{
|
||||
Log(Logs::General, Logs::Debug, "Client had a fatal error and had to be removed from the login.");
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->Process() == false) {
|
||||
LogWarning("Client had a fatal error and had to be removed from the login");
|
||||
delete (*iter);
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
@ -109,58 +138,52 @@ void ClientManager::Process()
|
||||
void ClientManager::ProcessDisconnect()
|
||||
{
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end())
|
||||
{
|
||||
while (iter != clients.end()) {
|
||||
std::shared_ptr<EQStreamInterface> c = (*iter)->GetConnection();
|
||||
if (c->CheckState(CLOSED))
|
||||
{
|
||||
Log(Logs::General, Logs::Login_Server, "Client disconnected from the server, removing client.");
|
||||
if (c->CheckState(CLOSED)) {
|
||||
LogInfo("Client disconnected from the server, removing client");
|
||||
delete (*iter);
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientManager::RemoveExistingClient(unsigned int account_id)
|
||||
/**
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
*/
|
||||
void ClientManager::RemoveExistingClient(unsigned int account_id, const std::string &loginserver)
|
||||
{
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end())
|
||||
{
|
||||
if ((*iter)->GetAccountID() == account_id)
|
||||
{
|
||||
Log(Logs::General, Logs::Login_Server, "Client attempting to log in and existing client already logged in, removing existing client.");
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->GetAccountID() == account_id && (*iter)->GetLoginServerName().compare(loginserver) == 0) {
|
||||
LogInfo("Client attempting to log in existing client already logged in, removing existing client");
|
||||
delete (*iter);
|
||||
iter = clients.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Client *ClientManager::GetClient(unsigned int account_id)
|
||||
/**
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
Client *ClientManager::GetClient(unsigned int account_id, const std::string &loginserver)
|
||||
{
|
||||
Client *cur = nullptr;
|
||||
int count = 0;
|
||||
auto iter = clients.begin();
|
||||
while (iter != clients.end())
|
||||
{
|
||||
if ((*iter)->GetAccountID() == account_id)
|
||||
{
|
||||
cur = (*iter);
|
||||
count++;
|
||||
while (iter != clients.end()) {
|
||||
if ((*iter)->GetAccountID() == account_id && (*iter)->GetLoginServerName().compare(loginserver) == 0) {
|
||||
return (*iter);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "More than one client with a given account_id existed in the client list.");
|
||||
}
|
||||
return cur;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1,20 +1,23 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_CLIENTMANAGER_H
|
||||
#define EQEMU_CLIENTMANAGER_H
|
||||
|
||||
@ -27,44 +30,50 @@
|
||||
/**
|
||||
* Client manager class, holds all the client objects and does basic processing.
|
||||
*/
|
||||
class ClientManager
|
||||
{
|
||||
class ClientManager {
|
||||
public:
|
||||
/**
|
||||
* Constructor, sets up the stream factories and opcode managers.
|
||||
*/
|
||||
* Constructor: sets up the stream factories and opcode managers
|
||||
*/
|
||||
ClientManager();
|
||||
|
||||
/**
|
||||
* Destructor, shuts down the streams and opcode managers.
|
||||
*/
|
||||
* Destructor: shuts down the streams and opcode managers
|
||||
*/
|
||||
~ClientManager();
|
||||
|
||||
/**
|
||||
* Processes every client in the internal list, removes them if necessary.
|
||||
*/
|
||||
* Processes every client in the internal list, removes them if necessary.
|
||||
*/
|
||||
void Process();
|
||||
|
||||
/**
|
||||
* Removes a client with a certain account id.
|
||||
*/
|
||||
void RemoveExistingClient(unsigned int account_id);
|
||||
* Removes a client with a certain account id
|
||||
*
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
*/
|
||||
void RemoveExistingClient(unsigned int account_id, const std::string &loginserver);
|
||||
|
||||
/**
|
||||
* Gets a client (if exists) by their account id.
|
||||
*/
|
||||
Client *GetClient(unsigned int account_id);
|
||||
* Gets a client (if exists) by their account id
|
||||
*
|
||||
* @param account_id
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
Client *GetClient(unsigned int account_id, const std::string &loginserver);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Processes disconnected clients, removes them if necessary.
|
||||
*/
|
||||
* Processes disconnected clients, removes them if necessary
|
||||
*/
|
||||
void ProcessDisconnect();
|
||||
|
||||
std::list<Client*> clients;
|
||||
OpcodeManager *titanium_ops;
|
||||
std::list<Client *> clients;
|
||||
OpcodeManager *titanium_ops;
|
||||
EQ::Net::EQStreamManager *titanium_stream;
|
||||
OpcodeManager *sod_ops;
|
||||
OpcodeManager *sod_ops;
|
||||
EQ::Net::EQStreamManager *sod_stream;
|
||||
};
|
||||
|
||||
|
||||
@ -1,214 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Retrieves the variable we want from our title or theme
|
||||
* First gets the map from the title
|
||||
* Then gets the argument from the map we got from title
|
||||
*/
|
||||
std::string Config::GetVariable(std::string title, std::string parameter)
|
||||
{
|
||||
std::map<std::string, std::map<std::string, std::string> >::iterator iter = vars.find(title);
|
||||
if(iter != vars.end())
|
||||
{
|
||||
std::map<std::string, std::string>::iterator arg_iter = iter->second.find(parameter);
|
||||
if(arg_iter != iter->second.end())
|
||||
{
|
||||
return arg_iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file and passes it to the tokenizer
|
||||
* Then it parses the tokens returned and puts them into titles and variables.
|
||||
*/
|
||||
void Config::Parse(const char *file_name)
|
||||
{
|
||||
if(file_name == nullptr)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Config::Parse(), file_name passed was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
vars.clear();
|
||||
FILE *input = fopen(file_name, "r");
|
||||
if(input)
|
||||
{
|
||||
std::list<std::string> tokens;
|
||||
Tokenize(input, tokens);
|
||||
|
||||
char mode = 0;
|
||||
std::string title, param, arg;
|
||||
std::list<std::string>::iterator iter = tokens.begin();
|
||||
while(iter != tokens.end())
|
||||
{
|
||||
if((*iter).compare("[") == 0)
|
||||
{
|
||||
title.clear();
|
||||
bool first = true;
|
||||
++iter;
|
||||
if(iter == tokens.end())
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Config::Parse(), EOF before title done parsing.");
|
||||
fclose(input);
|
||||
vars.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
while((*iter).compare("]") != 0 && iter != tokens.end())
|
||||
{
|
||||
if(!first)
|
||||
{
|
||||
title += " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
|
||||
title += (*iter);
|
||||
++iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
if(mode == 0)
|
||||
{
|
||||
param = (*iter);
|
||||
mode++;
|
||||
}
|
||||
else if(mode == 1)
|
||||
{
|
||||
mode++;
|
||||
if((*iter).compare("=") != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Config::Parse(), invalid parse token where = should be.");
|
||||
fclose(input);
|
||||
vars.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = (*iter);
|
||||
mode = 0;
|
||||
std::map<std::string, std::map<std::string, std::string> >::iterator map_iter = vars.find(title);
|
||||
if(map_iter != vars.end())
|
||||
{
|
||||
map_iter->second[param] = arg;
|
||||
vars[title] = map_iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<std::string, std::string> var_map;
|
||||
var_map[param] = arg;
|
||||
vars[title] = var_map;
|
||||
}
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
fclose(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Config::Parse(), file was unable to be opened for parsing.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty basic lexical analyzer
|
||||
* Breaks up the input character stream into tokens and puts them into the list provided.
|
||||
* Ignores # as a line comment
|
||||
*/
|
||||
void Config::Tokenize(FILE *input, std::list<std::string> &tokens)
|
||||
{
|
||||
auto c = fgetc(input);
|
||||
std::string lexeme;
|
||||
|
||||
while(c != EOF)
|
||||
{
|
||||
if(isspace(c))
|
||||
{
|
||||
if(lexeme.size() > 0)
|
||||
{
|
||||
tokens.push_back(lexeme);
|
||||
lexeme.clear();
|
||||
}
|
||||
c = fgetc(input);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isalnum(c))
|
||||
{
|
||||
lexeme += c;
|
||||
c = fgetc(input);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '#':
|
||||
{
|
||||
if(lexeme.size() > 0)
|
||||
{
|
||||
tokens.push_back(lexeme);
|
||||
lexeme.clear();
|
||||
}
|
||||
|
||||
while(c != '\n' && c != EOF)
|
||||
{
|
||||
c = fgetc(input);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '[':
|
||||
case ']':
|
||||
case '=':
|
||||
{
|
||||
if(lexeme.size() > 0)
|
||||
{
|
||||
tokens.push_back(lexeme);
|
||||
lexeme.clear();
|
||||
}
|
||||
|
||||
lexeme += c;
|
||||
tokens.push_back(lexeme);
|
||||
lexeme.clear();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
lexeme += c;
|
||||
}
|
||||
}
|
||||
|
||||
c = fgetc(input);
|
||||
}
|
||||
|
||||
if(lexeme.size() > 0)
|
||||
{
|
||||
tokens.push_back(lexeme);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_CONFIG_H
|
||||
#define EQEMU_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Keeps track of all the configuration for the application with a small parser.
|
||||
* Note: This is not a thread safe class, but only parse writes to variables in the class.
|
||||
* Thus making it mostly safe so long as you're careful with where you call Parse()
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
Config() { }
|
||||
~Config() { }
|
||||
|
||||
/**
|
||||
* Parses the selected file for variables, will clear current variables if selected.
|
||||
*/
|
||||
virtual void Parse(const char *file_name);
|
||||
|
||||
/**
|
||||
* Gets a variable if it exists.
|
||||
*/
|
||||
std::string GetVariable(std::string title, std::string parameter);
|
||||
|
||||
protected:
|
||||
std::map<std::string, std::map<std::string, std::string> > vars;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Breaks our input up into tokens for Parse().
|
||||
* This is private because it's not intended to be overloaded by a derived class which
|
||||
* may get it's input from other places than a C file pointer. (a http get request for example).
|
||||
* The programmer of a derived class would be expected to make their own Tokenize function for their own Parse().
|
||||
*/
|
||||
void Tokenize(FILE* input, std::list<std::string> &tokens);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
768
loginserver/database.cpp
Normal file
768
loginserver/database.cpp
Normal file
@ -0,0 +1,768 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
|
||||
#include "database.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/util/uuid.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
/**
|
||||
* Initial connect
|
||||
*
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param host
|
||||
* @param port
|
||||
* @param name
|
||||
*/
|
||||
Database::Database(
|
||||
std::string user,
|
||||
std::string pass,
|
||||
std::string host,
|
||||
std::string port,
|
||||
std::string name
|
||||
)
|
||||
{
|
||||
this->user = user;
|
||||
this->pass = pass;
|
||||
this->host = host;
|
||||
this->name = name;
|
||||
|
||||
uint32 errnum = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!Open(
|
||||
host.c_str(),
|
||||
user.c_str(),
|
||||
pass.c_str(),
|
||||
name.c_str(),
|
||||
std::stoi(port),
|
||||
&errnum,
|
||||
errbuf
|
||||
)
|
||||
) {
|
||||
LogError("Failed to connect to database: Error: [{0}]", errbuf);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
LogStatus("Using database [{0}] at [{1}:{2}]", name, host, port);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deconstructor
|
||||
*/
|
||||
Database::~Database()
|
||||
{
|
||||
if (database) {
|
||||
mysql_close(database);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param password
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::GetLoginDataFromAccountInfo(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
std::string &password,
|
||||
unsigned int &id
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, account_password FROM login_accounts WHERE account_name = '{0}' AND source_loginserver = '{1}' LIMIT 1",
|
||||
EscapeString(name),
|
||||
EscapeString(loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
LogDebug(
|
||||
"Could not find account for name [{0}] login [{1}]",
|
||||
name,
|
||||
loginserver
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
id = atoi(row[0]);
|
||||
password = row[1];
|
||||
|
||||
LogDebug(
|
||||
"Found account for name [{0}] login [{1}]",
|
||||
name,
|
||||
loginserver
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @param ip
|
||||
* @param db_account_id
|
||||
* @param db_loginserver
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
bool Database::GetLoginTokenDataFromToken(
|
||||
const std::string &token,
|
||||
const std::string &ip,
|
||||
unsigned int &db_account_id,
|
||||
std::string &db_loginserver,
|
||||
std::string &user
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT tbllogintokens.Id, tbllogintokens.IpAddress, tbllogintokenclaims.Name, tbllogintokenclaims.Value FROM tbllogintokens "
|
||||
"JOIN tbllogintokenclaims ON tbllogintokens.Id = tbllogintokenclaims.TokenId WHERE tbllogintokens.Expires > NOW() "
|
||||
"AND tbllogintokens.Id='{0}' AND tbllogintokens.IpAddress='{1}'",
|
||||
EscapeString(token),
|
||||
EscapeString(ip)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.RowCount() == 0 || !results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found_username = false;
|
||||
bool found_login_id = false;
|
||||
bool found_login_server_name = false;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (strcmp(row[2], "username") == 0) {
|
||||
user = row[3];
|
||||
found_username = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(row[2], "login_server_id") == 0) {
|
||||
db_account_id = atoi(row[3]);
|
||||
found_login_id = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(row[2], "login_server_name") == 0) {
|
||||
db_loginserver = row[3];
|
||||
found_login_server_name = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return found_username && found_login_id && found_login_server_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
unsigned int Database::GetFreeID(const std::string &loginserver)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT IFNULL(MAX(id), 0) + 1 FROM login_accounts WHERE source_loginserver = '{0}'",
|
||||
EscapeString(loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return std::stoi(row[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateLoginData(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int &id
|
||||
)
|
||||
{
|
||||
uint32 free_id = GetFreeID(loginserver);
|
||||
id = free_id;
|
||||
|
||||
return CreateLoginDataWithID(name, password, loginserver, free_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
uint32 Database::CreateLoginAccount(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
const std::string &email
|
||||
)
|
||||
{
|
||||
uint32 free_id = GetFreeID(loginserver);
|
||||
|
||||
if (free_id <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
|
||||
"VALUES ({0}, '{1}', '{2}', '{3}', '{4}', NOW(), '127.0.0.1', NOW())",
|
||||
free_id,
|
||||
EscapeString(loginserver),
|
||||
EscapeString(name),
|
||||
EscapeString(password),
|
||||
EscapeString(email)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return (results.Success() ? free_id : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_account_name
|
||||
* @param in_account_password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateLoginDataWithID(
|
||||
const std::string &in_account_name,
|
||||
const std::string &in_account_password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
)
|
||||
{
|
||||
if (id == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
|
||||
"VALUES ({0}, '{1}', '{2}', '{3}', 'local_creation', NOW(), '127.0.0.1', NOW())",
|
||||
id,
|
||||
EscapeString(loginserver),
|
||||
EscapeString(in_account_name),
|
||||
EscapeString(in_account_password)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::DoesLoginServerAccountExist(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
)
|
||||
{
|
||||
if (id == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT account_name FROM login_accounts WHERE account_name = '{0}' AND source_loginserver = '{1}'",
|
||||
EscapeString(name),
|
||||
EscapeString(loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param hash
|
||||
*/
|
||||
void Database::UpdateLoginserverAccountPasswordHash(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
const std::string &hash
|
||||
)
|
||||
{
|
||||
LogDebug(
|
||||
"name [{0}] loginserver [{1}] hash [{2}]",
|
||||
name,
|
||||
loginserver,
|
||||
hash
|
||||
);
|
||||
|
||||
auto query = fmt::format(
|
||||
"UPDATE login_accounts SET account_password = '{0}' WHERE account_name = '{1}' AND source_loginserver = '{2}'",
|
||||
hash,
|
||||
EscapeString(name),
|
||||
EscapeString(loginserver)
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param short_name
|
||||
* @param login_world_server_admin_id
|
||||
* @return
|
||||
*/
|
||||
Database::DbWorldRegistration Database::GetWorldRegistration(
|
||||
const std::string &short_name,
|
||||
uint32 login_world_server_admin_id
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT\n"
|
||||
" WSR.id,\n"
|
||||
" WSR.tag_description,\n"
|
||||
" WSR.is_server_trusted,\n"
|
||||
" SLT.id,\n"
|
||||
" SLT.description,\n"
|
||||
" ifnull(WSR.login_server_admin_id, 0) AS login_server_admin_id\n"
|
||||
"FROM\n"
|
||||
" login_world_servers AS WSR\n"
|
||||
" JOIN login_server_list_types AS SLT ON WSR.login_server_list_type_id = SLT.id\n"
|
||||
"WHERE\n"
|
||||
" WSR.short_name = '{0}' AND WSR.login_server_admin_id = {1} LIMIT 1",
|
||||
EscapeString(short_name),
|
||||
login_world_server_admin_id
|
||||
);
|
||||
|
||||
Database::DbWorldRegistration world_registration{};
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return world_registration;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
world_registration.loaded = true;
|
||||
world_registration.server_id = std::stoi(row[0]);
|
||||
world_registration.server_description = row[1];
|
||||
world_registration.server_list_type = std::stoi(row[3]);
|
||||
world_registration.is_server_trusted = std::stoi(row[2]) > 0;
|
||||
world_registration.server_list_description = row[4];
|
||||
|
||||
int db_account_id = std::stoi(row[5]);
|
||||
if (db_account_id <= 0) {
|
||||
return world_registration;
|
||||
}
|
||||
|
||||
auto world_registration_query = fmt::format(
|
||||
"SELECT account_name, account_password FROM login_server_admins WHERE id = {0} LIMIT 1",
|
||||
db_account_id
|
||||
);
|
||||
|
||||
auto world_registration_results = QueryDatabase(world_registration_query);
|
||||
if (world_registration_results.Success() && world_registration_results.RowCount() == 1) {
|
||||
auto world_registration_row = world_registration_results.begin();
|
||||
world_registration.server_admin_account_name = world_registration_row[0];
|
||||
world_registration.server_admin_account_password = world_registration_row[1];
|
||||
}
|
||||
|
||||
return world_registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param ip_address
|
||||
*/
|
||||
void Database::UpdateLSAccountData(unsigned int id, std::string ip_address)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"UPDATE login_accounts SET last_ip_address = '{0}', last_login_date = NOW() where id = {1}",
|
||||
ip_address,
|
||||
id
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param password
|
||||
* @param email
|
||||
*/
|
||||
void Database::UpdateLSAccountInfo(
|
||||
unsigned int id,
|
||||
std::string name,
|
||||
std::string password,
|
||||
std::string email
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"REPLACE login_accounts SET id = {0}, account_name = '{1}', account_password = sha('{2}'), "
|
||||
"account_email = '{3}', last_ip_address = '0.0.0.0', last_login_date = now()",
|
||||
id,
|
||||
EscapeString(name),
|
||||
EscapeString(password),
|
||||
EscapeString(email)
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param long_name
|
||||
* @param ip_address
|
||||
*/
|
||||
void Database::UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"UPDATE login_world_servers SET last_login_date = NOW(), last_ip_address = '{0}', long_name = '{1}' WHERE id = {2}",
|
||||
ip_address,
|
||||
EscapeString(long_name),
|
||||
id
|
||||
);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateWorldRegistration(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
std::string server_remote_ip,
|
||||
unsigned int &id,
|
||||
unsigned int &server_admin_id
|
||||
)
|
||||
{
|
||||
auto results = QueryDatabase("SELECT IFNULL(max(id), 0) + 1 FROM login_world_servers");
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
id = std::stoi(row[0]);
|
||||
auto insert_query = fmt::format(
|
||||
"INSERT INTO login_world_servers SET id = {0}, long_name = '{1}', short_name = '{2}', last_ip_address = '{3}', \n"
|
||||
"login_server_list_type_id = 3, login_server_admin_id = {4}, is_server_trusted = 0, tag_description = ''",
|
||||
id,
|
||||
EscapeString(server_long_name),
|
||||
EscapeString(server_short_name),
|
||||
server_remote_ip,
|
||||
server_admin_id
|
||||
);
|
||||
|
||||
auto insert_results = QueryDatabase(insert_query);
|
||||
if (!insert_results.Success()) {
|
||||
LogError(
|
||||
"Failed to register world server {0} - {1}",
|
||||
server_long_name,
|
||||
server_short_name
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param long_name
|
||||
* @param short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
std::string Database::CreateLoginserverApiToken(
|
||||
bool write_mode,
|
||||
bool read_mode
|
||||
)
|
||||
{
|
||||
std::string token = EQ::Util::UUID::Generate().ToString();
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_api_tokens (token, can_write, can_read, created_at) VALUES ('{0}', {1}, {2}, NOW())",
|
||||
token,
|
||||
(write_mode ? "1" : "0"),
|
||||
(read_mode ? "1" : "0")
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param long_name
|
||||
* @param short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
MySQLRequestResult Database::GetLoginserverApiTokens()
|
||||
{
|
||||
return QueryDatabase("SELECT token, can_write, can_read FROM login_api_tokens");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_settings
|
||||
*/
|
||||
void Database::LoadLogSettings(EQEmuLogSys::LogSettings *log_settings)
|
||||
{
|
||||
std::string query =
|
||||
"SELECT "
|
||||
"log_category_id, "
|
||||
"log_category_description, "
|
||||
"log_to_console, "
|
||||
"log_to_file, "
|
||||
"log_to_gmsay "
|
||||
"FROM "
|
||||
"logsys_categories "
|
||||
"ORDER BY log_category_id";
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
int log_category_id = 0;
|
||||
|
||||
int *categories_in_database = new int[1000];
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
log_category_id = atoi(row[0]);
|
||||
if (log_category_id <= Logs::None || log_category_id >= Logs::MaxCategoryID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
log_settings[log_category_id].log_to_console = static_cast<uint8>(atoi(row[2]));
|
||||
log_settings[log_category_id].log_to_file = static_cast<uint8>(atoi(row[3]));
|
||||
log_settings[log_category_id].log_to_gmsay = static_cast<uint8>(atoi(row[4]));
|
||||
|
||||
/**
|
||||
* Determine if any output method is enabled for the category
|
||||
* and set it to 1 so it can used to check if category is enabled
|
||||
*/
|
||||
const bool log_to_console = log_settings[log_category_id].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[log_category_id].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[log_category_id].log_to_gmsay > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
||||
|
||||
if (is_category_enabled) {
|
||||
log_settings[log_category_id].is_category_enabled = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This determines whether or not the process needs to actually file log anything.
|
||||
* If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open
|
||||
*/
|
||||
if (log_settings[log_category_id].log_to_file > 0) {
|
||||
LogSys.file_logs_enabled = true;
|
||||
}
|
||||
|
||||
categories_in_database[log_category_id] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto inject categories that don't exist in the database...
|
||||
*/
|
||||
for (int log_index = Logs::AA; log_index != Logs::MaxCategoryID; log_index++) {
|
||||
if (categories_in_database[log_index] != 1) {
|
||||
|
||||
LogInfo(
|
||||
"New Log Category [{0}] doesn't exist... Automatically adding to [logsys_categories] table...",
|
||||
Logs::LogCategoryName[log_index]
|
||||
);
|
||||
|
||||
auto inject_query = fmt::format(
|
||||
"INSERT INTO logsys_categories "
|
||||
"(log_category_id, "
|
||||
"log_category_description, "
|
||||
"log_to_console, "
|
||||
"log_to_file, "
|
||||
"log_to_gmsay) "
|
||||
"VALUES "
|
||||
"({0}, '{1}', {2}, {3}, {4})",
|
||||
log_index,
|
||||
EscapeString(Logs::LogCategoryName[log_index]),
|
||||
std::to_string(log_settings[log_index].log_to_console),
|
||||
std::to_string(log_settings[log_index].log_to_file),
|
||||
std::to_string(log_settings[log_index].log_to_gmsay)
|
||||
);
|
||||
|
||||
QueryDatabase(inject_query);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] categories_in_database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @param account_password
|
||||
* @param first_name
|
||||
* @param last_name
|
||||
* @param email
|
||||
* @param ip_address
|
||||
* @return
|
||||
*/
|
||||
uint32 Database::CreateLoginserverWorldAdminAccount(
|
||||
const std::string &account_name,
|
||||
const std::string &account_password,
|
||||
const std::string &first_name,
|
||||
const std::string &last_name,
|
||||
const std::string &email,
|
||||
const std::string &ip_address
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO login_server_admins (account_name, account_password, first_name, last_name, email, registration_date, "
|
||||
"registration_ip_address) "
|
||||
"VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', NOW(), '{5}')",
|
||||
EscapeString(account_name),
|
||||
EscapeString(account_password),
|
||||
EscapeString(first_name),
|
||||
EscapeString(last_name),
|
||||
EscapeString(email),
|
||||
ip_address
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return (results.Success() ? results.LastInsertedID() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
bool Database::DoesLoginserverWorldAdminAccountExist(
|
||||
const std::string &account_name
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT account_name FROM login_server_admins WHERE account_name = '{0}' LIMIT 1",
|
||||
EscapeString(account_name)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return (results.RowCount() == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &account_name)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, account_name, account_password, first_name, last_name, email, registration_date, registration_ip_address"
|
||||
" FROM login_server_admins WHERE account_name = '{0}' LIMIT 1",
|
||||
EscapeString(account_name)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
Database::DbLoginServerAdmin login_server_admin{};
|
||||
if (results.RowCount() == 1) {
|
||||
auto row = results.begin();
|
||||
login_server_admin.loaded = true;
|
||||
login_server_admin.id = std::stoi(row[0]);
|
||||
login_server_admin.account_name = row[1];
|
||||
login_server_admin.account_password = row[2];
|
||||
login_server_admin.first_name = row[3];
|
||||
login_server_admin.last_name = row[4];
|
||||
login_server_admin.email = row[5];
|
||||
login_server_admin.registration_date = row[7];
|
||||
login_server_admin.registration_ip_address = row[8];
|
||||
}
|
||||
|
||||
return login_server_admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
|
||||
const std::string &account_name,
|
||||
const std::string &source_loginserver
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT id, account_name, account_password, account_email, source_loginserver, last_ip_address, last_login_date, "
|
||||
"created_at, updated_at"
|
||||
" FROM login_accounts WHERE account_name = '{0}' and source_loginserver = '{1}' LIMIT 1",
|
||||
EscapeString(account_name),
|
||||
EscapeString(source_loginserver)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
Database::DbLoginServerAccount login_server_account{};
|
||||
if (results.RowCount() == 1) {
|
||||
auto row = results.begin();
|
||||
login_server_account.loaded = true;
|
||||
login_server_account.id = std::stoi(row[0]);
|
||||
login_server_account.account_name = row[1];
|
||||
login_server_account.account_password = row[2];
|
||||
login_server_account.account_email = row[3];
|
||||
login_server_account.source_loginserver = row[4];
|
||||
login_server_account.last_ip_address = row[5];
|
||||
login_server_account.last_login_date = row[6];
|
||||
login_server_account.created_at = row[7];
|
||||
login_server_account.updated_at = row[8];
|
||||
}
|
||||
|
||||
return login_server_account;
|
||||
}
|
||||
@ -1,82 +1,291 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
#ifndef EQEMU_DATABASEMYSQL_H
|
||||
#define EQEMU_DATABASEMYSQL_H
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_DATABASE_H
|
||||
#define EQEMU_DATABASE_H
|
||||
#include "../common/dbcore.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#define EQEMU_MYSQL_ENABLED
|
||||
//#define EQEMU_POSTGRESQL_ENABLED
|
||||
|
||||
/**
|
||||
* Base database class, intended to be extended.
|
||||
*/
|
||||
class Database
|
||||
{
|
||||
class Database : public DBcore {
|
||||
public:
|
||||
Database() : user(""), pass(""), host(""), port(""), name("") { }
|
||||
virtual ~Database() { }
|
||||
|
||||
Database() { database = nullptr; }
|
||||
|
||||
/**
|
||||
* Returns true if the database successfully connected.
|
||||
*/
|
||||
virtual bool IsConnected() { return false; }
|
||||
* Constructor, tries to set our database to connect to the supplied options.
|
||||
*
|
||||
* @param user
|
||||
* @param pass
|
||||
* @param host
|
||||
* @param port
|
||||
* @param name
|
||||
*/
|
||||
Database(std::string user, std::string pass, std::string host, std::string port, std::string name);
|
||||
|
||||
/**
|
||||
* Retrieves the login data (password hash and account id) from the account name provided
|
||||
* Needed for client login procedure.
|
||||
* Returns true if the record was found, false otherwise.
|
||||
*/
|
||||
virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id) { return false; }
|
||||
|
||||
virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user) { return false; }
|
||||
|
||||
virtual bool CreateLoginData(const std::string &name, const std::string &password, unsigned int &id) { return false; }
|
||||
* Destructor, frees our database if needed.
|
||||
*/
|
||||
~Database();
|
||||
bool IsConnected() { return (database != nullptr); }
|
||||
|
||||
/**
|
||||
* Retrieves the world registration from the long and short names provided.
|
||||
* Needed for world login procedure.
|
||||
* Returns true if the record was found, false otherwise.
|
||||
*/
|
||||
virtual bool GetWorldRegistration(std::string long_name, std::string short_name, unsigned int &id, std::string &desc, unsigned int &list_id,
|
||||
unsigned int &trusted, std::string &list_desc, std::string &account, std::string &password) { return false; }
|
||||
* Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure.
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param password
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool GetLoginDataFromAccountInfo(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
std::string &password,
|
||||
unsigned int &id
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the ip address of the client with account id = id
|
||||
*/
|
||||
virtual void UpdateLSAccountData(unsigned int id, std::string ip_address) { }
|
||||
* @param token
|
||||
* @param ip
|
||||
* @param db_account_id
|
||||
* @param db_loginserver
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
bool GetLoginTokenDataFromToken(
|
||||
const std::string &token,
|
||||
const std::string &ip,
|
||||
unsigned int &db_account_id,
|
||||
std::string &db_loginserver,
|
||||
std::string &user
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates or creates the login server account with info from world server
|
||||
*/
|
||||
virtual void UpdateLSAccountInfo(unsigned int id, std::string name, std::string password, std::string email) { }
|
||||
* @param loginserver
|
||||
* @return
|
||||
*/
|
||||
unsigned int GetFreeID(const std::string &loginserver);
|
||||
|
||||
/**
|
||||
* Updates the ip address of the world with account id = id
|
||||
*/
|
||||
virtual void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address) { }
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool CreateLoginData(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int &id
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates new world registration for unregistered servers and returns new id
|
||||
*/
|
||||
virtual bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id) { return false; }
|
||||
* @param in_account_name
|
||||
* @param in_account_password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool CreateLoginDataWithID(
|
||||
const std::string &in_account_name,
|
||||
const std::string &in_account_password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param loginserver
|
||||
* @param hash
|
||||
*/
|
||||
void UpdateLoginserverAccountPasswordHash(
|
||||
const std::string &name,
|
||||
const std::string &loginserver,
|
||||
const std::string &hash);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool DoesLoginServerAccountExist(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver,
|
||||
unsigned int id
|
||||
);
|
||||
|
||||
struct DbWorldRegistration {
|
||||
bool loaded = false;
|
||||
int32 server_id = 0;
|
||||
int8 server_list_type = 3;
|
||||
bool is_server_trusted = false;
|
||||
std::string server_description;
|
||||
std::string server_list_description;
|
||||
std::string server_admin_account_name;
|
||||
std::string server_admin_account_password;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the world registration from the long and short names provided
|
||||
* Needed for world login procedure
|
||||
* Returns true if the record was found, false otherwise
|
||||
*
|
||||
* @param short_name
|
||||
* @param login_world_server_admin_id
|
||||
* @return
|
||||
*/
|
||||
Database::DbWorldRegistration GetWorldRegistration(
|
||||
const std::string &short_name,
|
||||
uint32 login_world_server_admin_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param ip_address
|
||||
*/
|
||||
void UpdateLSAccountData(unsigned int id, std::string ip_address);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param password
|
||||
* @param email
|
||||
*/
|
||||
void UpdateLSAccountInfo(unsigned int id, std::string name, std::string password, std::string email);
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param long_name
|
||||
* @param ip_address
|
||||
*/
|
||||
void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
||||
|
||||
/**
|
||||
* @param server_long_name
|
||||
* @param server_short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool CreateWorldRegistration(
|
||||
std::string server_long_name,
|
||||
std::string server_short_name,
|
||||
std::string server_remote_ip,
|
||||
unsigned int &id,
|
||||
unsigned int &server_admin_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @param log_settings
|
||||
*/
|
||||
void LoadLogSettings(EQEmuLogSys::LogSettings *log_settings);
|
||||
|
||||
/**
|
||||
* @param write_mode
|
||||
* @param read_mode
|
||||
* @return
|
||||
*/
|
||||
std::string CreateLoginserverApiToken(bool write_mode, bool read_mode);
|
||||
MySQLRequestResult GetLoginserverApiTokens();
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @param account_password
|
||||
* @param first_name
|
||||
* @param last_name
|
||||
* @param email
|
||||
* @param ip_address
|
||||
* @return
|
||||
*/
|
||||
uint32 CreateLoginserverWorldAdminAccount(
|
||||
const std::string &account_name,
|
||||
const std::string &account_password,
|
||||
const std::string &first_name,
|
||||
const std::string &last_name,
|
||||
const std::string &email,
|
||||
const std::string &ip_address
|
||||
);
|
||||
|
||||
/**
|
||||
* @param account_name
|
||||
* @return
|
||||
*/
|
||||
bool DoesLoginserverWorldAdminAccountExist(const std::string &account_name);
|
||||
|
||||
struct DbLoginServerAdmin {
|
||||
bool loaded = false;
|
||||
uint32 id;
|
||||
std::string account_name;
|
||||
std::string account_password;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::string email;
|
||||
std::string registration_date;
|
||||
std::string registration_ip_address;
|
||||
};
|
||||
|
||||
Database::DbLoginServerAdmin GetLoginServerAdmin(const std::string &account_name);
|
||||
|
||||
struct DbLoginServerAccount {
|
||||
bool loaded = false;
|
||||
uint32 id;
|
||||
std::string account_name;
|
||||
std::string account_password;
|
||||
std::string account_email;
|
||||
std::string source_loginserver;
|
||||
std::string last_login_date;
|
||||
std::string last_ip_address;
|
||||
std::string created_at;
|
||||
std::string updated_at;
|
||||
};
|
||||
|
||||
Database::DbLoginServerAccount GetLoginServerAccountByAccountName(
|
||||
const std::string &account_name,
|
||||
const std::string &source_loginserver = "local"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param password
|
||||
* @param loginserver
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
uint32 CreateLoginAccount(
|
||||
const std::string &name,
|
||||
const std::string &password,
|
||||
const std::string &loginserver = "local",
|
||||
const std::string &email = "local_creation"
|
||||
);
|
||||
|
||||
protected:
|
||||
std::string user, pass, host, port, name;
|
||||
MYSQL *database{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,362 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/global_define.h"
|
||||
#include "database.h"
|
||||
|
||||
#ifdef EQEMU_MYSQL_ENABLED
|
||||
#include "database_mysql.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/eqemu_logsys_fmt.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
DatabaseMySQL::DatabaseMySQL(std::string user, std::string pass, std::string host, std::string port, std::string name)
|
||||
{
|
||||
this->user = user;
|
||||
this->pass = pass;
|
||||
this->host = host;
|
||||
this->name = name;
|
||||
|
||||
database = mysql_init(nullptr);
|
||||
if (database)
|
||||
{
|
||||
char r = 1;
|
||||
mysql_options(database, MYSQL_OPT_RECONNECT, &r);
|
||||
if (!mysql_real_connect(database, host.c_str(), user.c_str(), pass.c_str(), name.c_str(), atoi(port.c_str()), nullptr, 0))
|
||||
{
|
||||
mysql_close(database);
|
||||
Log(Logs::General, Logs::Error, "Failed to connect to MySQL database. Error: %s", mysql_error(database));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Failed to create db object in MySQL database.");
|
||||
}
|
||||
}
|
||||
|
||||
DatabaseMySQL::~DatabaseMySQL()
|
||||
{
|
||||
if (database)
|
||||
{
|
||||
mysql_close(database);
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseMySQL::GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "SELECT LoginServerID, AccountPassword FROM " << server.options.GetAccountTable() << " WHERE AccountName = '";
|
||||
query << name;
|
||||
query << "'";
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
LogF(Logs::General, Logs::Error, "Mysql query failed: {0}", query.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
res = mysql_use_result(database);
|
||||
|
||||
if (res)
|
||||
{
|
||||
while ((row = mysql_fetch_row(res)) != nullptr)
|
||||
{
|
||||
id = atoi(row[0]);
|
||||
password = row[1];
|
||||
mysql_free_result(res);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DatabaseMySQL::GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "SELECT tbllogintokens.Id, tbllogintokens.IpAddress, tbllogintokenclaims.Name, tbllogintokenclaims.Value FROM tbllogintokens ";
|
||||
query << "JOIN tbllogintokenclaims ON tbllogintokens.Id = tbllogintokenclaims.TokenId WHERE tbllogintokens.Expires > NOW() AND tbllogintokens.Id='";
|
||||
query << EscapeString(token) << "' AND tbllogintokens.IpAddress='" << EscapeString(ip) << "'";
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
res = mysql_use_result(database);
|
||||
|
||||
bool found_username = false;
|
||||
bool found_login_id = false;
|
||||
if (res)
|
||||
{
|
||||
while ((row = mysql_fetch_row(res)) != nullptr)
|
||||
{
|
||||
if (strcmp(row[2], "username") == 0) {
|
||||
user = row[3];
|
||||
found_username = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(row[2], "login_server_id") == 0) {
|
||||
db_account_id = atoi(row[3]);
|
||||
found_login_id = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mysql_free_result(res);
|
||||
}
|
||||
|
||||
return found_username && found_login_id;
|
||||
}
|
||||
|
||||
bool DatabaseMySQL::CreateLoginData(const std::string &name, const std::string &password, unsigned int &id)
|
||||
{
|
||||
if (!database) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
|
||||
query << "INSERT INTO " << server.options.GetAccountTable() << " (AccountName, AccountPassword, AccountEmail, LastLoginDate, LastIPAddress) ";
|
||||
query << " VALUES('" << name << "', '" << password << "', 'local_creation', NOW(), '127.0.0.1'); ";
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0) {
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
id = mysql_insert_id(database);
|
||||
return true;
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DatabaseMySQL::GetWorldRegistration(std::string long_name, std::string short_name, unsigned int &id, std::string &desc, unsigned int &list_id,
|
||||
unsigned int &trusted, std::string &list_desc, std::string &account, std::string &password)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char escaped_short_name[101];
|
||||
unsigned long length;
|
||||
length = mysql_real_escape_string(database, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length());
|
||||
escaped_short_name[length + 1] = 0;
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "SELECT ifnull(WSR.ServerID,999999) AS ServerID, WSR.ServerTagDescription, ifnull(WSR.ServerTrusted,0) AS ServerTrusted, ifnull(SLT.ServerListTypeID,3) AS ServerListTypeID, ";
|
||||
query << "SLT.ServerListTypeDescription, ifnull(WSR.ServerAdminID,0) AS ServerAdminID FROM " << server.options.GetWorldRegistrationTable();
|
||||
query << " AS WSR JOIN " << server.options.GetWorldServerTypeTable() << " AS SLT ON WSR.ServerListTypeID = SLT.ServerListTypeID";
|
||||
query << " WHERE WSR.ServerShortName = '";
|
||||
query << escaped_short_name;
|
||||
query << "'";
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
res = mysql_use_result(database);
|
||||
if (res)
|
||||
{
|
||||
if ((row = mysql_fetch_row(res)) != nullptr)
|
||||
{
|
||||
id = atoi(row[0]);
|
||||
desc = row[1];
|
||||
trusted = atoi(row[2]);
|
||||
list_id = atoi(row[3]);
|
||||
list_desc = row[4];
|
||||
int db_account_id = atoi(row[5]);
|
||||
mysql_free_result(res);
|
||||
|
||||
if (db_account_id > 0)
|
||||
{
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "SELECT AccountName, AccountPassword FROM " << server.options.GetWorldAdminRegistrationTable();
|
||||
query << " WHERE ServerAdminID = " << db_account_id;
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
res = mysql_use_result(database);
|
||||
if (res)
|
||||
{
|
||||
if ((row = mysql_fetch_row(res)) != nullptr)
|
||||
{
|
||||
account = row[0];
|
||||
password = row[1];
|
||||
mysql_free_result(res);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void DatabaseMySQL::UpdateLSAccountData(unsigned int id, std::string ip_address)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "UPDATE " << server.options.GetAccountTable() << " SET LastIPAddress = '";
|
||||
query << ip_address;
|
||||
query << "', LastLoginDate = now() where LoginServerID = ";
|
||||
query << id;
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseMySQL::UpdateLSAccountInfo(unsigned int id, std::string name, std::string password, std::string email)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "REPLACE " << server.options.GetAccountTable() << " SET LoginServerID = ";
|
||||
query << id << ", AccountName = '" << name << "', AccountPassword = sha('";
|
||||
query << password << "'), AccountCreateDate = now(), AccountEmail = '" << email;
|
||||
query << "', LastIPAddress = '0.0.0.0', LastLoginDate = now()";
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseMySQL::UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char escaped_long_name[101];
|
||||
unsigned long length;
|
||||
length = mysql_real_escape_string(database, escaped_long_name, long_name.substr(0, 100).c_str(), long_name.substr(0, 100).length());
|
||||
escaped_long_name[length + 1] = 0;
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "UPDATE " << server.options.GetWorldRegistrationTable() << " SET ServerLastLoginDate = now(), ServerLastIPAddr = '";
|
||||
query << ip_address;
|
||||
query << "', ServerLongName = '";
|
||||
query << escaped_long_name;
|
||||
query << "' WHERE ServerID = ";
|
||||
query << id;
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseMySQL::CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id)
|
||||
{
|
||||
if (!database)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char escaped_long_name[201];
|
||||
char escaped_short_name[101];
|
||||
unsigned long length;
|
||||
length = mysql_real_escape_string(database, escaped_long_name, long_name.substr(0, 100).c_str(), long_name.substr(0, 100).length());
|
||||
escaped_long_name[length + 1] = 0;
|
||||
length = mysql_real_escape_string(database, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length());
|
||||
escaped_short_name[length + 1] = 0;
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "SELECT ifnull(max(ServerID),0) FROM " << server.options.GetWorldRegistrationTable();
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
res = mysql_use_result(database);
|
||||
if (res)
|
||||
{
|
||||
if ((row = mysql_fetch_row(res)) != nullptr)
|
||||
{
|
||||
id = atoi(row[0]) + 1;
|
||||
mysql_free_result(res);
|
||||
|
||||
std::stringstream query(std::stringstream::in | std::stringstream::out);
|
||||
query << "INSERT INTO " << server.options.GetWorldRegistrationTable() << " SET ServerID = " << id;
|
||||
query << ", ServerLongName = '" << escaped_long_name << "', ServerShortName = '" << escaped_short_name;
|
||||
query << "', ServerListTypeID = 3, ServerAdminID = 0, ServerTrusted = 0, ServerTagDescription = ''";
|
||||
|
||||
if (mysql_query(database, query.str().c_str()) != 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Log(Logs::General, Logs::Error, "World registration did not exist in the database for %s %s", long_name.c_str(), short_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,100 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_DATABASEMYSQL_H
|
||||
#define EQEMU_DATABASEMYSQL_H
|
||||
|
||||
#include "database.h"
|
||||
#ifdef EQEMU_MYSQL_ENABLED
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <mysql.h>
|
||||
|
||||
/**
|
||||
* Mysql Database class
|
||||
*/
|
||||
class DatabaseMySQL : public Database
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor, sets our database to null.
|
||||
*/
|
||||
DatabaseMySQL() { database = nullptr; }
|
||||
|
||||
/**
|
||||
* Constructor, tries to set our database to connect to the supplied options.
|
||||
*/
|
||||
DatabaseMySQL(std::string user, std::string pass, std::string host, std::string port, std::string name);
|
||||
|
||||
/**
|
||||
* Destructor, frees our database if needed.
|
||||
*/
|
||||
virtual ~DatabaseMySQL();
|
||||
|
||||
/**
|
||||
* @return Returns true if the database successfully connected.
|
||||
*/
|
||||
virtual bool IsConnected() { return (database != nullptr); }
|
||||
|
||||
/**
|
||||
* Retrieves the login data (password hash and account id) from the account name provided
|
||||
* Needed for client login procedure.
|
||||
* Returns true if the record was found, false otherwise.
|
||||
*/
|
||||
virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id);
|
||||
|
||||
virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user);
|
||||
|
||||
virtual bool CreateLoginData(const std::string &name, const std::string &password, unsigned int &id);
|
||||
|
||||
/**
|
||||
* Retrieves the world registration from the long and short names provided.
|
||||
* Needed for world login procedure.
|
||||
* Returns true if the record was found, false otherwise.
|
||||
*/
|
||||
virtual bool GetWorldRegistration(std::string long_name, std::string short_name, unsigned int &id, std::string &desc, unsigned int &list_id,
|
||||
unsigned int &trusted, std::string &list_desc, std::string &account, std::string &password);
|
||||
|
||||
/**
|
||||
* Updates the ip address of the client with account id = id
|
||||
*/
|
||||
virtual void UpdateLSAccountData(unsigned int id, std::string ip_address);
|
||||
|
||||
/**
|
||||
* Updates or creates the login server account with info from world server
|
||||
*/
|
||||
virtual void UpdateLSAccountInfo(unsigned int id, std::string name, std::string password, std::string email);
|
||||
|
||||
/**
|
||||
* Updates the ip address of the world with account id = id
|
||||
*/
|
||||
virtual void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
||||
|
||||
/**
|
||||
* Creates new world registration for unregistered servers and returns new id
|
||||
*/
|
||||
virtual bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id);
|
||||
protected:
|
||||
std::string user, pass, host, port, name;
|
||||
MYSQL *database;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1,234 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "../common/global_define.h"
|
||||
#include "database.h"
|
||||
|
||||
#ifdef EQEMU_POSTGRESQL_ENABLED
|
||||
#include "database_postgresql.h"
|
||||
#include "error_log.h"
|
||||
#include "login_server.h"
|
||||
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
#pragma comment(lib, "libpq.lib")
|
||||
|
||||
DatabasePostgreSQL::DatabasePostgreSQL(string user, string pass, string host, string port, string name)
|
||||
{
|
||||
db = nullptr;
|
||||
db = PQsetdbLogin(host.c_str(), port.c_str(), nullptr, nullptr, name.c_str(), user.c_str(), pass.c_str());
|
||||
if(!db)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Failed to connect to PostgreSQL Database.");
|
||||
}
|
||||
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Failed to connect to PostgreSQL Database.");
|
||||
PQfinish(db);
|
||||
db = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DatabasePostgreSQL::~DatabasePostgreSQL()
|
||||
{
|
||||
if(db)
|
||||
{
|
||||
PQfinish(db);
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabasePostgreSQL::GetLoginDataFromAccountName(string name, string &password, unsigned int &id)
|
||||
{
|
||||
if(!db)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL doesn't have automatic reconnection option like mysql
|
||||
* but it's easy to check and reconnect
|
||||
*/
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
PQreset(db);
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stringstream query(stringstream::in | stringstream::out);
|
||||
query << "SELECT LoginServerID, AccountPassword FROM " << server.options.GetAccountTable() << " WHERE AccountName = '";
|
||||
query << name;
|
||||
query << "'";
|
||||
|
||||
PGresult *res = PQexec(db, query.str().c_str());
|
||||
|
||||
char *error = PQresultErrorMessage(res);
|
||||
if(strlen(error) > 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error);
|
||||
PQclear(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(PQntuples(res) > 0)
|
||||
{
|
||||
id = atoi(PQgetvalue(res, 0, 0));
|
||||
password = PQgetvalue(res, 0, 1);
|
||||
PQclear(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DatabasePostgreSQL::GetWorldRegistration(string long_name, string short_name, unsigned int &id, string &desc, unsigned int &list_id,
|
||||
unsigned int &trusted, string &list_desc, string &account, string &password)
|
||||
{
|
||||
if(!db)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL doesn't have automatic reconnection option like mysql
|
||||
* but it's easy to check and reconnect
|
||||
*/
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
PQreset(db);
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stringstream query(stringstream::in | stringstream::out);
|
||||
query << "SELECT WSR.ServerID, WSR.ServerTagDescription, WSR.ServerTrusted, SLT.ServerListTypeID, ";
|
||||
query << "SLT.ServerListTypeDescription, SAR.AccountName, SAR.AccountPassword FROM " << server.options.GetWorldRegistrationTable();
|
||||
query << " AS WSR JOIN " << server.options.GetWorldServerTypeTable() << " AS SLT ON WSR.ServerListTypeID = SLT.ServerListTypeID JOIN ";
|
||||
query << server.options.GetWorldAdminRegistrationTable() << " AS SAR ON WSR.ServerAdminID = SAR.ServerAdminID WHERE WSR.ServerShortName";
|
||||
query << " = '";
|
||||
query << short_name;
|
||||
query << "'";
|
||||
|
||||
PGresult *res = PQexec(db, query.str().c_str());
|
||||
|
||||
char *error = PQresultErrorMessage(res);
|
||||
if(strlen(error) > 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetWorldRegistration(): %s", error);
|
||||
PQclear(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(PQntuples(res) > 0)
|
||||
{
|
||||
id = atoi(PQgetvalue(res, 0, 0));
|
||||
desc = PQgetvalue(res, 0, 1);
|
||||
trusted = atoi(PQgetvalue(res, 0, 2));
|
||||
list_id = atoi(PQgetvalue(res, 0, 3));
|
||||
list_desc = PQgetvalue(res, 0, 4);
|
||||
account = PQgetvalue(res, 0, 5);
|
||||
password = PQgetvalue(res, 0, 6);
|
||||
|
||||
PQclear(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DatabasePostgreSQL::UpdateLSAccountData(unsigned int id, string ip_address)
|
||||
{
|
||||
if(!db)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL doesn't have automatic reconnection option like mysql
|
||||
* but it's easy to check and reconnect
|
||||
*/
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
PQreset(db);
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stringstream query(stringstream::in | stringstream::out);
|
||||
query << "UPDATE " << server.options.GetAccountTable() << " SET LastIPAddress = '";
|
||||
query << ip_address;
|
||||
query << "', LastLoginDate = current_date where LoginServerID = ";
|
||||
query << id;
|
||||
PGresult *res = PQexec(db, query.str().c_str());
|
||||
|
||||
char *error = PQresultErrorMessage(res);
|
||||
if(strlen(error) > 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error);
|
||||
}
|
||||
PQclear(res);
|
||||
}
|
||||
|
||||
void DatabasePostgreSQL::UpdateWorldRegistration(unsigned int id, string long_name, string ip_address)
|
||||
{
|
||||
if(!db)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL doesn't have automatic reconnection option like mysql
|
||||
* but it's easy to check and reconnect
|
||||
*/
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
PQreset(db);
|
||||
if(PQstatus(db) != CONNECTION_OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stringstream query(stringstream::in | stringstream::out);
|
||||
query << "UPDATE " << server.options.GetWorldRegistrationTable() << " SET ServerLastLoginDate = current_date, ServerLastIPAddr = '";
|
||||
query << ip_address;
|
||||
query << "', ServerLongName = '";
|
||||
query << long_name;
|
||||
query << "' where ServerID = ";
|
||||
query << id;
|
||||
PGresult *res = PQexec(db, query.str().c_str());
|
||||
|
||||
char *error = PQresultErrorMessage(res);
|
||||
if(strlen(error) > 0)
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error);
|
||||
}
|
||||
PQclear(res);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,91 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_DATABASEPOSTGRESQL_H
|
||||
#define EQEMU_DATABASEPOSTGRESQL_H
|
||||
|
||||
#include "database.h"
|
||||
#ifdef EQEMU_POSTGRESQL_ENABLED
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
/**
|
||||
* PostgreSQL Database class
|
||||
*/
|
||||
class DatabasePostgreSQL : public Database
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor, sets our database to null.
|
||||
*/
|
||||
DatabasePostgreSQL() { db = nullptr; }
|
||||
|
||||
/**
|
||||
* Constructor, tries to set our database to connect to the supplied options.
|
||||
*/
|
||||
DatabasePostgreSQL(std::string user, std::string pass, std::string host, std::string port, std::string name);
|
||||
|
||||
/**
|
||||
* Destructor, frees our database if needed.
|
||||
*/
|
||||
virtual ~DatabasePostgreSQL();
|
||||
|
||||
/**
|
||||
* Returns true if the database successfully connected.
|
||||
*/
|
||||
virtual bool IsConnected() { return (db != nullptr); }
|
||||
|
||||
/**
|
||||
* Retrieves the login data (password hash and account id) from the account name provided
|
||||
* Needed for client login procedure.
|
||||
* Returns true if the record was found, false otherwise.
|
||||
*/
|
||||
virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id);
|
||||
|
||||
/**
|
||||
* Retrieves the world registration from the long and short names provided.
|
||||
* Needed for world login procedure.
|
||||
* Returns true if the record was found, false otherwise.
|
||||
*/
|
||||
virtual bool GetWorldRegistration(std::string long_name, std::string short_name, unsigned int &id, std::string &desc, unsigned int &list_id,
|
||||
unsigned int &trusted, std::string &list_desc, std::string &account, std::string &password);
|
||||
|
||||
/**
|
||||
* Updates the ip address of the client with account id = id
|
||||
*/
|
||||
virtual void UpdateLSAccountData(unsigned int id, std::string ip_address);
|
||||
|
||||
/**
|
||||
* Updates the ip address of the world with account id = id
|
||||
*/
|
||||
virtual void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
||||
|
||||
/**
|
||||
* Creates new world registration for unregistered servers and returns new id
|
||||
*/
|
||||
virtual bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id);
|
||||
protected:
|
||||
std::string user, pass, host, port, name;
|
||||
PGconn *db;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,51 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "../common/types.h"
|
||||
|
||||
enum EncryptionMode
|
||||
{
|
||||
EncryptionModeMD5 = 1,
|
||||
EncryptionModeMD5PassUser = 2,
|
||||
EncryptionModeMD5UserPass = 3,
|
||||
EncryptionModeMD5Triple = 4,
|
||||
EncryptionModeSHA = 5,
|
||||
EncryptionModeSHAPassUser = 6,
|
||||
EncryptionModeSHAUserPass = 7,
|
||||
EncryptionModeSHATriple = 8,
|
||||
EncryptionModeSHA512 = 9,
|
||||
EncryptionModeSHA512PassUser = 10,
|
||||
EncryptionModeSHA512UserPass = 11,
|
||||
EncryptionModeSHA512Triple = 12,
|
||||
EncryptionModeArgon2 = 13,
|
||||
EncryptionModeSCrypt = 14
|
||||
};
|
||||
|
||||
/**
|
||||
* @param mode
|
||||
* @return
|
||||
*/
|
||||
std::string GetEncryptionByModeId(uint32 mode);
|
||||
const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc);
|
||||
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
|
||||
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);
|
||||
|
||||
@ -1,20 +1,23 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMUCAPI__H
|
||||
#define EQEMUCAPI__H
|
||||
|
||||
|
||||
@ -1,46 +1,53 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
#include <utility>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_LOGINSERVER_H
|
||||
#define EQEMU_LOGINSERVER_H
|
||||
|
||||
#include "config.h"
|
||||
#include "../common/json_config.h"
|
||||
#include "database.h"
|
||||
#include "database_mysql.h"
|
||||
#include "database_postgresql.h"
|
||||
#include "encryption.h"
|
||||
#include "options.h"
|
||||
#include "server_manager.h"
|
||||
#include "client_manager.h"
|
||||
#include "loginserver_webserver.h"
|
||||
|
||||
/**
|
||||
* Login server struct, contains every variable for the server that needs to exist
|
||||
* outside the scope of main().
|
||||
*/
|
||||
* Login server struct, contains every variable for the server that needs to exist outside the scope of main()
|
||||
*/
|
||||
struct LoginServer
|
||||
{
|
||||
public:
|
||||
LoginServer() : config(nullptr), db(nullptr), server_manager(nullptr) { }
|
||||
LoginServer() : db(nullptr), server_manager(nullptr) {
|
||||
|
||||
Config *config;
|
||||
Database *db;
|
||||
Options options;
|
||||
ServerManager *server_manager;
|
||||
ClientManager *client_manager;
|
||||
}
|
||||
|
||||
EQ::JsonConfigFile config;
|
||||
Database *db;
|
||||
LoginserverWebserver::TokenManager *token_manager{};
|
||||
Options options;
|
||||
ServerManager *server_manager;
|
||||
ClientManager *client_manager{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,32 +1,35 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net)
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef EQEMU_LOGINSTRUCTURES_H
|
||||
#define EQEMU_LOGINSTRUCTURES_H
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct LoginChatMessage_Struct {
|
||||
short Unknown0;
|
||||
short Unknown0;
|
||||
uint32 Unknown1;
|
||||
uint32 Unknown2;
|
||||
uint32 Unknown3;
|
||||
uint8 Unknown4;
|
||||
char ChatMessage[1];
|
||||
uint8 Unknown4;
|
||||
char ChatMessage[1];
|
||||
};
|
||||
|
||||
struct LoginLoginRequest_Struct {
|
||||
@ -35,7 +38,7 @@ struct LoginLoginRequest_Struct {
|
||||
short unknown3;
|
||||
short unknown4;
|
||||
short unknown5;
|
||||
char unknown6[16];
|
||||
char unknown6[16];
|
||||
};
|
||||
|
||||
struct LoginAccepted_Struct {
|
||||
@ -44,28 +47,27 @@ struct LoginAccepted_Struct {
|
||||
short unknown3;
|
||||
short unknown4;
|
||||
short unknown5;
|
||||
char encrypt[80];
|
||||
char encrypt[80];
|
||||
};
|
||||
|
||||
struct LoginFailedAttempts_Struct
|
||||
{
|
||||
char message; //0x01
|
||||
char unknown2[7]; //0x00
|
||||
struct LoginFailedAttempts_Struct {
|
||||
char message; //0x01
|
||||
char unknown2[7]; //0x00
|
||||
uint32 lsid;
|
||||
char key[11]; //10 char + null term;
|
||||
char key[11]; //10 char + null term;
|
||||
uint32 failed_attempts;
|
||||
char unknown3[4]; //0x00, 0x00, 0x00, 0x03
|
||||
char unknown4[4]; //0x00, 0x00, 0x00, 0x02
|
||||
char unknown5[4]; //0xe7, 0x03, 0x00, 0x00
|
||||
char unknown6[4]; //0xff, 0xff, 0xff, 0xff
|
||||
char unknown7[4]; //0xa0, 0x05, 0x00, 0x00
|
||||
char unknown8[4]; //0x00, 0x00, 0x00, 0x02
|
||||
char unknown9[4]; //0xff, 0x03, 0x00, 0x00
|
||||
char unknown10[4]; //0x00, 0x00, 0x00, 0x00
|
||||
char unknown11[4]; //0x63, 0x00, 0x00, 0x00
|
||||
char unknown12[4]; //0x01, 0x00, 0x00, 0x00
|
||||
char unknown13[4]; //0x00, 0x00, 0x00, 0x00
|
||||
char unknown14[4]; //0x00, 0x00, 0x00, 0x00
|
||||
char unknown3[4]; //0x00, 0x00, 0x00, 0x03
|
||||
char unknown4[4]; //0x00, 0x00, 0x00, 0x02
|
||||
char unknown5[4]; //0xe7, 0x03, 0x00, 0x00
|
||||
char unknown6[4]; //0xff, 0xff, 0xff, 0xff
|
||||
char unknown7[4]; //0xa0, 0x05, 0x00, 0x00
|
||||
char unknown8[4]; //0x00, 0x00, 0x00, 0x02
|
||||
char unknown9[4]; //0xff, 0x03, 0x00, 0x00
|
||||
char unknown10[4]; //0x00, 0x00, 0x00, 0x00
|
||||
char unknown11[4]; //0x63, 0x00, 0x00, 0x00
|
||||
char unknown12[4]; //0x01, 0x00, 0x00, 0x00
|
||||
char unknown13[4]; //0x00, 0x00, 0x00, 0x00
|
||||
char unknown14[4]; //0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
struct LoginLoginFailed_Struct {
|
||||
@ -74,7 +76,7 @@ struct LoginLoginFailed_Struct {
|
||||
short unknown3;
|
||||
short unknown4;
|
||||
short unknown5;
|
||||
char unknown6[74];
|
||||
char unknown6[74];
|
||||
};
|
||||
|
||||
struct ServerListHeader_Struct {
|
||||
@ -86,8 +88,7 @@ struct ServerListHeader_Struct {
|
||||
uint32 NumberOfServers;
|
||||
};
|
||||
|
||||
struct PlayEverquestRequest_Struct
|
||||
{
|
||||
struct PlayEverquestRequest_Struct {
|
||||
uint16 Sequence;
|
||||
uint32 Unknown1;
|
||||
uint32 Unknown2;
|
||||
@ -95,18 +96,19 @@ struct PlayEverquestRequest_Struct
|
||||
};
|
||||
|
||||
struct PlayEverquestResponse_Struct {
|
||||
uint8 Sequence;
|
||||
uint8 Unknown1[9];
|
||||
uint8 Allowed;
|
||||
uint8 Sequence;
|
||||
uint8 Unknown1[9];
|
||||
uint8 Allowed;
|
||||
uint16 Message;
|
||||
uint8 Unknown2[3];
|
||||
uint8 Unknown2[3];
|
||||
uint32 ServerNumber;
|
||||
};
|
||||
|
||||
static const unsigned char FailedLoginResponseData[] = {
|
||||
0xf6, 0x85, 0x9c, 0x23, 0x57, 0x7e, 0x3e, 0x55, 0xb3, 0x4c, 0xf8, 0xc8, 0xcb, 0x77, 0xd5, 0x16,
|
||||
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3, 0x4c, 0xf8, 0xc8, 0xcb, 0x77, 0xd5, 0x16,
|
||||
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3 };
|
||||
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3
|
||||
};
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
@ -1,57 +0,0 @@
|
||||
DROP TABLE IF EXISTS tblLoginServerAccounts;
|
||||
CREATE TABLE IF NOT EXISTS tblLoginServerAccounts (
|
||||
LoginServerID integer unsigned NOT NULL auto_increment,
|
||||
AccountName varchar(30) NOT NULL,
|
||||
AccountPassword varchar(50) NOT NULL,
|
||||
AccountCreateDate timestamp default CURRENT_TIMESTAMP NOT NULL,
|
||||
AccountEmail varchar(100) NOT NULL,
|
||||
LastLoginDate datetime NOT NULL,
|
||||
LastIPAddress varchar(15) NOT NULL,
|
||||
PRIMARY KEY (LoginServerID, AccountName)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
insert into tblLoginServerAccounts (AccountName, AccountPassword, AccountEmail, LastLoginDate, LastIPAddress) values('Admin', sha('password'), 'admin@somewhere.com', now(), '127.0.0.1');
|
||||
|
||||
DROP TABLE IF EXISTS tblServerListType;
|
||||
CREATE TABLE IF NOT EXISTS tblServerListType (
|
||||
ServerListTypeID integer unsigned NOT NULL,
|
||||
ServerListTypeDescription varchar(20) NOT NULL,
|
||||
PRIMARY KEY (ServerListTypeID)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (1, 'Legends');
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (2, 'Preferred');
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (3, 'Standard');
|
||||
|
||||
DROP TABLE IF EXISTS tblServerAdminRegistration;
|
||||
CREATE TABLE IF NOT EXISTS tblServerAdminRegistration (
|
||||
ServerAdminID integer unsigned NOT NULL auto_increment,
|
||||
AccountName varchar(30) NOT NULL,
|
||||
AccountPassword varchar(30) NOT NULL,
|
||||
FirstName varchar(40) NOT NULL,
|
||||
LastName varchar(50) NOT NULL,
|
||||
Email varchar(100) NULL,
|
||||
RegistrationDate datetime NOT NULL,
|
||||
RegistrationIPAddr varchar(15) NOT NULL,
|
||||
PRIMARY KEY (ServerAdminID, Email)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
INSERT INTO tblServerAdminRegistration (AccountName, AccountPassword, FirstName, LastName, Email, RegistrationDate, RegistrationIPAddr) VALUES ('Admin', 'Password', 'Tom', 'Wilson', 'Tom.Wilson@gmail.com', now(), '0.0.0.0');
|
||||
|
||||
DROP TABLE IF EXISTS tblWorldServerRegistration;
|
||||
CREATE TABLE IF NOT EXISTS tblWorldServerRegistration (
|
||||
ServerID integer unsigned NOT NULL auto_increment,
|
||||
ServerLongName varchar(100) NOT NULL,
|
||||
ServerTagDescription varchar(50) NOT NULL DEFAULT '',
|
||||
ServerShortName varchar(25) NOT NULL,
|
||||
ServerListTypeID integer NOT NULL,
|
||||
ServerLastLoginDate datetime NULL,
|
||||
ServerLastIPAddr varchar(15) NULL,
|
||||
ServerAdminID integer NOT NULL,
|
||||
ServerTrusted integer NOT NULL,
|
||||
Note varchar(300) NULL,
|
||||
PRIMARY KEY (ServerID, ServerLongName)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
|
||||
INSERT INTO tblWorldServerRegistration (ServerLongName, ServerTagDescription, ServerShortName, ServerListTypeID, ServerLastLoginDate, ServerLastIPAddr, ServerAdminID, ServerTrusted, Note) VALUES ('My Test Server', 'A test server', 'MTST', 1, now(), '0.0.0.0', 1, 0, 'This is a note for the test server');
|
||||
@ -1,57 +0,0 @@
|
||||
DROP TABLE IF EXISTS tblLoginServerAccounts;
|
||||
CREATE TABLE tblLoginServerAccounts (
|
||||
LoginServerID SERIAL,
|
||||
AccountName text NOT NULL,
|
||||
AccountPassword text NOT NULL,
|
||||
AccountCreateDate date NOT NULL,
|
||||
AccountEmail text NOT NULL,
|
||||
LastLoginDate date NOT NULL,
|
||||
LastIPAddress text NOT NULL,
|
||||
PRIMARY KEY(LoginServerID, AccountName)
|
||||
);
|
||||
|
||||
insert into tblLoginServerAccounts (AccountName, AccountPassword, AccountEmail, AccountCreateDate, LastLoginDate, LastIPAddress) values('Admin', '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', 'admin@somewhere.com', current_date, current_date, '127.0.0.1');
|
||||
|
||||
DROP TABLE IF EXISTS tblServerListType;
|
||||
CREATE TABLE tblServerListType (
|
||||
ServerListTypeID integer NOT NULL,
|
||||
CHECK (ServerListTypeID >= 0),
|
||||
ServerListTypeDescription text NOT NULL,
|
||||
PRIMARY KEY (ServerListTypeID)
|
||||
);
|
||||
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (1, 'Legends');
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (2, 'Preferred');
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (3, 'Standard');
|
||||
|
||||
DROP TABLE IF EXISTS tblServerAdminRegistration;
|
||||
CREATE TABLE tblServerAdminRegistration (
|
||||
ServerAdminID SERIAL,
|
||||
AccountName text NOT NULL,
|
||||
AccountPassword text NOT NULL,
|
||||
FirstName text NOT NULL,
|
||||
LastName text NOT NULL,
|
||||
Email text NOT NULL,
|
||||
RegistrationDate date NOT NULL,
|
||||
RegistrationIPAddr text NOT NULL,
|
||||
PRIMARY KEY (ServerAdminID, Email)
|
||||
);
|
||||
|
||||
INSERT INTO tblServerAdminRegistration (AccountName, AccountPassword, FirstName, LastName, Email, RegistrationDate, RegistrationIPAddr) VALUES ('Admin', 'Password', 'Tom', 'Wilson', 'Tom.Wilson@gmail.com', current_date, '0.0.0.0');
|
||||
|
||||
DROP TABLE IF EXISTS tblWorldServerRegistration;
|
||||
CREATE TABLE tblWorldServerRegistration (
|
||||
ServerID SERIAL,
|
||||
ServerLongName text NOT NULL,
|
||||
ServerTagDescription text NOT NULL,
|
||||
ServerShortName text NOT NULL,
|
||||
ServerListTypeID integer NOT NULL,
|
||||
ServerLastLoginDate date NULL,
|
||||
ServerLastIPAddr text NOT NULL,
|
||||
ServerAdminID integer NOT NULL,
|
||||
ServerTrusted integer NOT NULL,
|
||||
Note text NOT NULL,
|
||||
PRIMARY KEY (ServerID, ServerLongName)
|
||||
);
|
||||
|
||||
INSERT INTO tblWorldServerRegistration (ServerLongName, ServerTagDescription, ServerShortName, ServerListTypeID, ServerLastLoginDate, ServerLastIPAddr, ServerAdminID, ServerTrusted, Note) VALUES ('My Test Server', 'A test server', 'MTST', 1, current_date, '0.0.0.0', 1, 0, 'This is a note for the test server');
|
||||
@ -1,35 +0,0 @@
|
||||
[database]
|
||||
host = localhost
|
||||
port = 3306
|
||||
db = eqemu
|
||||
user = user
|
||||
password = password
|
||||
subsystem = MySQL
|
||||
|
||||
[options]
|
||||
unregistered_allowed = TRUE
|
||||
reject_duplicate_servers = FALSE
|
||||
trace = TRUE
|
||||
world_trace = FALSE
|
||||
dump_packets_in = FALSE
|
||||
dump_packets_out = FALSE
|
||||
listen_port = 5998
|
||||
local_network = 192.168.1.
|
||||
|
||||
[security]
|
||||
plugin = EQEmuAuthCrypto
|
||||
mode = 5
|
||||
|
||||
[Titanium]
|
||||
port = 5998
|
||||
opcodes = login_opcodes.conf
|
||||
|
||||
[SoD]
|
||||
port = 5999
|
||||
opcodes = login_opcodes_sod.conf
|
||||
|
||||
[schema]
|
||||
account_table = tblLoginServerAccounts
|
||||
world_registration_table = tblWorldServerRegistration
|
||||
world_admin_registration_table = tblServerAdminRegistration
|
||||
world_server_type_table = tblServerListType
|
||||
39
loginserver/login_util/login.json
Normal file
39
loginserver/login_util/login.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"database": {
|
||||
"host": "mariadb", // database host
|
||||
"port": "3306", // database port
|
||||
"db": "peq", // database name
|
||||
"user": "eqemu", // database user
|
||||
"password": "eqemu" // database password
|
||||
},
|
||||
"account": {
|
||||
// ideal for local LAN setups, if you want a login attempt to automatically create an account
|
||||
// this will automatically create the account using the username and password if it doesn't exist
|
||||
"auto_create_accounts": true
|
||||
},
|
||||
"worldservers": {
|
||||
"unregistered_allowed": true, // allows worldservers to connect to your loginserver without server admin authentication
|
||||
"reject_duplicate_servers": false // if enabled, rejects duplicate worldservers
|
||||
},
|
||||
"web_api": {
|
||||
"enabled": true, // enable/disable embedded webserver api
|
||||
"port": 6000 // the port you want the web api to serve on (recommended not to change)
|
||||
},
|
||||
"security": {
|
||||
"mode": 14, // encryption mode (dont touch) (14=scrypt)
|
||||
"allow_password_login": true, // allows users to login via password, most cases, leave this on
|
||||
"allow_token_login": true // allows token based login directly from launching game
|
||||
},
|
||||
"logging": {
|
||||
"trace": false, // For debugging general packet messaging
|
||||
"world_trace": false, // For debugging world to loginserver messaging
|
||||
"dump_packets_in": false, // for debugging inbound packets
|
||||
"dump_packets_out": false // for debugging outbound packets
|
||||
},
|
||||
"client_configuration": {
|
||||
"titanium_port": 5998, // don't change
|
||||
"titanium_opcodes": "login_opcodes.conf", // opcodes for the titanium era clients
|
||||
"sod_port": 5999, // don't change
|
||||
"sod_opcodes": "login_opcodes_sod.conf" // opcodes for sod and higher era clients
|
||||
}
|
||||
}
|
||||
87
loginserver/login_util/login_old_to_new_schema_convert.sql
Normal file
87
loginserver/login_util/login_old_to_new_schema_convert.sql
Normal file
@ -0,0 +1,87 @@
|
||||
-- Because the old / legacy schema was mostly inconsistent with naming and overall data structure, we have
|
||||
-- migrated to a schema that follows our modern conventions and meanwhile fixes quite a few bugs that
|
||||
-- were present as well
|
||||
|
||||
-- Login Accounts
|
||||
|
||||
INSERT INTO
|
||||
login_accounts (
|
||||
id,
|
||||
account_name,
|
||||
account_password,
|
||||
account_email,
|
||||
source_loginserver,
|
||||
last_ip_address,
|
||||
last_login_date,
|
||||
created_at
|
||||
)
|
||||
SELECT
|
||||
LoginServerID,
|
||||
AccountName,
|
||||
AccountPassword,
|
||||
AccountEmail,
|
||||
'local',
|
||||
LastIPAddress,
|
||||
LastLoginDate,
|
||||
AccountCreateDate
|
||||
FROM
|
||||
tblLoginServerAccounts;
|
||||
|
||||
-- Server Admins
|
||||
|
||||
INSERT INTO
|
||||
login_server_admins (
|
||||
id,
|
||||
account_name,
|
||||
account_password,
|
||||
first_name,
|
||||
last_name,
|
||||
email,
|
||||
registration_date,
|
||||
registration_ip_address
|
||||
)
|
||||
SELECT
|
||||
ServerAdminID,
|
||||
AccountName,
|
||||
AccountPassword,
|
||||
FirstName,
|
||||
LastName,
|
||||
Email,
|
||||
RegistrationDate,
|
||||
RegistrationIPAddr
|
||||
FROM
|
||||
tblServerAdminRegistration;
|
||||
|
||||
-- World Servers
|
||||
|
||||
INSERT INTO
|
||||
login_world_servers (
|
||||
id,
|
||||
long_name,
|
||||
short_name,
|
||||
tag_description,
|
||||
login_server_list_type_id,
|
||||
last_login_date,
|
||||
last_ip_address,
|
||||
login_server_admin_id,
|
||||
is_server_trusted,
|
||||
note
|
||||
)
|
||||
SELECT
|
||||
`ServerID`,
|
||||
`ServerLongName`,
|
||||
`ServerShortName`,
|
||||
`ServerTagDescription`,
|
||||
`ServerListTypeID`,
|
||||
`ServerLastLoginDate`,
|
||||
`ServerLastIPAddr`,
|
||||
`ServerAdminID`,
|
||||
`ServerTrusted`,
|
||||
`Note`
|
||||
FROM
|
||||
tblWorldServerRegistration;
|
||||
|
||||
DROP TABLE tblLoginServerAccounts;
|
||||
DROP TABLE tblServerAdminRegistration;
|
||||
DROP TABLE tblWorldServerRegistration;
|
||||
DROP TABLE tblServerListType;
|
||||
64
loginserver/login_util/login_schema.sql
Normal file
64
loginserver/login_util/login_schema.sql
Normal file
@ -0,0 +1,64 @@
|
||||
DROP TABLE IF EXISTS `login_accounts`;
|
||||
CREATE TABLE `login_accounts` (
|
||||
`id` int(11) unsigned NOT NULL,
|
||||
`account_name` varchar(50) NOT NULL,
|
||||
`account_password` text NOT NULL,
|
||||
`account_email` varchar(100) NOT NULL,
|
||||
`source_loginserver` varchar(64) DEFAULT NULL,
|
||||
`last_ip_address` varchar(15) NOT NULL,
|
||||
`last_login_date` datetime NOT NULL,
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `source_loginserver_account_name` (`source_loginserver`,`account_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
DROP TABLE IF EXISTS `login_server_admins`;
|
||||
CREATE TABLE `login_server_admins` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`account_name` varchar(30) NOT NULL,
|
||||
`account_password` varchar(255) NOT NULL,
|
||||
`first_name` varchar(50) NOT NULL,
|
||||
`last_name` varchar(50) NOT NULL,
|
||||
`email` varchar(100) NOT NULL,
|
||||
`registration_date` datetime NOT NULL,
|
||||
`registration_ip_address` varchar(15) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
|
||||
|
||||
DROP TABLE IF EXISTS `login_server_list_types`;
|
||||
CREATE TABLE `login_server_list_types` (
|
||||
`id` int(10) unsigned NOT NULL,
|
||||
`description` varchar(60) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
INSERT INTO `login_server_list_types` (`id`, `description`) VALUES ('1', 'Legends'),
|
||||
('2', 'Preferred'),
|
||||
('3', 'Standard');
|
||||
|
||||
DROP TABLE IF EXISTS `login_world_servers`;
|
||||
CREATE TABLE `login_world_servers` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`long_name` varchar(100) NOT NULL,
|
||||
`short_name` varchar(100) NOT NULL,
|
||||
`tag_description` varchar(50) NOT NULL DEFAULT '',
|
||||
`login_server_list_type_id` int(11) NOT NULL,
|
||||
`last_login_date` datetime DEFAULT NULL,
|
||||
`last_ip_address` varchar(15) DEFAULT NULL,
|
||||
`login_server_admin_id` int(11) NOT NULL,
|
||||
`is_server_trusted` int(11) NOT NULL,
|
||||
`note` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
|
||||
|
||||
DROP TABLE IF EXISTS `login_api_tokens`;
|
||||
CREATE TABLE `login_api_tokens` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`token` varchar(200) DEFAULT NULL,
|
||||
`can_write` int(11) DEFAULT 0,
|
||||
`can_read` int(11) DEFAULT 0,
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
|
||||
@ -1,11 +0,0 @@
|
||||
DROP TABLE IF EXISTS tblLoginServerAccounts;
|
||||
CREATE TABLE IF NOT EXISTS tblLoginServerAccounts (
|
||||
LoginServerID integer unsigned NOT NULL auto_increment,
|
||||
AccountName varchar(30) NOT NULL,
|
||||
AccountPassword varchar(50) NOT NULL,
|
||||
AccountCreateDate timestamp default CURRENT_TIMESTAMP NOT NULL,
|
||||
AccountEmail varchar(100) NOT NULL,
|
||||
LastLoginDate datetime NOT NULL,
|
||||
LastIPAddress varchar(15) NOT NULL,
|
||||
PRIMARY KEY (LoginServerID, AccountName)
|
||||
) ENGINE=InnoDB;
|
||||
@ -1,12 +0,0 @@
|
||||
DROP TABLE IF EXISTS tblServerAdminRegistration;
|
||||
CREATE TABLE IF NOT EXISTS tblServerAdminRegistration (
|
||||
ServerAdminID integer unsigned NOT NULL auto_increment,
|
||||
AccountName varchar(30) NOT NULL,
|
||||
AccountPassword varchar(30) NOT NULL,
|
||||
FirstName varchar(40) NOT NULL,
|
||||
LastName varchar(50) NOT NULL,
|
||||
Email varchar(100) NULL,
|
||||
RegistrationDate datetime NOT NULL,
|
||||
RegistrationIPAddr varchar(15) NOT NULL,
|
||||
PRIMARY KEY (ServerAdminID, Email)
|
||||
) ENGINE=MyISAM;
|
||||
@ -1,10 +0,0 @@
|
||||
DROP TABLE IF EXISTS tblServerListType;
|
||||
CREATE TABLE IF NOT EXISTS tblServerListType (
|
||||
ServerListTypeID integer unsigned NOT NULL,
|
||||
ServerListTypeDescription varchar(20) NOT NULL,
|
||||
PRIMARY KEY (ServerListTypeID)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (1, 'Legends');
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (2, 'Preferred');
|
||||
INSERT INTO tblServerListType (ServerListTypeID, ServerListTypeDescription) VALUES (3, 'Standard');
|
||||
@ -1,14 +0,0 @@
|
||||
DROP TABLE IF EXISTS tblWorldServerRegistration;
|
||||
CREATE TABLE IF NOT EXISTS tblWorldServerRegistration (
|
||||
ServerID integer unsigned NOT NULL auto_increment,
|
||||
ServerLongName varchar(100) NOT NULL,
|
||||
ServerTagDescription varchar(50) NOT NULL DEFAULT '',
|
||||
ServerShortName varchar(25) NOT NULL,
|
||||
ServerListTypeID integer NOT NULL,
|
||||
ServerLastLoginDate datetime NULL,
|
||||
ServerLastIPAddr varchar(15) NULL,
|
||||
ServerAdminID integer NOT NULL,
|
||||
Note varchar(300) NULL,
|
||||
ServerTrusted int(11),
|
||||
PRIMARY KEY (ServerID, ServerLongName)
|
||||
) ENGINE=InnoDB;
|
||||
272
loginserver/loginserver_command_handler.cpp
Normal file
272
loginserver/loginserver_command_handler.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include "loginserver_command_handler.h"
|
||||
#include "../common/util/uuid.h"
|
||||
#include "login_server.h"
|
||||
#include "loginserver_webserver.h"
|
||||
#include "account_management.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
namespace LoginserverCommandHandler {
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void CommandHandler(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1) { return; }
|
||||
|
||||
argh::parser cmd;
|
||||
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
|
||||
EQEmuCommand::DisplayDebug(cmd);
|
||||
|
||||
/**
|
||||
* Declare command mapping
|
||||
*/
|
||||
auto function_map = EQEmuCommand::function_map;
|
||||
|
||||
/**
|
||||
* Register commands
|
||||
*/
|
||||
function_map["login-user:check-credentials"] = &LoginserverCommandHandler::CheckLoginserverUserCredentials;
|
||||
function_map["login-user:check-external-credentials"] = &LoginserverCommandHandler::CheckExternalLoginserverUserCredentials;
|
||||
function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
|
||||
function_map["login-user:update-credentials"] = &LoginserverCommandHandler::UpdateLoginserverUserCredentials;
|
||||
function_map["web-api-token:create"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
|
||||
function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
|
||||
function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
|
||||
|
||||
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Creates Loginserver API Token";
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> arguments = {};
|
||||
std::vector<std::string> options = {
|
||||
"--read",
|
||||
"--write"
|
||||
};
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
bool can_read = cmd[{"-r", "--read"}];
|
||||
bool can_write = cmd[{"-w", "--write"}];
|
||||
|
||||
if (!can_read || !can_write) {
|
||||
LogInfo("[{0}] --read or --write must be set or both!", __func__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string token = server.db->CreateLoginserverApiToken(can_write, can_read);
|
||||
if (!token.empty()) {
|
||||
LogInfo("[{0}] Created Loginserver API token [{1}]", __func__, token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Lists Loginserver API Tokens";
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &it : server.token_manager->loaded_api_tokens) {
|
||||
LogInfo(
|
||||
"token [{0}] can_write [{1}] can_read [{2}]",
|
||||
it.second.token,
|
||||
it.second.can_write,
|
||||
it.second.can_read
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Creates Local Loginserver Account";
|
||||
|
||||
std::vector<std::string> arguments = {
|
||||
"--username",
|
||||
"--password"
|
||||
};
|
||||
std::vector<std::string> options = {
|
||||
"--email=*"
|
||||
};
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
AccountManagement::CreateLoginServerAccount(
|
||||
cmd("--username").str(),
|
||||
cmd("--password").str(),
|
||||
cmd("--email").str()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Creates Loginserver World Administrator Account";
|
||||
|
||||
std::vector<std::string> arguments = {
|
||||
"--username",
|
||||
"--password",
|
||||
"--email"
|
||||
};
|
||||
std::vector<std::string> options = {};
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
AccountManagement::CreateLoginserverWorldAdminAccount(
|
||||
cmd("--username").str(),
|
||||
cmd("--password").str(),
|
||||
cmd("--email").str()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Check user login credentials";
|
||||
|
||||
std::vector<std::string> arguments = {
|
||||
"--username",
|
||||
"--password"
|
||||
};
|
||||
std::vector<std::string> options = {};
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
auto res = AccountManagement::CheckLoginserverUserCredentials(
|
||||
cmd("--username").str(),
|
||||
cmd("--password").str()
|
||||
);
|
||||
|
||||
LogInfo("Credentials were {0}", res == true ? "accepted" : "not accepted");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Change user login credentials";
|
||||
|
||||
std::vector<std::string> arguments = {
|
||||
"--username",
|
||||
"--password"
|
||||
};
|
||||
std::vector<std::string> options = {};
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
AccountManagement::UpdateLoginserverUserCredentials(
|
||||
cmd("--username").str(),
|
||||
cmd("--password").str()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
* @param description
|
||||
*/
|
||||
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||
{
|
||||
description = "Check user external login credentials";
|
||||
|
||||
std::vector<std::string> arguments = {
|
||||
"--username",
|
||||
"--password"
|
||||
};
|
||||
std::vector<std::string> options = {};
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
}
|
||||
|
||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||
|
||||
auto res = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
cmd("--username").str(),
|
||||
cmd("--password").str()
|
||||
);
|
||||
|
||||
LogInfo("Credentials were {0}", res ? "accepted" : "not accepted");
|
||||
}
|
||||
}
|
||||
39
loginserver/loginserver_command_handler.h
Normal file
39
loginserver/loginserver_command_handler.h
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iostream"
|
||||
#include "../common/cli/eqemu_command_handler.h"
|
||||
|
||||
#ifndef EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||
#define EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||
|
||||
namespace LoginserverCommandHandler {
|
||||
void CommandHandler(int argc, char **argv);
|
||||
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||
533
loginserver/loginserver_webserver.cpp
Normal file
533
loginserver/loginserver_webserver.cpp
Normal file
@ -0,0 +1,533 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "loginserver_webserver.h"
|
||||
#include "server_manager.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/json/json.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "account_management.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
namespace LoginserverWebserver {
|
||||
|
||||
constexpr static int HTTP_RESPONSE_OK = 200;
|
||||
constexpr static int HTTP_RESPONSE_BAD_REQUEST = 400;
|
||||
constexpr static int HTTP_RESPONSE_UNAUTHORIZED = 401;
|
||||
|
||||
/**
|
||||
* @param api
|
||||
*/
|
||||
void RegisterRoutes(httplib::Server &api)
|
||||
{
|
||||
server.token_manager = new LoginserverWebserver::TokenManager;
|
||||
server.token_manager->LoadApiTokens();
|
||||
|
||||
api.Get(
|
||||
"/v1/servers/list", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanRead(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value response;
|
||||
auto iter = server.server_manager->getWorldServers().begin();
|
||||
while (iter != server.server_manager->getWorldServers().end()) {
|
||||
Json::Value row;
|
||||
row["server_long_name"] = (*iter)->GetServerLongName();
|
||||
row["server_short_name"] = (*iter)->GetServerLongName();
|
||||
row["server_list_id"] = (*iter)->GetServerListID();
|
||||
row["server_status"] = (*iter)->GetStatus();
|
||||
row["zones_booted"] = (*iter)->GetZonesBooted();
|
||||
row["local_ip"] = (*iter)->GetLocalIP();
|
||||
row["remote_ip"] = (*iter)->GetRemoteIP();
|
||||
row["players_online"] = (*iter)->GetPlayersOnline();
|
||||
response.append(row);
|
||||
++iter;
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
|
||||
api.Post(
|
||||
"/v1/account/create", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanWrite(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
std::string email = request_body.get("email", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
response["error"] = "Username or password not set";
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 account_created_id = AccountManagement::CreateLoginServerAccount(username, password, email);
|
||||
if (account_created_id > 0) {
|
||||
response["message"] = "Account created successfully!";
|
||||
response["data"]["account_id"] = account_created_id;
|
||||
}
|
||||
else if (account_created_id == -1) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Account already exists!";
|
||||
}
|
||||
else {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Account failed to create!";
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
|
||||
api.Post(
|
||||
"/v1/account/create/external", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanWrite(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
std::string email = request_body.get("email", "").asString();
|
||||
uint32 login_account_id = request_body.get("login_account_id", "").asInt();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Username or password not set";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string source_loginserver = "eqemu";
|
||||
int32 account_created_id = AccountManagement::CreateLoginServerAccount(
|
||||
username,
|
||||
password,
|
||||
email,
|
||||
source_loginserver,
|
||||
login_account_id
|
||||
);
|
||||
|
||||
if (account_created_id > 0) {
|
||||
response["message"] = "Account created successfully!";
|
||||
response["data"]["account_id"] = account_created_id;
|
||||
}
|
||||
else if (account_created_id == -1) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Account already exists!";
|
||||
}
|
||||
else {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Account failed to create!";
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
|
||||
api.Post(
|
||||
"/v1/account/credentials/validate/local", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanRead(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Username or password not set";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 login_account_id = AccountManagement::CheckLoginserverUserCredentials(
|
||||
username,
|
||||
password
|
||||
);
|
||||
|
||||
if (login_account_id > 0) {
|
||||
response["message"] = "Credentials valid!";
|
||||
response["data"]["account_id"] = login_account_id;
|
||||
}
|
||||
else {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Credentials invalid!";
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
|
||||
api.Post(
|
||||
"/v1/account/credentials/update/local", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanWrite(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Username or password not set";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
||||
username
|
||||
);
|
||||
|
||||
if (!login_server_account.loaded) {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Failed to find associated loginserver account!";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
bool credentials_valid = AccountManagement::UpdateLoginserverUserCredentials(
|
||||
username,
|
||||
password
|
||||
);
|
||||
|
||||
if (credentials_valid) {
|
||||
response["message"] = "Loginserver account credentials updated!";
|
||||
}
|
||||
else {
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
response["error"] = "Failed to update loginserver account credentials!";
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
api.Post(
|
||||
"/v1/account/credentials/update/external", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanWrite(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
response["error"] = "Username or password not set";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string source_loginserver = "eqemu";
|
||||
|
||||
Database::DbLoginServerAccount
|
||||
login_server_account = server.db->GetLoginServerAccountByAccountName(
|
||||
username,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
if (!login_server_account.loaded) {
|
||||
response["error"] = "Failed to find associated loginserver account!";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
bool credentials_valid = AccountManagement::UpdateLoginserverUserCredentials(
|
||||
username,
|
||||
password,
|
||||
source_loginserver
|
||||
);
|
||||
|
||||
if (credentials_valid) {
|
||||
response["message"] = "Loginserver account credentials updated!";
|
||||
}
|
||||
else {
|
||||
response["error"] = "Failed to update loginserver account credentials!";
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
|
||||
api.Post(
|
||||
"/v1/account/credentials/validate/external", [](const httplib::Request &request, httplib::Response &res) {
|
||||
if (!LoginserverWebserver::TokenManager::AuthCanRead(request, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||
std::string username = request_body.get("username", "").asString();
|
||||
std::string password = request_body.get("password", "").asString();
|
||||
|
||||
Json::Value response;
|
||||
if (username.empty() || password.empty()) {
|
||||
response["error"] = "Username or password not set";
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||
username,
|
||||
password
|
||||
);
|
||||
|
||||
if (account_id > 0) {
|
||||
response["message"] = "Credentials valid!";
|
||||
response["data"]["account_id"] = account_id;
|
||||
}
|
||||
else {
|
||||
response["error"] = "Credentials invalid!";
|
||||
res.status = HTTP_RESPONSE_BAD_REQUEST;
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param payload
|
||||
* @param res
|
||||
*/
|
||||
void SendResponse(const Json::Value &payload, httplib::Response &res)
|
||||
{
|
||||
if (res.get_header_value("response_set") == "true") {
|
||||
res.set_header("response_set", "");
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream response_payload;
|
||||
|
||||
if (payload.empty()) {
|
||||
Json::Value response;
|
||||
response["message"] = "There were no results found";
|
||||
response_payload << response;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
return;
|
||||
}
|
||||
|
||||
response_payload << payload;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param payload
|
||||
* @param res
|
||||
*/
|
||||
Json::Value ParseRequestBody(const httplib::Request &request)
|
||||
{
|
||||
Json::Value request_body;
|
||||
|
||||
try {
|
||||
std::stringstream ss;
|
||||
ss.str(request.body);
|
||||
ss >> request_body;
|
||||
}
|
||||
catch (std::exception &) {
|
||||
request_body["error"] = "Payload invalid";
|
||||
|
||||
return request_body;
|
||||
}
|
||||
|
||||
return request_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param res
|
||||
*/
|
||||
bool LoginserverWebserver::TokenManager::AuthCanRead(const httplib::Request &request, httplib::Response &res)
|
||||
{
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||
|
||||
if (!user_token.can_read) {
|
||||
Json::Value response;
|
||||
std::stringstream response_payload;
|
||||
response["message"] = "Authorization token is either invalid or cannot read!";
|
||||
response_payload << response;
|
||||
|
||||
res.status = HTTP_RESPONSE_UNAUTHORIZED;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
res.set_header("response_set", "true");
|
||||
|
||||
LogWarning(
|
||||
"AuthCanRead access failure remote_address [{0}] user_agent [{1}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param res
|
||||
*/
|
||||
bool LoginserverWebserver::TokenManager::AuthCanWrite(const httplib::Request &request, httplib::Response &res)
|
||||
{
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||
|
||||
if (!user_token.can_write) {
|
||||
Json::Value response;
|
||||
std::stringstream response_payload;
|
||||
response["message"] = "Authorization token is either invalid or cannot write!";
|
||||
response_payload << response;
|
||||
|
||||
res.status = HTTP_RESPONSE_UNAUTHORIZED;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
res.set_header("response_set", "true");
|
||||
|
||||
LogWarning(
|
||||
"AuthCanWrite access failure remote_address [{0}] user_agent [{1}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(
|
||||
const httplib::Request &request
|
||||
)
|
||||
{
|
||||
std::string authorization_key;
|
||||
|
||||
LoginserverWebserver::TokenManager::token_data user_token{};
|
||||
|
||||
for (const auto &header : request.headers) {
|
||||
auto header_key = header.first;
|
||||
auto header_value = header.second;
|
||||
if (header_key == "Authorization") {
|
||||
authorization_key = header.second;
|
||||
find_replace(authorization_key, "Bearer ", "");
|
||||
if (LoginserverWebserver::TokenManager::TokenExists(authorization_key)) {
|
||||
user_token = server.token_manager->GetToken(authorization_key);
|
||||
}
|
||||
}
|
||||
|
||||
if (header_key == "REMOTE_ADDR") {
|
||||
user_token.remote_address = header.second;
|
||||
}
|
||||
|
||||
if (header_key == "User-Agent") {
|
||||
user_token.user_agent = header.second;
|
||||
}
|
||||
}
|
||||
|
||||
LogDebug(
|
||||
"Authentication Request | remote_address [{0}] user_agent [{1}] authorization_key [{2}] request_path [{3}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent,
|
||||
authorization_key,
|
||||
request.path
|
||||
);
|
||||
|
||||
return user_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads API Tokens
|
||||
*/
|
||||
void TokenManager::LoadApiTokens()
|
||||
{
|
||||
auto results = server.db->GetLoginserverApiTokens();
|
||||
int token_count = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
LoginserverWebserver::TokenManager::token_data token_data;
|
||||
token_data.token = row[0];
|
||||
token_data.can_write = std::stoi(row[1]) > 0;
|
||||
token_data.can_read = std::stoi(row[2]) > 0;
|
||||
|
||||
LogDebug(
|
||||
"Inserting api token to internal list [{0}] write {1} read {2}",
|
||||
token_data.token,
|
||||
token_data.can_read,
|
||||
token_data.can_write
|
||||
);
|
||||
|
||||
server.token_manager->loaded_api_tokens.insert(
|
||||
std::make_pair(
|
||||
token_data.token,
|
||||
token_data
|
||||
)
|
||||
);
|
||||
|
||||
token_count++;
|
||||
}
|
||||
|
||||
LogInfo("Loaded [{}] API token(s)", token_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
bool TokenManager::TokenExists(const std::string &token)
|
||||
{
|
||||
auto it = server.token_manager->loaded_api_tokens.find(token);
|
||||
|
||||
return !(it == server.token_manager->loaded_api_tokens.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
LoginserverWebserver::TokenManager::token_data TokenManager::GetToken(
|
||||
const std::string &token
|
||||
)
|
||||
{
|
||||
auto iter = server.token_manager->loaded_api_tokens.find(token);
|
||||
if (iter != server.token_manager->loaded_api_tokens.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
58
loginserver/loginserver_webserver.h
Normal file
58
loginserver/loginserver_webserver.h
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_LOGINSERVER_WEBSERVER_H
|
||||
#define EQEMU_LOGINSERVER_WEBSERVER_H
|
||||
|
||||
#include "../common/http/httplib.h"
|
||||
#include "../common/json/json.h"
|
||||
#include "../common/types.h"
|
||||
|
||||
namespace LoginserverWebserver {
|
||||
|
||||
class TokenManager {
|
||||
|
||||
public:
|
||||
TokenManager() = default;
|
||||
|
||||
struct token_data {
|
||||
std::string token;
|
||||
bool can_read;
|
||||
bool can_write;
|
||||
std::string user_agent;
|
||||
std::string remote_address;
|
||||
};
|
||||
|
||||
std::map<std::string, token_data> loaded_api_tokens{};
|
||||
|
||||
void LoadApiTokens();
|
||||
static bool TokenExists(const std::string &token);
|
||||
token_data GetToken(const std::string &token);
|
||||
static token_data CheckApiAuthorizationHeaders(const httplib::Request &request);
|
||||
static bool AuthCanRead(const httplib::Request &request, httplib::Response &res);
|
||||
static bool AuthCanWrite(const httplib::Request &request, httplib::Response &res);
|
||||
};
|
||||
|
||||
void RegisterRoutes(httplib::Server &api);
|
||||
void SendResponse(const Json::Value &payload, httplib::Response &res);
|
||||
static Json::Value ParseRequestBody(const httplib::Request &request);
|
||||
};
|
||||
|
||||
#endif //EQEMU_LOGINSERVER_WEBSERVER_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user