Merge fix

This commit is contained in:
KimLS 2019-09-17 20:56:22 -07:00
commit 8ae76bc217
231 changed files with 18003 additions and 13896 deletions

5
.gitignore vendored
View File

@ -30,4 +30,7 @@ vcpkg/
perl/
.idea/*
*cbp
*cbp
submodules/*
cmake-build-debug/

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
View 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));
}
}

View 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 &param : 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);
}
}

View 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

View 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_

View File

@ -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*/

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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*/

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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

View File

@ -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

View 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

View 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;
};
}
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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")
);
}

View File

@ -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

View File

@ -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 &parameter, 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 &parameter,
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 &parameter, const int default_value) {
/**
* @param title
* @param parameter
* @param default_value
* @return
*/
int EQ::JsonConfigFile::GetVariableInt(
const std::string &title,
const std::string &parameter,
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 &parameter, const bool default_value) {
/**
* @param title
* @param parameter
* @param default_value
* @return
*/
bool EQ::JsonConfigFile::GetVariableBool(
const std::string &title,
const std::string &parameter,
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 &parameter, const double default_value) {
/**
* @param title
* @param parameter
* @param default_value
* @return
*/
double EQ::JsonConfigFile::GetVariableDouble(
const std::string &title,
const std::string &parameter,
const double default_value
)
{
try {
if (m_root.isMember(title) && m_root[title].isMember(parameter)) {
return m_root[title][parameter].asDouble();

View File

@ -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 &parameter, const std::string &default_value);
int GetVariableInt(const std::string &title, const std::string &parameter, const int default_value);
@ -19,7 +21,6 @@ namespace EQ
Json::Value& RawHandle() { return m_root; }
private:
JsonConfigFile();
Json::Value m_root;
};

View File

@ -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; \
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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();
});

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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; \
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 "";
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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[];

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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();

View File

@ -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 ( &copy == 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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

View File

@ -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

View 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();
}

View 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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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
View 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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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');

View File

@ -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');

View File

@ -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

View 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
}
}

View 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;

View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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');

View File

@ -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;

View 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");
}
}

View 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

View 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 {};
}
}

View 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