mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-28 09:45:45 +00:00
Compare commits
171 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a66c3918a | |||
| a2c6252c58 | |||
| be00aa1b60 | |||
| b2658a6cbc | |||
| 026133f32a | |||
| 6d4f22a1c0 | |||
| e75f87a535 | |||
| 83e066bffc | |||
| 4639405fdf | |||
| 8ef3e87370 | |||
| bec28769aa | |||
| 8586cdc47e | |||
| 63ba5dc3ab | |||
| fcc7725ca3 | |||
| 5df6a61c96 | |||
| fc5105eed7 | |||
| 243fb781e8 | |||
| ec4d228dd5 | |||
| 2910073373 | |||
| b4d5e807e3 | |||
| 8f729fe948 | |||
| 7160aa651e | |||
| 8414ce02e3 | |||
| 17034a6e47 | |||
| be1772d464 | |||
| a00f086bb8 | |||
| de830e5535 | |||
| d1404a2d95 | |||
| 38da37755d | |||
| 57ac46d090 | |||
| 59f32b8d34 | |||
| a45117cd04 | |||
| 291aaea581 | |||
| 162d34e1d9 | |||
| 86c9be410d | |||
| 30e34c67b4 | |||
| ce8b8da0d6 | |||
| 02e8b125a4 | |||
| 11369247b1 | |||
| d493a6627b | |||
| b07945f0be | |||
| 8f3ac74196 | |||
| bcf7ccefcd | |||
| 9e9ef6809b | |||
| c8f6dbb86d | |||
| 7de50d0e60 | |||
| aaaee6c6a4 | |||
| d7f38361f2 | |||
| 275995a374 | |||
| 7072b5721b | |||
| 123bc5f19a | |||
| e6db71e31e | |||
| 129a738072 | |||
| 0de90dc135 | |||
| 5bc4cff7a9 | |||
| f9191d4ef4 | |||
| 49d751b3d5 | |||
| 14f48fcc93 | |||
| 25addc3bd9 | |||
| 7f12ad325a | |||
| 6636c64c82 | |||
| e2708af6f2 | |||
| 1de0c27629 | |||
| 9ccdb9eb84 | |||
| e69f7a6cf1 | |||
| efd04f8324 | |||
| eeacc62a91 | |||
| a7a525ed0b | |||
| e43538cf73 | |||
| 5b90d26a33 | |||
| 992e4ac59e | |||
| 6b85c914a5 | |||
| 089246db53 | |||
| f3e5423677 | |||
| 0e96099b3d | |||
| 6398381c44 | |||
| 7c1a139991 | |||
| 8554aab2ff | |||
| 77e72ba666 | |||
| 8329760632 | |||
| d8aa8f7e7a | |||
| 29cdd91ca0 | |||
| df99d97431 | |||
| f314e05087 | |||
| d120cf8a40 | |||
| 209b0eb273 | |||
| 763fc82379 | |||
| 6e0d101457 | |||
| a1a4f91ea6 | |||
| 6cc845e05e | |||
| 597e324319 | |||
| f370a6048f | |||
| 9d784d0d9b | |||
| fd7b15abb1 | |||
| b27428a6d8 | |||
| f201d4c999 | |||
| d9c41526e8 | |||
| 07b46ed445 | |||
| 9f9eaed983 | |||
| 862e1e33bf | |||
| dca34cc2ff | |||
| ccb316b11b | |||
| 10ae4ea8f6 | |||
| 7df9b2974b | |||
| 0b3065d7a9 | |||
| 7549fbbeea | |||
| e26eba8e03 | |||
| 02828a73b8 | |||
| 0e710fe5e7 | |||
| 86568e9292 | |||
| bf1d05d639 | |||
| 4eaf44fc33 | |||
| e62a283a79 | |||
| a847e461c1 | |||
| 37fefad58e | |||
| 26b26af8d7 | |||
| ee86001132 | |||
| 7d89c05a48 | |||
| 6e15fae6a0 | |||
| 2f962c2c8a | |||
| 6bbd1e94c3 | |||
| 78d44440eb | |||
| 1e45ffa24d | |||
| 37d5d96871 | |||
| 90725f9fd9 | |||
| c1aa3e7056 | |||
| 1d59fff2bf | |||
| 6beb220e93 | |||
| 3091a84540 | |||
| 9fbab76d40 | |||
| b03d47b9cd | |||
| b583d95f09 | |||
| 6846deb9c8 | |||
| adfec15893 | |||
| 132c936c90 | |||
| a0ed0d57c5 | |||
| 128e8ce08d | |||
| 55629ce396 | |||
| bf7c1252f8 | |||
| e2bfa44df0 | |||
| e5acc7c322 | |||
| 5aaaaed6f1 | |||
| 6d31786456 | |||
| 0aeab11408 | |||
| fc484d0b1c | |||
| 8dcc810b43 | |||
| 04f3d6286c | |||
| 35044becc1 | |||
| e08afb1234 | |||
| b2b87ea4e0 | |||
| 837c0a4385 | |||
| 9b075c28b6 | |||
| c4f05c3864 | |||
| 0c12ca8370 | |||
| a450779c91 | |||
| dc004c2a9d | |||
| d59dcb68ca | |||
| c7dbdfae58 | |||
| 759f9bd007 | |||
| 8f0b80097e | |||
| 71ae03d5bc | |||
| 34dc081306 | |||
| 35b35f85cf | |||
| 90da136b7a | |||
| 5b4aeaa457 | |||
| b02008ec53 | |||
| c709a6aa8e | |||
| 9113508269 | |||
| 1b7c12297d | |||
| b1311780a7 | |||
| 0d734a0837 |
+10
-1
@@ -7,10 +7,19 @@ name: EQEmulator Server Linux CI
|
||||
concurrency:
|
||||
limit: 1
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
host:
|
||||
path: /var/lib/cache
|
||||
|
||||
steps:
|
||||
- name: server-build
|
||||
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
|
||||
image: akkadius/eqemu-server:latest
|
||||
commands:
|
||||
- sudo chown eqemu:eqemu /drone/src/ * -R
|
||||
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
|
||||
- sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
|
||||
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LUA=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O0 -g -DNDEBUG" -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /home/eqemu/.ccache/
|
||||
|
||||
+1
-1
@@ -373,7 +373,7 @@ ENDIF()
|
||||
IF(PERL_LIBRARY_ENABLED)
|
||||
OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${PERL_LIBRARY_LIBS})
|
||||
SET(SERVER_LIBS ${SERVER_LIBS} ${PERL_LIBRARY_LIBS} perlbind)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${PERL_LIBRARY_INCLUDE}")
|
||||
ADD_DEFINITIONS(-DEMBPERL)
|
||||
ADD_DEFINITIONS(-DEMBPERL_PLUGIN)
|
||||
|
||||
@@ -7,6 +7,7 @@ SET(common_sources
|
||||
compression.cpp
|
||||
condition.cpp
|
||||
content/world_content_service.cpp
|
||||
discord/discord.cpp
|
||||
crash.cpp
|
||||
crc16.cpp
|
||||
crc32.cpp
|
||||
@@ -34,6 +35,7 @@ SET(common_sources
|
||||
event_sub.cpp
|
||||
expedition_lockout_timer.cpp
|
||||
extprofile.cpp
|
||||
discord_manager.cpp
|
||||
faction.cpp
|
||||
file_util.cpp
|
||||
guild_base.cpp
|
||||
@@ -491,6 +493,8 @@ SET(common_headers
|
||||
database_schema.h
|
||||
dbcore.h
|
||||
deity.h
|
||||
discord/discord.h
|
||||
discord_manager.h
|
||||
dynamic_zone_base.h
|
||||
emu_constants.h
|
||||
emu_limits.h
|
||||
|
||||
@@ -23,18 +23,18 @@
|
||||
|
||||
BasePacket::BasePacket(const unsigned char *buf, uint32 len)
|
||||
{
|
||||
this->pBuffer=nullptr;
|
||||
this->size=0;
|
||||
this->_wpos = 0;
|
||||
this->_rpos = 0;
|
||||
this->timestamp.tv_sec = 0;
|
||||
pBuffer=nullptr;
|
||||
size=0;
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
timestamp.tv_sec = 0;
|
||||
if (len>0) {
|
||||
this->size=len;
|
||||
size=len;
|
||||
pBuffer= new unsigned char[len];
|
||||
if (buf) {
|
||||
memcpy(this->pBuffer,buf,len);
|
||||
memcpy(pBuffer,buf,len);
|
||||
} else {
|
||||
memset(this->pBuffer,0,len);
|
||||
memset(pBuffer,0,len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -380,12 +380,12 @@ const char *GetClassIDName(uint8 class_id, uint8 level)
|
||||
return "Merchant";
|
||||
case DISCORD_MERCHANT:
|
||||
return "Discord Merchant";
|
||||
case ADVENTURERECRUITER:
|
||||
case ADVENTURE_RECRUITER:
|
||||
return "Adventure Recruiter";
|
||||
case ADVENTUREMERCHANT:
|
||||
case ADVENTURE_MERCHANT:
|
||||
return "Adventure Merchant";
|
||||
case CORPSE_CLASS:
|
||||
return "Corpse Class";
|
||||
case LDON_TREASURE:
|
||||
return "LDoN Treasure";
|
||||
case TRIBUTE_MASTER:
|
||||
return "Tribute Master";
|
||||
case GUILD_TRIBUTE_MASTER:
|
||||
@@ -400,7 +400,7 @@ const char *GetClassIDName(uint8 class_id, uint8 level)
|
||||
return "Fellowship Master";
|
||||
case ALT_CURRENCY_MERCHANT:
|
||||
return "Alternate Currency Merchant";
|
||||
case MERCERNARY_MASTER:
|
||||
case MERCENARY_MASTER:
|
||||
return "Mercenary Liaison";
|
||||
default:
|
||||
return "Unknown";
|
||||
|
||||
+4
-5
@@ -55,10 +55,9 @@
|
||||
#define BANKER 40
|
||||
#define MERCHANT 41
|
||||
#define DISCORD_MERCHANT 59
|
||||
#define ADVENTURERECRUITER 60
|
||||
#define ADVENTUREMERCHANT 61
|
||||
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs
|
||||
#define CORPSE_CLASS 62 // only seen on Danvi's Corpse in Akheva so far..
|
||||
#define ADVENTURE_RECRUITER 60
|
||||
#define ADVENTURE_MERCHANT 61
|
||||
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs, seen on Danvi's Corpse in Akheva
|
||||
#define TRIBUTE_MASTER 63
|
||||
#define GUILD_TRIBUTE_MASTER 64 // not sure
|
||||
#define GUILD_BANKER 66
|
||||
@@ -66,7 +65,7 @@
|
||||
#define DARK_REIGN_MERCHANT 68
|
||||
#define FELLOWSHIP_MASTER 69
|
||||
#define ALT_CURRENCY_MERCHANT 70
|
||||
#define MERCERNARY_MASTER 71
|
||||
#define MERCENARY_MASTER 71
|
||||
|
||||
|
||||
// player class values
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Expansion {
|
||||
VeilOfAlaris,
|
||||
RainOfFear,
|
||||
CallOfTheForsaken,
|
||||
TheDarkendSea,
|
||||
TheDarkenedSea,
|
||||
TheBrokenMirror,
|
||||
EmpiresOfKunark,
|
||||
RingOfScale,
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
bool IsVeilOfAlarisEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::VeilOfAlaris || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsRainOfFearEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::RainOfFear || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsCallOfTheForsakenEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::CallOfTheForsaken || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsTheDarkendSeaEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheDarkendSea || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsTheDarkenedSeaEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheDarkenedSea || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsTheBrokenMirrorEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::TheBrokenMirror || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsEmpiresOfKunarkEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::EmpiresOfKunark || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
bool IsRingOfScaleEnabled() { return GetCurrentExpansion() >= Expansion::ExpansionNumber::RingOfScale || GetCurrentExpansion() == Expansion::EXPANSION_ALL; }
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
bool IsCurrentExpansionVeilOfAlaris() { return current_expansion == Expansion::ExpansionNumber::VeilOfAlaris; }
|
||||
bool IsCurrentExpansionRainOfFear() { return current_expansion == Expansion::ExpansionNumber::RainOfFear; }
|
||||
bool IsCurrentExpansionCallOfTheForsaken() { return current_expansion == Expansion::ExpansionNumber::CallOfTheForsaken; }
|
||||
bool IsCurrentExpansionTheDarkendSea() { return current_expansion == Expansion::ExpansionNumber::TheDarkendSea; }
|
||||
bool IsCurrentExpansionTheDarkenedSea() { return current_expansion == Expansion::ExpansionNumber::TheDarkenedSea; }
|
||||
bool IsCurrentExpansionTheBrokenMirror() { return current_expansion == Expansion::ExpansionNumber::TheBrokenMirror; }
|
||||
bool IsCurrentExpansionEmpiresOfKunark() { return current_expansion == Expansion::ExpansionNumber::EmpiresOfKunark; }
|
||||
bool IsCurrentExpansionRingOfScale() { return current_expansion == Expansion::ExpansionNumber::RingOfScale; }
|
||||
|
||||
+185
-206
@@ -50,6 +50,8 @@
|
||||
#include "http/httplib.h"
|
||||
#include "http/uri.h"
|
||||
|
||||
#include "repositories/zone_repository.h"
|
||||
|
||||
extern Client client;
|
||||
|
||||
Database::Database () {
|
||||
@@ -92,112 +94,123 @@ Database::~Database()
|
||||
*/
|
||||
uint32 Database::CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus) {
|
||||
|
||||
if(strlen(name) >= 50 || strlen(password) >= 50)
|
||||
if (strlen(name) >= 50 || strlen(password) >= 50)
|
||||
return(0);
|
||||
|
||||
char tmpUN[100];
|
||||
char tmpPW[100];
|
||||
char temporary_username[100];
|
||||
char temporary_password[100];
|
||||
|
||||
DoEscapeString(tmpUN, name, strlen(name));
|
||||
DoEscapeString(tmpPW, password, strlen(password));
|
||||
DoEscapeString(temporary_username, name, strlen(name));
|
||||
DoEscapeString(temporary_password, password, strlen(password));
|
||||
|
||||
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, EscapeString(loginserver).c_str(), tmpPW, tmpPW);
|
||||
std::string query = fmt::format(
|
||||
"SELECT id, status FROM account WHERE `name` = '{}' AND ls_id = '{}' AND password is NOT NULL "
|
||||
"AND length(password) > 0 AND (password = '{}' OR password = MD5('{}'))",
|
||||
temporary_username,
|
||||
EscapeString(loginserver),
|
||||
temporary_password,
|
||||
temporary_password
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
uint32 id = atoi(row[0]);
|
||||
auto id = std::stoul(row[0]);
|
||||
|
||||
if (oStatus)
|
||||
*oStatus = atoi(row[1]);
|
||||
if (oStatus) {
|
||||
*oStatus = std::stoi(row[1]);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
//Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
|
||||
bool Database::CheckBannedIPs(const char* loginIP)
|
||||
bool Database::CheckBannedIPs(std::string login_ip)
|
||||
{
|
||||
std::string query = StringFormat("SELECT ip_address FROM banned_ips WHERE ip_address='%s'", loginIP);
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT ip_address FROM banned_ips WHERE ip_address = '{}'",
|
||||
login_ip
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success() || results.RowCount() != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Database::AddBannedIP(char* bannedIP, const char* notes) {
|
||||
std::string query = StringFormat("INSERT into banned_ips SET ip_address='%s', notes='%s'", bannedIP, notes);
|
||||
bool Database::AddBannedIP(std::string banned_ip, std::string notes) {
|
||||
auto query = fmt::format(
|
||||
"INSERT into banned_ips SET ip_address = '{}', notes = '{}'",
|
||||
EscapeString(banned_ip),
|
||||
EscapeString(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);
|
||||
bool Database::CheckGMIPs(std::string login_ip, uint32 account_id) {
|
||||
auto query = fmt::format(
|
||||
"SELECT * FROM `gm_ips` WHERE `ip_address` = '{}' AND `account_id` = {}",
|
||||
login_ip,
|
||||
account_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 1)
|
||||
if (results.RowCount() == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
void Database::LoginIP(uint32 account_id, std::string login_ip) {
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO account_ip SET accid = {}, ip = '{}' ON DUPLICATE KEY UPDATE count=count+1, lastused=now()",
|
||||
account_id,
|
||||
login_ip
|
||||
);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
int16 Database::CheckStatus(uint32 account_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"SELECT `status`, TIMESTAMPDIFF(SECOND, NOW(), `suspendeduntil`) FROM `account` WHERE `id` = %i",
|
||||
account_id);
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT `status`, TIMESTAMPDIFF(SECOND, NOW(), `suspendeduntil`) FROM `account` WHERE `id` = {}",
|
||||
account_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
if (!results.Success() || results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
int16 status = atoi(row[0]);
|
||||
int16 status = std::stoi(row[0]);
|
||||
int32 date_diff = 0;
|
||||
|
||||
if (row[1] != nullptr)
|
||||
date_diff = atoi(row[1]);
|
||||
if (row[1]) {
|
||||
date_diff = std::stoi(row[1]);
|
||||
}
|
||||
|
||||
if (date_diff > 0)
|
||||
if (date_diff > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -307,9 +320,7 @@ bool Database::SetAccountStatus(const std::string& account_name, int16 status)
|
||||
LogInfo("Account [{}] is attempting to be set to status [{}]", account_name, status);
|
||||
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
UPDATE account SET status = {} WHERE name = '{}'
|
||||
),
|
||||
"UPDATE account SET status = {} WHERE name = '{}'",
|
||||
status,
|
||||
account_name
|
||||
);
|
||||
@@ -807,36 +818,34 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
uint32 Database::GetAccountIDByName(const char* accname, const char *loginserver, int16* status, uint32* lsid) {
|
||||
if (!isAlphaNumeric(accname))
|
||||
uint32 Database::GetAccountIDByName(std::string account_name, std::string loginserver, int16* status, uint32* lsid) {
|
||||
if (!isAlphaNumeric(account_name.c_str())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 query = fmt::format(
|
||||
"SELECT `id`, `status`, `lsaccount_id` FROM `account` WHERE `name` = '{}' AND `ls_id` = '{}' LIMIT 1",
|
||||
EscapeString(account_name),
|
||||
EscapeString(loginserver)
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
auto account_id = std::stoul(row[0]);
|
||||
|
||||
uint32 id = atoi(row[0]);
|
||||
|
||||
if (status)
|
||||
*status = atoi(row[1]);
|
||||
|
||||
if (lsid) {
|
||||
if (row[2])
|
||||
*lsid = atoi(row[2]);
|
||||
else
|
||||
*lsid = 0;
|
||||
if (status) {
|
||||
*status = static_cast<int16>(std::stoi(row[1]));
|
||||
}
|
||||
|
||||
return id;
|
||||
if (lsid) {
|
||||
*lsid = row[2] ? std::stoul(row[2]) : 0;
|
||||
}
|
||||
|
||||
return account_id;
|
||||
}
|
||||
|
||||
void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID) {
|
||||
@@ -1100,21 +1109,6 @@ bool Database::GetZoneLongName(const char* short_name, char** long_name, char* f
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Database::GetZoneGraveyardID(uint32 zone_id, uint32 version) {
|
||||
|
||||
std::string query = StringFormat("SELECT graveyard_id FROM zone WHERE zoneidnumber='%u' AND (version=%i OR version=0) ORDER BY version DESC", zone_id, version);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1143,108 +1137,84 @@ bool Database::GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zon
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
uint8 Database::GetPEQZone(uint32 zone_id, uint32 version){
|
||||
std::string query = fmt::format(
|
||||
"SELECT peqzone FROM zone WHERE zoneidnumber = {} AND (version = {} OR version = 0) ORDER BY version DESC LIMIT 1",
|
||||
zone_id,
|
||||
version
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
return static_cast<uint8>(std::stoi(row[0]));
|
||||
}
|
||||
|
||||
bool Database::CheckNameFilter(const char* name, bool surname)
|
||||
bool Database::CheckNameFilter(std::string name, bool surname)
|
||||
{
|
||||
std::string str_name = name;
|
||||
name = str_tolower(name);
|
||||
|
||||
// the minimum 4 is enforced by the client too
|
||||
if (!name || strlen(name) < 4)
|
||||
{
|
||||
if (name.empty() || name.size() < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given name length is enforced by the client too
|
||||
if (!surname && strlen(name) > 15)
|
||||
{
|
||||
if (!surname && name.size() > 15) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < str_name.size(); i++)
|
||||
{
|
||||
if(!isalpha(str_name[i]))
|
||||
{
|
||||
for (size_t i = 0; i < name.size(); i++) {
|
||||
if (!isalpha(name[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < str_name.size(); ++x)
|
||||
{
|
||||
str_name[x] = tolower(str_name[x]);
|
||||
}
|
||||
|
||||
char c = '\0';
|
||||
uint8 num_c = 0;
|
||||
for(size_t x = 0; x < str_name.size(); ++x)
|
||||
{
|
||||
if(str_name[x] == c)
|
||||
{
|
||||
for (size_t x = 0; x < name.size(); ++x) {
|
||||
if (name[x] == c) {
|
||||
num_c++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
num_c = 1;
|
||||
c = str_name[x];
|
||||
c = name[x];
|
||||
}
|
||||
if(num_c > 2)
|
||||
{
|
||||
|
||||
if (num_c > 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string query("SELECT name FROM name_filter");
|
||||
std::string query = "SELECT name FROM name_filter";
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
// false through to true? shouldn't it be falls through to false?
|
||||
if (!results.Success()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto row = results.begin();row != results.end();++row)
|
||||
{
|
||||
std::string current_row = row[0];
|
||||
|
||||
for(size_t x = 0; x < current_row.size(); ++x)
|
||||
current_row[x] = tolower(current_row[x]);
|
||||
|
||||
if(str_name.find(current_row) != std::string::npos)
|
||||
for (auto row : results) {
|
||||
std::string current_row = str_tolower(row[0]);
|
||||
if (name.find(current_row) != std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::AddToNameFilter(const char* name) {
|
||||
|
||||
std::string query = StringFormat("INSERT INTO name_filter (name) values ('%s')", name);
|
||||
bool Database::AddToNameFilter(std::string name) {
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO name_filter (name) values ('{}')",
|
||||
name
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success() || !results.RowsAffected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowsAffected() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1332,16 +1302,16 @@ 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);
|
||||
bool Database::CheckUsedName(std::string name) {
|
||||
auto query = fmt::format(
|
||||
"SELECT `id` FROM `character_data` WHERE `name` = '{}'",
|
||||
name
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
if (!results.Success() || results.RowCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1499,41 +1469,25 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
|
||||
return base_cap;
|
||||
}
|
||||
|
||||
uint32 Database::GetCharacterInfo(
|
||||
const char *iName,
|
||||
uint32 *oAccID,
|
||||
uint32 *oZoneID,
|
||||
uint32 *oInstanceID,
|
||||
float *oX,
|
||||
float *oY,
|
||||
float *oZ
|
||||
)
|
||||
uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"SELECT `id`, `account_id`, `zone_id`, `zone_instance`, `x`, `y`, `z` FROM `character_data` WHERE `name` = '%s'",
|
||||
EscapeString(iName).c_str()
|
||||
auto query = fmt::format(
|
||||
"SELECT `id`, `account_id`, `zone_id`, `zone_instance` FROM `character_data` WHERE `name` = '{}'",
|
||||
EscapeString(character_name)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
auto character_id = std::stoul(row[0]);
|
||||
*account_id = std::stoul(row[1]);
|
||||
*zone_id = std::stoul(row[2]);
|
||||
*instance_id = std::stoul(row[3]);
|
||||
|
||||
auto row = results.begin();
|
||||
uint32 charid = atoi(row[0]);
|
||||
if (oAccID) { *oAccID = atoi(row[1]); }
|
||||
if (oZoneID) { *oZoneID = atoi(row[2]); }
|
||||
if (oInstanceID) { *oInstanceID = atoi(row[3]); }
|
||||
if (oX) { *oX = atof(row[4]); }
|
||||
if (oY) { *oY = atof(row[5]); }
|
||||
if (oZ) { *oZ = atof(row[6]); }
|
||||
|
||||
return charid;
|
||||
return character_id;
|
||||
}
|
||||
|
||||
bool Database::UpdateLiveChar(char* charname, uint32 account_id) {
|
||||
@@ -1657,29 +1611,36 @@ uint32 Database::GetGroupID(const char* name){
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
/* Is this really getting used properly... A half implementation ? Akkadius */
|
||||
char* Database::GetGroupLeaderForLogin(const char* name, char* leaderbuf) {
|
||||
strcpy(leaderbuf, "");
|
||||
std::string Database::GetGroupLeaderForLogin(std::string character_name) {
|
||||
uint32 group_id = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `groupid` FROM `group_id` WHERE `name` = '%s'", name);
|
||||
auto query = fmt::format(
|
||||
"SELECT `groupid` FROM `group_id` WHERE `name` = '{}'",
|
||||
character_name
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (row[0])
|
||||
group_id = atoi(row[0]);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
group_id = std::stoul(row[0]);
|
||||
}
|
||||
|
||||
if (group_id == 0)
|
||||
return leaderbuf;
|
||||
if (!group_id) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT `leadername` FROM `group_leaders` WHERE `gid` = '%u' LIMIT 1", group_id);
|
||||
query = fmt::format(
|
||||
"SELECT `leadername` FROM `group_leaders` WHERE `gid` = {} LIMIT 1",
|
||||
group_id
|
||||
);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (row[0])
|
||||
strcpy(leaderbuf, row[0]);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
return row[0];
|
||||
}
|
||||
|
||||
return leaderbuf;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
@@ -2274,28 +2235,32 @@ 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);
|
||||
}
|
||||
|
||||
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
std::string query = fmt::format(
|
||||
"SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
|
||||
auto query = fmt::format(
|
||||
"SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
|
||||
account_ip
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return RuleI(World, MaxClientsPerIP);
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return std::stoi(row[0]);
|
||||
}
|
||||
|
||||
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
auto query = fmt::format(
|
||||
"SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
|
||||
account_ip
|
||||
);
|
||||
|
||||
uint32 exemption_id = 0;
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
exemption_id = atoi(row[0]);
|
||||
exemption_id = std::stoul(row[0]);
|
||||
}
|
||||
|
||||
query = fmt::format(
|
||||
@@ -2304,13 +2269,14 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
exemption_amount
|
||||
);
|
||||
|
||||
if (exemption_id != 0) {
|
||||
if (exemption_id) {
|
||||
query = fmt::format(
|
||||
"UPDATE `ip_exemptions` SET `exemption_amount` = {} WHERE `exemption_ip` = '{}'",
|
||||
exemption_amount,
|
||||
account_ip
|
||||
);
|
||||
}
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
@@ -2528,3 +2494,16 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
|
||||
}
|
||||
}
|
||||
|
||||
uint8 Database::GetMinStatus(uint32 zone_id, uint32 instance_version)
|
||||
{
|
||||
auto zones = ZoneRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"zoneidnumber = {} AND (version = {} OR version = 0) ORDER BY version DESC LIMIT 1",
|
||||
zone_id,
|
||||
instance_version
|
||||
)
|
||||
);
|
||||
|
||||
return !zones.empty() ? zones[0].min_status : 0;
|
||||
}
|
||||
|
||||
+13
-15
@@ -88,7 +88,6 @@ public:
|
||||
|
||||
/* Character Creation */
|
||||
|
||||
bool AddToNameFilter(const char *name);
|
||||
bool CreateCharacter(
|
||||
uint32 account_id,
|
||||
char *name,
|
||||
@@ -121,18 +120,18 @@ public:
|
||||
|
||||
/* General Information Queries */
|
||||
|
||||
bool AddBannedIP(char* bannedIP, const char* notes); //Add IP address to the banned_ips table.
|
||||
bool AddGMIP(char* ip_address, char* name);
|
||||
bool CheckBannedIPs(const char* loginIP); //Check incoming connection against banned IP table.
|
||||
bool CheckGMIPs(const char* loginIP, uint32 account_id);
|
||||
bool CheckNameFilter(const char* name, bool surname = false);
|
||||
bool CheckUsedName(const char* name);
|
||||
bool AddBannedIP(std::string banned_ip, std::string notes); //Add IP address to the banned_ips table.
|
||||
bool AddToNameFilter(std::string name);
|
||||
bool CheckBannedIPs(std::string login_ip); //Check incoming connection against banned IP table.
|
||||
bool CheckGMIPs(std::string login_ip, uint32 account_id);
|
||||
bool CheckNameFilter(std::string name, bool surname = false);
|
||||
bool CheckUsedName(std::string name);
|
||||
|
||||
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
|
||||
uint32 GetAccountIDByChar(uint32 char_id);
|
||||
uint32 GetAccountIDByName(const char* accname, const char *loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetAccountIDByName(std::string account_name, std::string 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 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id);
|
||||
uint32 GetGuildIDByCharID(uint32 char_id);
|
||||
uint32 GetGroupIDByCharID(uint32 char_id);
|
||||
uint32 GetRaidIDByCharID(uint32 char_id);
|
||||
@@ -142,7 +141,7 @@ public:
|
||||
std::string GetCharNameByID(uint32 char_id);
|
||||
std::string GetNPCNameByID(uint32 npc_id);
|
||||
std::string GetCleanNPCNameByID(uint32 npc_id);
|
||||
void LoginIP(uint32 AccountID, const char* LoginIP);
|
||||
void LoginIP(uint32 account_id, std::string login_ip);
|
||||
|
||||
/* Instancing */
|
||||
|
||||
@@ -208,8 +207,8 @@ public:
|
||||
|
||||
/* Groups */
|
||||
|
||||
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
std::string GetGroupLeaderForLogin(std::string character_name);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
|
||||
uint32 GetGroupID(const char* name);
|
||||
|
||||
@@ -252,9 +251,8 @@ public:
|
||||
bool GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, uint32* graveyard_id = 0, uint32* maxclients = 0);
|
||||
bool LoadPTimers(uint32 charid, PTimerList &into);
|
||||
|
||||
uint32 GetZoneGraveyardID(uint32 zone_id, uint32 version);
|
||||
|
||||
uint8 GetPEQZone(uint32 zoneID, uint32 version);
|
||||
uint8 GetPEQZone(uint32 zone_id, uint32 version);
|
||||
uint8 GetMinStatus(uint32 zone_id, uint32 instance_version);
|
||||
uint8 GetRaceSkill(uint8 skillid, uint8 in_race);
|
||||
uint8 GetServerType();
|
||||
uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level);
|
||||
|
||||
@@ -163,6 +163,20 @@ std::string DatabaseDumpService::GetPlayerTablesList()
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
std::string DatabaseDumpService::GetBotTablesList()
|
||||
{
|
||||
std::string tables_list;
|
||||
std::vector<std::string> tables = DatabaseSchema::GetBotTables();
|
||||
for (const auto &table : tables) {
|
||||
tables_list += table + " ";
|
||||
}
|
||||
|
||||
return trim(tables_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@@ -317,6 +331,11 @@ void DatabaseDumpService::Dump()
|
||||
tables_to_dump += GetPlayerTablesList() + " ";
|
||||
dump_descriptor += "-player";
|
||||
}
|
||||
|
||||
if (IsDumpBotTables()) {
|
||||
tables_to_dump += GetBotTablesList() + " ";
|
||||
dump_descriptor += "-bots";
|
||||
}
|
||||
|
||||
if (IsDumpSystemTables()) {
|
||||
tables_to_dump += GetSystemTablesList() + " ";
|
||||
@@ -436,6 +455,7 @@ void DatabaseDumpService::Dump()
|
||||
// LogDebug("[{}] login", (IsDumpLoginServerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] player", (IsDumpPlayerTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] system", (IsDumpSystemTables() ? "true" : "false"));
|
||||
// LogDebug("[{}] bot", (IsDumpBotTables() ? "true" : "false"));
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpSystemTables() const
|
||||
@@ -577,3 +597,13 @@ void DatabaseDumpService::SetDumpStateTables(bool dump_state_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_state_tables = dump_state_tables;
|
||||
}
|
||||
|
||||
bool DatabaseDumpService::IsDumpBotTables() const
|
||||
{
|
||||
return dump_bot_tables;
|
||||
}
|
||||
|
||||
void DatabaseDumpService::SetDumpBotTables(bool dump_bot_tables)
|
||||
{
|
||||
DatabaseDumpService::dump_bot_tables = dump_bot_tables;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only);
|
||||
bool IsDumpStateTables() const;
|
||||
void SetDumpStateTables(bool dump_state_tables);
|
||||
bool IsDumpBotTables() const;
|
||||
void SetDumpBotTables(bool dump_bot_tables);
|
||||
|
||||
private:
|
||||
bool dump_all_tables = false;
|
||||
@@ -67,6 +69,7 @@ private:
|
||||
bool dump_with_compression = false;
|
||||
bool dump_output_to_console = false;
|
||||
bool dump_drop_table_syntax_only = false;
|
||||
bool dump_bot_tables = false;
|
||||
std::string dump_path;
|
||||
std::string dump_file_name;
|
||||
|
||||
@@ -75,6 +78,7 @@ private:
|
||||
std::string GetMySQLVersion();
|
||||
std::string GetBaseMySQLDumpCommand();
|
||||
std::string GetPlayerTablesList();
|
||||
std::string GetBotTablesList();
|
||||
std::string GetSystemTablesList();
|
||||
std::string GetStateTablesList();
|
||||
std::string GetContentTablesList();
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace DatabaseSchema {
|
||||
{"character_pet_buffs", "char_id"},
|
||||
{"character_pet_info", "char_id"},
|
||||
{"character_pet_inventory", "char_id"},
|
||||
{"character_peqzone_flags", "id"},
|
||||
{"character_potionbelt", "id"},
|
||||
{"character_skills", "id"},
|
||||
{"character_spells", "id"},
|
||||
@@ -129,6 +130,7 @@ namespace DatabaseSchema {
|
||||
"character_pet_buffs",
|
||||
"character_pet_info",
|
||||
"character_pet_inventory",
|
||||
"character_peqzone_flags",
|
||||
"character_potionbelt",
|
||||
"character_skills",
|
||||
"character_spells",
|
||||
@@ -373,6 +375,40 @@ namespace DatabaseSchema {
|
||||
"inventory_versions",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Gets all player bot tables
|
||||
* @note These tables have no content in the PEQ daily dump
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<std::string> GetBotTables()
|
||||
{
|
||||
return {
|
||||
"bot_buffs",
|
||||
"bot_command_settings",
|
||||
"bot_create_combinations",
|
||||
"bot_data",
|
||||
"bot_group_members",
|
||||
"bot_groups",
|
||||
"bot_guild_members",
|
||||
"bot_heal_rotation_members",
|
||||
"bot_heal_rotation_targets",
|
||||
"bot_heal_rotations",
|
||||
"bot_inspect_messages",
|
||||
"bot_inventories",
|
||||
"bot_owner_options",
|
||||
"bot_pet_buffs",
|
||||
"bot_pet_inventories",
|
||||
"bot_pets",
|
||||
"bot_spell_casting_chances",
|
||||
"bot_spells_entries",
|
||||
"bot_stances",
|
||||
"bot_timers",
|
||||
"vw_bot_character_mobs",
|
||||
"vw_bot_groups"
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -167,7 +167,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
|
||||
if ((strncasecmp(query, "select", 6) == 0)) {
|
||||
LogMySQLQuery(
|
||||
"{0} ({1} row{2} returned) ({3}s)",
|
||||
"{0}; -- ({1} row{2} returned) ({3}s)",
|
||||
query,
|
||||
requestResult.RowCount(),
|
||||
requestResult.RowCount() == 1 ? "" : "s",
|
||||
@@ -176,7 +176,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
}
|
||||
else {
|
||||
LogMySQLQuery(
|
||||
"{0} ({1} row{2} affected) ({3}s)",
|
||||
"{0}; -- ({1} row{2} affected) ({3}s)",
|
||||
query,
|
||||
requestResult.RowsAffected(),
|
||||
requestResult.RowsAffected() == 1 ? "" : "s",
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "discord.h"
|
||||
#include "../http/httplib.h"
|
||||
#include "../json/json.h"
|
||||
#include "../string_util.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
constexpr int MAX_RETRIES = 10;
|
||||
|
||||
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
|
||||
{
|
||||
// validate
|
||||
if (webhook_url.empty()) {
|
||||
LogDiscord("[webhook_url] is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
// validate
|
||||
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
|
||||
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
|
||||
return;
|
||||
}
|
||||
|
||||
// split
|
||||
auto s = SplitString(webhook_url, '/');
|
||||
|
||||
// url
|
||||
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
|
||||
std::string endpoint = replace_string(webhook_url, base_url, "");
|
||||
|
||||
// client
|
||||
httplib::Client cli(base_url.c_str());
|
||||
cli.set_connection_timeout(0, 15000000); // 15 sec
|
||||
cli.set_read_timeout(15, 0); // 15 seconds
|
||||
cli.set_write_timeout(15, 0); // 15 seconds
|
||||
httplib::Headers headers = {
|
||||
{"Content-Type", "application/json"}
|
||||
};
|
||||
|
||||
// payload
|
||||
Json::Value p;
|
||||
p["content"] = message;
|
||||
std::stringstream payload;
|
||||
payload << p;
|
||||
|
||||
bool retry = true;
|
||||
int retries = 0;
|
||||
int retry_timer = 1000;
|
||||
while (retry) {
|
||||
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
|
||||
if (res->status != 200 && res->status != 204) {
|
||||
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
|
||||
}
|
||||
if (res->status == 429) {
|
||||
if (!res->body.empty()) {
|
||||
std::stringstream ss(res->body);
|
||||
Json::Value response;
|
||||
|
||||
try {
|
||||
ss >> response;
|
||||
}
|
||||
catch (std::exception const &ex) {
|
||||
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
|
||||
}
|
||||
|
||||
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
|
||||
}
|
||||
|
||||
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
|
||||
}
|
||||
if (res->status == 204) {
|
||||
retry = false;
|
||||
}
|
||||
if (retries > MAX_RETRIES) {
|
||||
LogDiscord("Retries exceeded for message [{}]", message);
|
||||
retry = false;
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
|
||||
{
|
||||
if (category_id == Logs::LogCategory::MySQLQuery) {
|
||||
return fmt::format("```sql\n{}\n```", message);
|
||||
}
|
||||
|
||||
return message + "\n";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef EQEMU_DISCORD_H
|
||||
#define EQEMU_DISCORD_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include "../types.h"
|
||||
|
||||
class Discord {
|
||||
public:
|
||||
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
|
||||
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_DISCORD_H
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "discord_manager.h"
|
||||
#include "../common/discord/discord.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
|
||||
{
|
||||
webhook_queue_lock.lock();
|
||||
webhook_message_queue[webhook_id].emplace_back(message);
|
||||
webhook_queue_lock.unlock();
|
||||
}
|
||||
|
||||
constexpr int MAX_MESSAGE_LENGTH = 1900;
|
||||
|
||||
void DiscordManager::ProcessMessageQueue()
|
||||
{
|
||||
if (webhook_message_queue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
webhook_queue_lock.lock();
|
||||
for (auto &q: webhook_message_queue) {
|
||||
LogDiscord("Processing [{}] messages in queue for webhook ID [{}]...", q.second.size(), q.first);
|
||||
|
||||
auto webhook = LogSys.discord_webhooks[q.first];
|
||||
std::string message;
|
||||
|
||||
for (auto &m: q.second) {
|
||||
// next message would become too large
|
||||
bool next_message_too_large = ((int) m.length() + (int) message.length()) > MAX_MESSAGE_LENGTH;
|
||||
if (next_message_too_large) {
|
||||
Discord::SendWebhookMessage(
|
||||
message,
|
||||
webhook.webhook_url
|
||||
);
|
||||
message = "";
|
||||
}
|
||||
|
||||
message += m;
|
||||
|
||||
// one single message was too large
|
||||
// this should rarely happen but the message will need to be split
|
||||
if ((int) message.length() > MAX_MESSAGE_LENGTH) {
|
||||
for (unsigned mi = 0; mi < message.length(); mi += MAX_MESSAGE_LENGTH) {
|
||||
Discord::SendWebhookMessage(
|
||||
message.substr(mi, MAX_MESSAGE_LENGTH),
|
||||
webhook.webhook_url
|
||||
);
|
||||
}
|
||||
message = "";
|
||||
}
|
||||
}
|
||||
|
||||
// final flush
|
||||
if (!message.empty()) {
|
||||
Discord::SendWebhookMessage(
|
||||
message,
|
||||
webhook.webhook_url
|
||||
);
|
||||
}
|
||||
|
||||
webhook_message_queue.erase(q.first);
|
||||
}
|
||||
webhook_queue_lock.unlock();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef EQEMU_DISCORD_MANAGER_H
|
||||
#define EQEMU_DISCORD_MANAGER_H
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/types.h"
|
||||
|
||||
class DiscordManager {
|
||||
public:
|
||||
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
|
||||
void ProcessMessageQueue();
|
||||
private:
|
||||
std::mutex webhook_queue_lock{};
|
||||
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
+74
-24
@@ -22,7 +22,6 @@
|
||||
#include "data_verification.h"
|
||||
#include "bodytypes.h"
|
||||
|
||||
|
||||
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
|
||||
static const int16 local_array[] = {
|
||||
POSSESSIONS_SIZE,
|
||||
@@ -189,15 +188,16 @@ const std::map<int, std::string>& EQ::constants::GetLanguageMap()
|
||||
{ LANG_HADAL, "Hadal" },
|
||||
{ LANG_UNKNOWN, "Unknown" }
|
||||
};
|
||||
|
||||
return language_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetLanguageName(int language_id)
|
||||
{
|
||||
if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
|
||||
auto languages = EQ::constants::GetLanguageMap();
|
||||
return languages[language_id];
|
||||
return EQ::constants::GetLanguageMap().find(language_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -211,21 +211,22 @@ const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
|
||||
{ LDoNThemes::RUJ, "Rujarkian Hills" },
|
||||
{ LDoNThemes::TAK, "Takish-Hiz" },
|
||||
};
|
||||
|
||||
return ldon_theme_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
|
||||
{
|
||||
if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
|
||||
auto ldon_themes = EQ::constants::GetLDoNThemeMap();
|
||||
return ldon_themes[theme_id];
|
||||
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> flymode_map = {
|
||||
static const std::map<int8, std::string> flymode_map = {
|
||||
{ GravityBehavior::Ground, "Ground" },
|
||||
{ GravityBehavior::Flying, "Flying" },
|
||||
{ GravityBehavior::Levitating, "Levitating" },
|
||||
@@ -233,15 +234,16 @@ const std::map<uint8, std::string>& EQ::constants::GetFlyModeMap()
|
||||
{ GravityBehavior::Floating, "Floating" },
|
||||
{ GravityBehavior::LevitateWhileRunning, "Levitating While Running" },
|
||||
};
|
||||
|
||||
return flymode_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetFlyModeName(uint8 flymode_id)
|
||||
std::string EQ::constants::GetFlyModeName(int8 flymode_id)
|
||||
{
|
||||
if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
|
||||
auto flymodes = EQ::constants::GetFlyModeMap();
|
||||
return flymodes[flymode_id];
|
||||
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -288,15 +290,16 @@ const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
|
||||
{ BT_InvisMan, "Invisible Man" },
|
||||
{ BT_Special, "Special" },
|
||||
};
|
||||
|
||||
return bodytype_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetBodyTypeName(bodyType bodytype_id)
|
||||
{
|
||||
auto bodytypes = EQ::constants::GetBodyTypeMap();
|
||||
if (!bodytypes[bodytype_id].empty()) {
|
||||
return bodytypes[bodytype_id];
|
||||
if (EQ::constants::GetBodyTypeMap().find(bodytype_id) != EQ::constants::GetBodyTypeMap().end()) {
|
||||
return EQ::constants::GetBodyTypeMap().find(bodytype_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -321,21 +324,23 @@ const std::map<uint8, std::string>& EQ::constants::GetAccountStatusMap()
|
||||
{ AccountStatus::GMImpossible, "GM Impossible" },
|
||||
{ AccountStatus::Max, "GM Max" }
|
||||
};
|
||||
|
||||
return account_status_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetAccountStatusName(uint8 account_status)
|
||||
{
|
||||
auto account_statuses = EQ::constants::GetAccountStatusMap();
|
||||
std::string status_name;
|
||||
for (auto status_level = account_statuses.rbegin(); status_level != account_statuses.rend(); ++status_level) {
|
||||
for (
|
||||
auto status_level = EQ::constants::GetAccountStatusMap().rbegin();
|
||||
status_level != EQ::constants::GetAccountStatusMap().rend();
|
||||
++status_level
|
||||
) {
|
||||
if (account_status >= status_level->first) {
|
||||
status_name = status_level->second;
|
||||
break;
|
||||
return status_level->second;
|
||||
}
|
||||
}
|
||||
|
||||
return status_name;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||
@@ -351,15 +356,16 @@ const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||
{ ConsiderLevel::Threateningly, "Threateningly" },
|
||||
{ ConsiderLevel::Scowls, "Scowls" }
|
||||
};
|
||||
|
||||
return consider_level_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level)
|
||||
{
|
||||
auto consider_levels = EQ::constants::GetConsiderLevelMap();
|
||||
if (!consider_levels[faction_consider_level].empty()) {
|
||||
return consider_levels[faction_consider_level];
|
||||
if (EQ::constants::GetConsiderLevelMap().find(faction_consider_level) != EQ::constants::GetConsiderLevelMap().end()) {
|
||||
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -371,14 +377,58 @@ const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
|
||||
{ EnvironmentalDamage::Falling, "Falling" },
|
||||
{ EnvironmentalDamage::Trap, "Trap" }
|
||||
};
|
||||
|
||||
return damage_type_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type)
|
||||
{
|
||||
if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
|
||||
auto damage_types = EQ::constants::GetEnvironmentalDamageMap();
|
||||
return damage_types[damage_type];
|
||||
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> stuck_behavior_map = {
|
||||
{ StuckBehavior::RunToTarget, "Run To Target" },
|
||||
{ StuckBehavior::WarpToTarget, "Warp To Target" },
|
||||
{ StuckBehavior::TakeNoAction, "Take No Action" },
|
||||
{ StuckBehavior::EvadeCombat, "Evade Combat" }
|
||||
};
|
||||
|
||||
return stuck_behavior_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id)
|
||||
{
|
||||
if (EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
|
||||
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
|
||||
{
|
||||
static const std::map<uint8, std::string> spawn_animation_map = {
|
||||
{ SpawnAnimations::Standing, "Standing" },
|
||||
{ SpawnAnimations::Sitting, "Sitting" },
|
||||
{ SpawnAnimations::Crouching, "Crouching" },
|
||||
{ SpawnAnimations::Laying, "Laying" },
|
||||
{ SpawnAnimations::Looting, "Looting" }
|
||||
};
|
||||
|
||||
return spawn_animation_map;
|
||||
}
|
||||
|
||||
std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
|
||||
{
|
||||
if (EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
|
||||
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
+52
-3
@@ -221,7 +221,7 @@ namespace EQ
|
||||
stanceBurnAE
|
||||
};
|
||||
|
||||
enum GravityBehavior : uint8 {
|
||||
enum GravityBehavior : int8 {
|
||||
Ground,
|
||||
Flying,
|
||||
Levitating,
|
||||
@@ -237,6 +237,21 @@ namespace EQ
|
||||
Trap
|
||||
};
|
||||
|
||||
enum StuckBehavior : uint8 {
|
||||
RunToTarget,
|
||||
WarpToTarget,
|
||||
TakeNoAction,
|
||||
EvadeCombat
|
||||
};
|
||||
|
||||
enum SpawnAnimations : uint8 {
|
||||
Standing,
|
||||
Sitting,
|
||||
Crouching,
|
||||
Laying,
|
||||
Looting
|
||||
};
|
||||
|
||||
const char *GetStanceName(StanceType stance_type);
|
||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
||||
|
||||
@@ -246,8 +261,8 @@ namespace EQ
|
||||
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
|
||||
std::string GetLDoNThemeName(uint32 theme_id);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetFlyModeMap();
|
||||
std::string GetFlyModeName(uint8 flymode_id);
|
||||
extern const std::map<int8, std::string>& GetFlyModeMap();
|
||||
std::string GetFlyModeName(int8 flymode_id);
|
||||
|
||||
extern const std::map<bodyType, std::string>& GetBodyTypeMap();
|
||||
std::string GetBodyTypeName(bodyType bodytype_id);
|
||||
@@ -261,6 +276,12 @@ namespace EQ
|
||||
extern const std::map<uint8, std::string>& GetEnvironmentalDamageMap();
|
||||
std::string GetEnvironmentalDamageName(uint8 damage_type);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetStuckBehaviorMap();
|
||||
std::string GetStuckBehaviorName(uint8 behavior_id);
|
||||
|
||||
extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
|
||||
std::string GetSpawnAnimationName(uint8 animation_id);
|
||||
|
||||
const int STANCE_TYPE_FIRST = stancePassive;
|
||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
||||
@@ -416,4 +437,32 @@ enum ConsiderLevel : uint8 {
|
||||
Scowls
|
||||
};
|
||||
|
||||
enum TargetDescriptionType : uint8 {
|
||||
LCSelf,
|
||||
UCSelf,
|
||||
LCYou,
|
||||
UCYou,
|
||||
LCYour,
|
||||
UCYour
|
||||
};
|
||||
|
||||
enum ReloadWorld : uint8 {
|
||||
NoRepop = 0,
|
||||
Repop,
|
||||
ForceRepop
|
||||
};
|
||||
|
||||
enum MerchantBucketComparison : uint8 {
|
||||
BucketEqualTo = 0,
|
||||
BucketNotEqualTo,
|
||||
BucketGreaterThanOrEqualTo,
|
||||
BucketLesserThanOrEqualTo,
|
||||
BucketGreaterThan,
|
||||
BucketLesserThan,
|
||||
BucketIsAny,
|
||||
BucketIsNotAny,
|
||||
BucketIsBetween,
|
||||
BucketIsNotBetween
|
||||
};
|
||||
|
||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||
|
||||
@@ -455,6 +455,7 @@ N(OP_ServerListResponse),
|
||||
N(OP_SessionReady),
|
||||
N(OP_SetChatServer),
|
||||
N(OP_SetChatServer2),
|
||||
N(OP_SetFace),
|
||||
N(OP_SetGroupTarget),
|
||||
N(OP_SetGuildMOTD),
|
||||
N(OP_SetGuildRank),
|
||||
|
||||
+17
-11
@@ -2316,9 +2316,12 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint32 drakkin_heritage;
|
||||
/*011*/ uint32 drakkin_tattoo;
|
||||
/*015*/ uint32 drakkin_details;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
//increase the face value by ten so if there were 8 woad
|
||||
//designs then there would be 80 barb faces
|
||||
@@ -3621,14 +3624,17 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
|
||||
};
|
||||
|
||||
struct MerchantList {
|
||||
uint32 id;
|
||||
uint32 slot;
|
||||
uint32 item;
|
||||
int16 faction_required;
|
||||
int8 level_required;
|
||||
uint16 alt_currency_cost;
|
||||
uint32 classes_required;
|
||||
uint8 probability;
|
||||
uint32 id;
|
||||
uint32 slot;
|
||||
uint32 item;
|
||||
int16 faction_required;
|
||||
int8 level_required;
|
||||
uint16 alt_currency_cost;
|
||||
uint32 classes_required;
|
||||
uint8 probability;
|
||||
std::string bucket_name;
|
||||
std::string bucket_value;
|
||||
uint8 bucket_comparison;
|
||||
};
|
||||
|
||||
struct TempMerchantList {
|
||||
|
||||
+53
-59
@@ -23,6 +23,8 @@
|
||||
#include "platform.h"
|
||||
#include "string_util.h"
|
||||
#include "misc.h"
|
||||
#include "discord/discord.h"
|
||||
#include "repositories/discord_webhooks_repository.h"
|
||||
#include "repositories/logsys_categories_repository.h"
|
||||
|
||||
#include <iostream>
|
||||
@@ -46,6 +48,7 @@ std::ofstream process_log;
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <thread>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -89,7 +92,7 @@ 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 &) {};
|
||||
on_log_console_hook = [](uint16 log_type, const std::string &) {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,6 +111,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
log_settings[log_category_id].log_to_console = 0;
|
||||
log_settings[log_category_id].log_to_file = 0;
|
||||
log_settings[log_category_id].log_to_gmsay = 0;
|
||||
log_settings[log_category_id].log_to_discord = 0;
|
||||
log_settings[log_category_id].is_category_enabled = 0;
|
||||
}
|
||||
|
||||
@@ -134,6 +138,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ChecksumVerification].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
@@ -153,7 +159,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
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;
|
||||
const bool log_to_discord = log_settings[log_category_id].log_to_discord > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay || log_to_discord;
|
||||
if (is_category_enabled) {
|
||||
log_settings[log_category_id].is_category_enabled = 1;
|
||||
}
|
||||
@@ -220,41 +227,12 @@ std::string EQEmuLogSys::FormatOutMessageString(
|
||||
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param 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
|
||||
*/
|
||||
if (log_category == Logs::LogCategory::Netcode) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes that actually support hooks
|
||||
*/
|
||||
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||
EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld
|
||||
) {
|
||||
on_log_gmsay_hook(log_category, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param debug_level
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessLogWrite(
|
||||
uint16 debug_level,
|
||||
uint16 log_category,
|
||||
const std::string &message
|
||||
)
|
||||
@@ -272,10 +250,9 @@ void EQEmuLogSys::ProcessLogWrite(
|
||||
crash_log.close();
|
||||
}
|
||||
|
||||
char time_stamp[80];
|
||||
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
|
||||
|
||||
if (process_log) {
|
||||
char time_stamp[80];
|
||||
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
|
||||
process_log << time_stamp << " " << message << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -371,7 +348,7 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
|
||||
* @param log_category
|
||||
* @param message
|
||||
*/
|
||||
void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message)
|
||||
void EQEmuLogSys::ProcessConsoleMessage(uint16 log_category, const std::string &message)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
HANDLE console_handle;
|
||||
@@ -389,7 +366,7 @@ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category,
|
||||
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
|
||||
#endif
|
||||
|
||||
on_log_console_hook(debug_level, log_category, message);
|
||||
on_log_console_hook(log_category, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,28 +423,28 @@ void EQEmuLogSys::Out(
|
||||
...
|
||||
)
|
||||
{
|
||||
bool log_to_console = true;
|
||||
if (log_settings[log_category].log_to_console < debug_level) {
|
||||
log_to_console = false;
|
||||
}
|
||||
bool log_to_console = log_settings[log_category].log_to_console > 0 &&
|
||||
log_settings[log_category].log_to_console >= debug_level;
|
||||
bool log_to_file = log_settings[log_category].log_to_file > 0 &&
|
||||
log_settings[log_category].log_to_file >= debug_level;
|
||||
bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0 &&
|
||||
log_settings[log_category].log_to_gmsay >= debug_level &&
|
||||
log_category != Logs::LogCategory::Netcode &&
|
||||
(EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||
EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld);
|
||||
bool log_to_discord = EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone &&
|
||||
log_settings[log_category].log_to_discord > 0 &&
|
||||
log_settings[log_category].log_to_discord >= debug_level &&
|
||||
log_settings[log_category].discord_webhook_id > 0 &&
|
||||
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
|
||||
|
||||
bool log_to_file = true;
|
||||
if (log_settings[log_category].log_to_file < debug_level) {
|
||||
log_to_file = false;
|
||||
}
|
||||
|
||||
bool log_to_gmsay = true;
|
||||
if (log_settings[log_category].log_to_gmsay < debug_level) {
|
||||
log_to_gmsay = false;
|
||||
}
|
||||
|
||||
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay;
|
||||
// bail out if nothing to log
|
||||
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay && !log_to_discord;
|
||||
if (nothing_to_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string prefix;
|
||||
|
||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
|
||||
}
|
||||
@@ -480,13 +457,16 @@ void EQEmuLogSys::Out(
|
||||
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);
|
||||
EQEmuLogSys::ProcessConsoleMessage(log_category, output_debug_message);
|
||||
}
|
||||
if (log_to_gmsay) {
|
||||
EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message);
|
||||
on_log_gmsay_hook(log_category, message);
|
||||
}
|
||||
if (log_to_file) {
|
||||
EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message);
|
||||
EQEmuLogSys::ProcessLogWrite(log_category, output_debug_message);
|
||||
}
|
||||
if (log_to_discord && on_log_discord_hook) {
|
||||
on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,16 +609,20 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
continue;
|
||||
}
|
||||
|
||||
log_settings[c.log_category_id].log_to_console = static_cast<uint8>(c.log_to_console);
|
||||
log_settings[c.log_category_id].log_to_file = static_cast<uint8>(c.log_to_file);
|
||||
log_settings[c.log_category_id].log_to_gmsay = static_cast<uint8>(c.log_to_gmsay);
|
||||
log_settings[c.log_category_id].log_to_console = static_cast<uint8>(c.log_to_console);
|
||||
log_settings[c.log_category_id].log_to_file = static_cast<uint8>(c.log_to_file);
|
||||
log_settings[c.log_category_id].log_to_gmsay = static_cast<uint8>(c.log_to_gmsay);
|
||||
log_settings[c.log_category_id].log_to_discord = static_cast<uint8>(c.log_to_discord);
|
||||
log_settings[c.log_category_id].discord_webhook_id = c.discord_webhook_id;
|
||||
|
||||
// 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[c.log_category_id].log_to_console > 0;
|
||||
const bool log_to_file = log_settings[c.log_category_id].log_to_file > 0;
|
||||
const bool log_to_gmsay = log_settings[c.log_category_id].log_to_gmsay > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
||||
const bool log_to_discord = log_settings[c.log_category_id].log_to_discord > 0 &&
|
||||
log_settings[c.log_category_id].discord_webhook_id > 0;
|
||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay || log_to_discord;
|
||||
|
||||
if (is_category_enabled) {
|
||||
log_settings[c.log_category_id].is_category_enabled = 1;
|
||||
@@ -668,6 +652,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
new_category.log_to_console = log_settings[i].log_to_console;
|
||||
new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
|
||||
new_category.log_to_file = log_settings[i].log_to_file;
|
||||
new_category.log_to_discord = log_settings[i].log_to_discord;
|
||||
|
||||
LogsysCategoriesRepository::InsertOne(*m_database, new_category);
|
||||
}
|
||||
@@ -675,6 +660,14 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
||||
|
||||
LogInfo("Loaded [{}] log categories", categories.size());
|
||||
|
||||
auto webhooks = DiscordWebhooksRepository::All(*m_database);
|
||||
if (!webhooks.empty()) {
|
||||
for (auto &w: webhooks) {
|
||||
discord_webhooks[w.id] = {w.id, w.webhook_name, w.webhook_url};
|
||||
}
|
||||
LogInfo("Loaded [{}] Discord webhooks", webhooks.size());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -684,3 +677,4 @@ EQEmuLogSys *EQEmuLogSys::SetDatabase(Database *db)
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+42
-11
@@ -128,6 +128,9 @@ namespace Logs {
|
||||
HTTP,
|
||||
Saylink,
|
||||
ChecksumVerification,
|
||||
CombatRecord,
|
||||
Hate,
|
||||
Discord,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@@ -214,6 +217,9 @@ namespace Logs {
|
||||
"HTTP",
|
||||
"Saylink",
|
||||
"ChecksumVerification",
|
||||
"CombatRecord",
|
||||
"Hate",
|
||||
"Discord",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -221,6 +227,8 @@ namespace Logs {
|
||||
|
||||
class Database;
|
||||
|
||||
constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300;
|
||||
|
||||
class EQEmuLogSys {
|
||||
public:
|
||||
EQEmuLogSys();
|
||||
@@ -283,9 +291,19 @@ public:
|
||||
uint8 log_to_file;
|
||||
uint8 log_to_console;
|
||||
uint8 log_to_gmsay;
|
||||
uint8 log_to_discord;
|
||||
int discord_webhook_id;
|
||||
uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */
|
||||
};
|
||||
|
||||
struct OriginationInfo {
|
||||
std::string zone_short_name;
|
||||
std::string zone_long_name;
|
||||
int instance_id;
|
||||
};
|
||||
|
||||
OriginationInfo origination_info{};
|
||||
|
||||
/**
|
||||
* Internally used memory reference for all log settings per category
|
||||
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
|
||||
@@ -293,24 +311,38 @@ public:
|
||||
*/
|
||||
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
|
||||
|
||||
struct DiscordWebhooks {
|
||||
int id;
|
||||
std::string webhook_name;
|
||||
std::string webhook_url;
|
||||
};
|
||||
|
||||
DiscordWebhooks discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
|
||||
|
||||
bool file_logs_enabled = false;
|
||||
|
||||
int log_platform = 0;
|
||||
std::string platform_file_name;
|
||||
int log_platform = 0;
|
||||
std::string platform_file_name;
|
||||
|
||||
|
||||
// gmsay
|
||||
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
||||
|
||||
EQEmuLogSys * SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f) {
|
||||
EQEmuLogSys *SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f)
|
||||
{
|
||||
on_log_gmsay_hook = f;
|
||||
return this;
|
||||
}
|
||||
|
||||
EQEmuLogSys *SetDiscordHandler(std::function<void(uint16 log_category, int webhook_id, const std::string &)> f)
|
||||
{
|
||||
on_log_discord_hook = f;
|
||||
return this;
|
||||
}
|
||||
|
||||
// console
|
||||
void SetConsoleHandler(
|
||||
std::function<void(
|
||||
uint16 debug_level,
|
||||
uint16 log_type,
|
||||
const std::string &
|
||||
)> f
|
||||
@@ -324,18 +356,17 @@ public:
|
||||
private:
|
||||
|
||||
// reference to database
|
||||
Database *m_database;
|
||||
|
||||
std::function<void(uint16 log_category, const std::string &)> on_log_gmsay_hook;
|
||||
std::function<void(uint16 debug_level, uint16 log_category, const std::string &)> on_log_console_hook;
|
||||
Database *m_database;
|
||||
std::function<void(uint16 log_category, const std::string &)> on_log_gmsay_hook;
|
||||
std::function<void(uint16 log_category, int webhook_id, const std::string &)> on_log_discord_hook;
|
||||
std::function<void(uint16 log_category, const std::string &)> on_log_console_hook;
|
||||
|
||||
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
|
||||
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
|
||||
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
|
||||
|
||||
void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message);
|
||||
void ProcessConsoleMessage(uint16 log_category, const std::string &message);
|
||||
void ProcessLogWrite(uint16 log_category, const std::string &message);
|
||||
bool IsRfc5424LogCategory(uint16 log_category);
|
||||
};
|
||||
|
||||
|
||||
@@ -706,6 +706,36 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::ChecksumVerification, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCombatRecord(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::CombatRecord].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::CombatRecord, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogCombatRecordDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::CombatRecord].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::CombatRecord, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHate(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Hate].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Hate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogHateDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Hate].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Hate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDiscord(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Discord].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Discord, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDiscordDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Discord].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Discord, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#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__);\
|
||||
@@ -1108,12 +1138,48 @@
|
||||
#define LogSaylinkDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogScheduler(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogSchedulerDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogCheat(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogCheatDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogLoot(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogLootDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogFood(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogFoodDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogChecksumVerification(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogChecksumVerificationDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogCombatRecord(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogCombatRecordDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogHate(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogHateDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
|
||||
+9
-9
@@ -370,7 +370,7 @@ namespace EQ
|
||||
uint32 Slots; // Bitfield for which slots this item can be used in
|
||||
uint32 Price; // Item cost (?)
|
||||
uint32 Icon; // Icon Number
|
||||
uint32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
|
||||
int32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
|
||||
bool LoreFlag; // This will be true if LoreGroup is non-zero
|
||||
bool PendingLoreFlag;
|
||||
bool ArtifactFlag;
|
||||
@@ -473,14 +473,14 @@ namespace EQ
|
||||
uint32 LDoNSold;
|
||||
uint32 BaneDmgRaceAmt;
|
||||
uint32 AugRestrict;
|
||||
uint32 Endur;
|
||||
uint32 DotShielding;
|
||||
uint32 Attack;
|
||||
uint32 Regen;
|
||||
uint32 ManaRegen;
|
||||
uint32 EnduranceRegen;
|
||||
uint32 Haste;
|
||||
uint32 DamageShield;
|
||||
int32 Endur;
|
||||
int32 DotShielding;
|
||||
int32 Attack;
|
||||
int32 Regen;
|
||||
int32 ManaRegen;
|
||||
int32 EnduranceRegen;
|
||||
int32 Haste;
|
||||
int32 DamageShield;
|
||||
uint32 RecastDelay;
|
||||
int RecastType;
|
||||
uint32 AugDistiller;
|
||||
|
||||
+21
-21
@@ -214,7 +214,7 @@ EQ::ItemInstance::~ItemInstance()
|
||||
bool EQ::ItemInstance::IsType(item::ItemClass item_class) const
|
||||
{
|
||||
// IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr'
|
||||
|
||||
|
||||
// Check usage type
|
||||
if ((m_use_type == ItemInstWorldContainer) && (item_class == item::ItemClassBag))
|
||||
return true;
|
||||
@@ -245,7 +245,7 @@ bool EQ::ItemInstance::IsStackable() const
|
||||
{
|
||||
if (!m_item)
|
||||
return false;
|
||||
|
||||
|
||||
return m_item->Stackable;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ bool EQ::ItemInstance::IsCharged() const
|
||||
{
|
||||
if (!m_item)
|
||||
return false;
|
||||
|
||||
|
||||
if (m_item->MaxCharges > 1)
|
||||
return true;
|
||||
else
|
||||
@@ -381,7 +381,7 @@ EQ::ItemInstance* EQ::ItemInstance::PopItem(uint8 index)
|
||||
m_contents.erase(index);
|
||||
return inst; // Return pointer that needs to be deleted (or otherwise managed)
|
||||
}
|
||||
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ uint8 EQ::ItemInstance::GetTotalItemCount() const
|
||||
{
|
||||
if (!m_item)
|
||||
return 0;
|
||||
|
||||
|
||||
uint8 item_count = 1;
|
||||
|
||||
if (m_item && !m_item->IsClassBag()) { return item_count; }
|
||||
@@ -526,7 +526,7 @@ EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAug(int32 ornamentationAugty
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return this->GetAugment(i);
|
||||
return GetAugment(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +549,7 @@ uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const {
|
||||
bool EQ::ItemInstance::UpdateOrnamentationInfo() {
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return false;
|
||||
|
||||
|
||||
bool ornamentSet = false;
|
||||
|
||||
int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
@@ -642,7 +642,7 @@ void EQ::ItemInstance::PutAugment(uint8 slot, const ItemInstance& augment)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return;
|
||||
|
||||
|
||||
PutItem(slot, augment);
|
||||
}
|
||||
|
||||
@@ -655,7 +655,7 @@ void EQ::ItemInstance::PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id
|
||||
if (aug) {
|
||||
PutAugment(slot, *aug);
|
||||
safe_delete(aug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove augment from item and destroy it
|
||||
@@ -663,7 +663,7 @@ void EQ::ItemInstance::DeleteAugment(uint8 index)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return;
|
||||
|
||||
|
||||
DeleteItem(index);
|
||||
}
|
||||
|
||||
@@ -672,7 +672,7 @@ EQ::ItemInstance* EQ::ItemInstance::RemoveAugment(uint8 index)
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return nullptr;
|
||||
|
||||
|
||||
return PopItem(index);
|
||||
}
|
||||
|
||||
@@ -680,7 +680,7 @@ bool EQ::ItemInstance::IsAugmented()
|
||||
{
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return false;
|
||||
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (GetAugmentItemID(index))
|
||||
return true;
|
||||
@@ -698,7 +698,7 @@ bool EQ::ItemInstance::ContainsAugmentByID(uint32 item_id)
|
||||
if (!item_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
|
||||
if (GetAugmentItemID(augment_slot) == item_id) {
|
||||
return true;
|
||||
@@ -718,7 +718,7 @@ int EQ::ItemInstance::CountAugmentByID(uint32 item_id)
|
||||
if (!item_id) {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
|
||||
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
|
||||
if (GetAugmentItemID(augment_slot) == item_id) {
|
||||
quantity++;
|
||||
@@ -873,7 +873,7 @@ bool EQ::ItemInstance::IsDroppable(bool recurse) const
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1097,7 +1097,7 @@ int EQ::ItemInstance::GetItemElementalFlag(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemElementalDamage(bool augments) const
|
||||
{
|
||||
int damage = 0;
|
||||
int64 damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
damage = item->ElemDmgAmt;
|
||||
@@ -1162,7 +1162,7 @@ int EQ::ItemInstance::GetItemRequiredLevel(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemWeaponDamage(bool augments) const
|
||||
{
|
||||
int damage = 0;
|
||||
int64 damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
damage = item->Damage;
|
||||
@@ -1178,7 +1178,7 @@ int EQ::ItemInstance::GetItemWeaponDamage(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBackstabDamage(bool augments) const
|
||||
{
|
||||
int damage = 0;
|
||||
int64 damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
damage = item->BackstabDmg;
|
||||
@@ -1236,7 +1236,7 @@ int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) const
|
||||
{
|
||||
int damage = 0;
|
||||
int64 damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
if (item->BaneDmgBody == against)
|
||||
@@ -1253,7 +1253,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) con
|
||||
|
||||
int EQ::ItemInstance::GetItemBaneDamageRace(uint16 against, bool augments) const
|
||||
{
|
||||
int damage = 0;
|
||||
int64 damage = 0;
|
||||
const auto item = GetItem();
|
||||
if (item) {
|
||||
if (item->BaneDmgRace == against)
|
||||
@@ -1745,4 +1745,4 @@ EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32
|
||||
|
||||
EvolveInfo::~EvolveInfo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2649,11 +2649,11 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint8 unknown007;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 unknown020;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
};
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
|
||||
@@ -2622,11 +2622,11 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint8 unknown007;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 unknown020;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
};
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
|
||||
@@ -2136,11 +2136,11 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint8 unknown007;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 unknown020;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
};
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
|
||||
@@ -2106,11 +2106,11 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint8 unknown007;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 unknown020;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
};
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
|
||||
@@ -1464,6 +1464,30 @@ namespace Titanium
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SetFace)
|
||||
{
|
||||
auto emu = reinterpret_cast<FaceChange_Struct*>((*p)->pBuffer);
|
||||
|
||||
EQApplicationPacket outapp(OP_Illusion, sizeof(structs::Illusion_Struct));
|
||||
auto buf = reinterpret_cast<structs::Illusion_Struct*>(outapp.pBuffer);
|
||||
|
||||
buf->spawnid = emu->entity_id;
|
||||
buf->race = -1; // unchanged
|
||||
buf->gender = -1; // unchanged
|
||||
buf->texture = -1; // unchanged
|
||||
buf->helmtexture = -1; // unchanged
|
||||
buf->face = emu->face;
|
||||
buf->hairstyle = emu->hairstyle;
|
||||
buf->haircolor = emu->haircolor;
|
||||
buf->beard = emu->beard;
|
||||
buf->beardcolor = emu->beardcolor;
|
||||
buf->size = 0.0f; // unchanged
|
||||
|
||||
safe_delete(*p); // not using the original packet
|
||||
|
||||
dest->QueuePacket(&outapp, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_ShopPlayerSell)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Merchant_Purchase_Struct);
|
||||
|
||||
@@ -66,6 +66,7 @@ E(OP_ReadBook)
|
||||
E(OP_RespondAA)
|
||||
E(OP_SendCharInfo)
|
||||
E(OP_SendAATable)
|
||||
E(OP_SetFace)
|
||||
E(OP_ShopPlayerSell)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_TaskDescription)
|
||||
|
||||
@@ -1761,8 +1761,7 @@ struct AdventureRequestResponse_Struct{
|
||||
struct Illusion_Struct {
|
||||
/*000*/ uint32 spawnid;
|
||||
/*004*/ char charname[64];
|
||||
/*068*/ uint16 race;
|
||||
/*070*/ char unknown070[2];
|
||||
/*068*/ int race;
|
||||
/*072*/ uint8 gender;
|
||||
/*073*/ uint8 texture;
|
||||
/*074*/ uint8 helmtexture;
|
||||
|
||||
@@ -2185,11 +2185,11 @@ struct FaceChange_Struct {
|
||||
/*004*/ uint8 hairstyle;
|
||||
/*005*/ uint8 beard;
|
||||
/*006*/ uint8 face;
|
||||
/*007*/ uint8 unknown007;
|
||||
/*007*/ uint8 unused_padding;
|
||||
/*008*/ uint32 drakkin_heritage;
|
||||
/*012*/ uint32 drakkin_tattoo;
|
||||
/*016*/ uint32 drakkin_details;
|
||||
/*020*/ uint32 unknown020;
|
||||
/*020*/ uint32 entity_id;
|
||||
/*024*/
|
||||
};
|
||||
//there are only 10 faces for barbs changing woad just
|
||||
|
||||
@@ -58,7 +58,8 @@ XS(XS_EQDB_field_count)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->field_count();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -84,7 +85,8 @@ XS(XS_EQDB_affected_rows)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->affected_rows();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -110,7 +112,8 @@ XS(XS_EQDB_insert_id)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->insert_id();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -136,7 +139,8 @@ XS(XS_EQDB_get_errno)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->get_errno();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ XS(XS_EQDBRes_num_rows)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->num_rows();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -80,7 +81,8 @@ XS(XS_EQDBRes_num_fields)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->num_fields();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "profanity_manager.h"
|
||||
#include "dbcore.h"
|
||||
#include "string_util.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <cstring>
|
||||
@@ -34,15 +35,17 @@ bool EQ::ProfanityManager::LoadProfanityList(DBcore *db) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!load_database_entries(db))
|
||||
if (!load_database_entries(db)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::UpdateProfanityList(DBcore *db) {
|
||||
if (!load_database_entries(db))
|
||||
if (!load_database_entries(db)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_originator_flag = true;
|
||||
|
||||
@@ -58,53 +61,60 @@ bool EQ::ProfanityManager::DeleteProfanityList(DBcore *db) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::AddProfanity(DBcore *db, const char *profanity) {
|
||||
if (!db || !profanity)
|
||||
bool EQ::ProfanityManager::AddProfanity(DBcore *db, std::string profanity) {
|
||||
if (!db || profanity.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string entry(profanity);
|
||||
std::string entry = str_tolower(profanity);
|
||||
|
||||
std::transform(entry.begin(), entry.end(), entry.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||
|
||||
if (check_for_existing_entry(entry.c_str()))
|
||||
if (check_for_existing_entry(entry)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry.length() < REDACTION_LENGTH_MIN)
|
||||
if (entry.length() < REDACTION_LENGTH_MIN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
profanity_list.push_back(entry);
|
||||
|
||||
std::string query = "REPLACE INTO `profanity_list` (`word`) VALUES ('";
|
||||
query.append(entry);
|
||||
query.append("')");
|
||||
auto query = fmt::format(
|
||||
"REPLACE INTO `profanity_list` (`word`) VALUES ('{}')",
|
||||
profanity
|
||||
);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_originator_flag = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::RemoveProfanity(DBcore *db, const char *profanity) {
|
||||
if (!db || !profanity)
|
||||
bool EQ::ProfanityManager::RemoveProfanity(DBcore *db, std::string profanity) {
|
||||
if (!db || profanity.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string entry(profanity);
|
||||
std::string entry = str_tolower(profanity);
|
||||
|
||||
std::transform(entry.begin(), entry.end(), entry.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||
|
||||
if (!check_for_existing_entry(entry.c_str()))
|
||||
if (!check_for_existing_entry(entry)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
profanity_list.remove(entry);
|
||||
|
||||
std::string query = "DELETE FROM `profanity_list` WHERE `word` LIKE '";
|
||||
query.append(entry);
|
||||
query.append("'");
|
||||
auto query = fmt::format(
|
||||
"DELETE FROM `profanity_list` WHERE `word` = '{}'",
|
||||
entry
|
||||
);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_originator_flag = true;
|
||||
|
||||
@@ -112,16 +122,16 @@ bool EQ::ProfanityManager::RemoveProfanity(DBcore *db, const char *profanity) {
|
||||
}
|
||||
|
||||
void EQ::ProfanityManager::RedactMessage(char *message) {
|
||||
if (!message)
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string test_message(message);
|
||||
std::string test_message = str_tolower(message);
|
||||
// hard-coded max length based on channel message buffer size (4096 bytes)..
|
||||
// ..will need to change or remove if other sources are used for redaction
|
||||
if (test_message.length() < REDACTION_LENGTH_MIN || test_message.length() >= 4096)
|
||||
if (test_message.length() < REDACTION_LENGTH_MIN || test_message.length() >= 4096) {
|
||||
return;
|
||||
|
||||
std::transform(test_message.begin(), test_message.end(), test_message.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||
}
|
||||
|
||||
for (const auto &iter : profanity_list) { // consider adding textlink checks if it becomes an issue
|
||||
size_t pos = 0;
|
||||
@@ -129,12 +139,17 @@ void EQ::ProfanityManager::RedactMessage(char *message) {
|
||||
|
||||
while (pos != std::string::npos) {
|
||||
pos = test_message.find(iter, start_pos);
|
||||
if (pos == std::string::npos)
|
||||
if (pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pos + iter.length()) == test_message.length() || !isalpha(test_message.at(pos + iter.length()))) {
|
||||
if (pos == 0 || !isalpha(test_message.at(pos - 1)))
|
||||
if (
|
||||
(pos + iter.length()) == test_message.length() ||
|
||||
!isalpha(test_message.at(pos + iter.length()))
|
||||
) {
|
||||
if (pos == 0 || !isalpha(test_message.at(pos - 1))) {
|
||||
memset((message + pos), REDACTION_CHARACTER, iter.length());
|
||||
}
|
||||
}
|
||||
|
||||
start_pos = (pos + iter.length());
|
||||
@@ -143,25 +158,29 @@ void EQ::ProfanityManager::RedactMessage(char *message) {
|
||||
}
|
||||
|
||||
void EQ::ProfanityManager::RedactMessage(std::string &message) {
|
||||
if (message.length() < REDACTION_LENGTH_MIN || message.length() >= 4096)
|
||||
if (message.length() < REDACTION_LENGTH_MIN || message.length() >= 4096) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string test_message(const_cast<const std::string&>(message));
|
||||
std::string test_message = str_tolower(message);
|
||||
|
||||
std::transform(test_message.begin(), test_message.end(), test_message.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||
|
||||
for (const auto &iter : profanity_list) { // consider adding textlink checks if it becomes an issue
|
||||
for (const auto &iter : profanity_list) {
|
||||
size_t pos = 0;
|
||||
size_t start_pos = 0;
|
||||
|
||||
while (pos != std::string::npos) {
|
||||
pos = test_message.find(iter, start_pos);
|
||||
if (pos == std::string::npos)
|
||||
if (pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pos + iter.length()) == test_message.length() || !isalpha(test_message.at(pos + iter.length()))) {
|
||||
if (pos == 0 || !isalpha(test_message.at(pos - 1)))
|
||||
if (
|
||||
(pos + iter.length()) == test_message.length() ||
|
||||
!isalpha(test_message.at(pos + iter.length()))
|
||||
) {
|
||||
if (pos == 0 || !isalpha(test_message.at(pos - 1))) {
|
||||
message.replace(pos, iter.length(), iter.length(), REDACTION_CHARACTER);
|
||||
}
|
||||
}
|
||||
|
||||
start_pos = (pos + iter.length());
|
||||
@@ -169,24 +188,18 @@ void EQ::ProfanityManager::RedactMessage(std::string &message) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::ContainsCensoredLanguage(const char *message) {
|
||||
if (!message)
|
||||
return false;
|
||||
|
||||
return ContainsCensoredLanguage(std::string(message));
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::ContainsCensoredLanguage(const std::string &message) {
|
||||
if (message.length() < REDACTION_LENGTH_MIN || message.length() >= 4096)
|
||||
if (message.length() < REDACTION_LENGTH_MIN || message.length() >= 4096) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string test_message(message);
|
||||
|
||||
std::transform(test_message.begin(), test_message.end(), test_message.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||
std::string test_message = str_tolower(message);
|
||||
|
||||
for (const auto &iter : profanity_list) {
|
||||
if (test_message.find(iter) != std::string::npos)
|
||||
if (test_message.find(iter) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -197,26 +210,28 @@ const std::list<std::string> &EQ::ProfanityManager::GetProfanityList() {
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::IsCensorshipActive() {
|
||||
return (profanity_list.size() != 0);
|
||||
return profanity_list.size() != 0;
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::load_database_entries(DBcore *db) {
|
||||
if (!db)
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
profanity_list.clear();
|
||||
|
||||
std::string query = "SELECT `word` FROM `profanity_list`";
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (std::strlen(row[0]) >= REDACTION_LENGTH_MIN) {
|
||||
std::string entry(row[0]);
|
||||
std::transform(entry.begin(), entry.end(), entry.begin(), [](unsigned char c) -> unsigned char { return tolower(c); });
|
||||
if (!check_for_existing_entry(entry.c_str()))
|
||||
profanity_list.push_back((std::string)entry);
|
||||
for (auto row : results) {
|
||||
std::string entry = str_tolower(row[0]);
|
||||
if (entry.length() >= REDACTION_LENGTH_MIN) {
|
||||
if (!check_for_existing_entry(entry)) {
|
||||
profanity_list.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,26 +239,31 @@ bool EQ::ProfanityManager::load_database_entries(DBcore *db) {
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::clear_database_entries(DBcore *db) {
|
||||
if (!db)
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
profanity_list.clear();
|
||||
|
||||
std::string query = "DELETE FROM `profanity_list`";
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQ::ProfanityManager::check_for_existing_entry(const char *profanity) {
|
||||
if (!profanity)
|
||||
bool EQ::ProfanityManager::check_for_existing_entry(std::string profanity) {
|
||||
if (profanity.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &iter : profanity_list) {
|
||||
if (iter.compare(profanity) == 0)
|
||||
if (!iter.compare(profanity)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <fmt/format.h>
|
||||
|
||||
|
||||
class DBcore;
|
||||
@@ -34,13 +35,12 @@ namespace EQ
|
||||
static bool UpdateProfanityList(DBcore *db);
|
||||
static bool DeleteProfanityList(DBcore *db);
|
||||
|
||||
static bool AddProfanity(DBcore *db, const char *profanity);
|
||||
static bool RemoveProfanity(DBcore *db, const char *profanity);
|
||||
static bool AddProfanity(DBcore *db, std::string profanity);
|
||||
static bool RemoveProfanity(DBcore *db, std::string profanity);
|
||||
|
||||
static void RedactMessage(char *message);
|
||||
static void RedactMessage(std::string &message);
|
||||
|
||||
static bool ContainsCensoredLanguage(const char *message);
|
||||
static bool ContainsCensoredLanguage(const std::string &message);
|
||||
|
||||
static const std::list<std::string> &GetProfanityList();
|
||||
@@ -53,7 +53,7 @@ namespace EQ
|
||||
private:
|
||||
static bool load_database_entries(DBcore *db);
|
||||
static bool clear_database_entries(DBcore *db);
|
||||
static bool check_for_existing_entry(const char *profanity);
|
||||
static bool check_for_existing_entry(std::string profanity);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* DO NOT MODIFY THIS FILE
|
||||
*
|
||||
* This repository was automatically generated and is NOT to be modified directly.
|
||||
* Any repository modifications are meant to be made to the repository extending the base.
|
||||
* Any modifications to base repositories are to be made by the generator only
|
||||
*
|
||||
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_BASE_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||
#define EQEMU_BASE_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../string_util.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseDiscordWebhooksRepository {
|
||||
public:
|
||||
struct DiscordWebhooks {
|
||||
int id;
|
||||
std::string webhook_name;
|
||||
std::string webhook_url;
|
||||
time_t created_at;
|
||||
time_t deleted_at;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"webhook_name",
|
||||
"webhook_url",
|
||||
"created_at",
|
||||
"deleted_at",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"webhook_name",
|
||||
"webhook_url",
|
||||
"UNIX_TIMESTAMP(created_at)",
|
||||
"UNIX_TIMESTAMP(deleted_at)",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("discord_webhooks");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
ColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static DiscordWebhooks NewEntity()
|
||||
{
|
||||
DiscordWebhooks entry{};
|
||||
|
||||
entry.id = 0;
|
||||
entry.webhook_name = "";
|
||||
entry.webhook_url = "";
|
||||
entry.created_at = 0;
|
||||
entry.deleted_at = 0;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static DiscordWebhooks GetDiscordWebhooksEntry(
|
||||
const std::vector<DiscordWebhooks> &discord_webhookss,
|
||||
int discord_webhooks_id
|
||||
)
|
||||
{
|
||||
for (auto &discord_webhooks : discord_webhookss) {
|
||||
if (discord_webhooks.id == discord_webhooks_id) {
|
||||
return discord_webhooks;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static DiscordWebhooks FindOne(
|
||||
Database& db,
|
||||
int discord_webhooks_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
discord_webhooks_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
DiscordWebhooks entry{};
|
||||
|
||||
entry.id = atoi(row[0]);
|
||||
entry.webhook_name = row[1] ? row[1] : "";
|
||||
entry.webhook_url = row[2] ? row[2] : "";
|
||||
entry.created_at = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||
entry.deleted_at = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
Database& db,
|
||||
int discord_webhooks_id
|
||||
)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
discord_webhooks_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
Database& db,
|
||||
DiscordWebhooks discord_webhooks_entry
|
||||
)
|
||||
{
|
||||
std::vector<std::string> update_values;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
update_values.push_back(columns[1] + " = '" + EscapeString(discord_webhooks_entry.webhook_name) + "'");
|
||||
update_values.push_back(columns[2] + " = '" + EscapeString(discord_webhooks_entry.webhook_url) + "'");
|
||||
update_values.push_back(columns[3] + " = FROM_UNIXTIME(" + (discord_webhooks_entry.created_at > 0 ? std::to_string(discord_webhooks_entry.created_at) : "null") + ")");
|
||||
update_values.push_back(columns[4] + " = FROM_UNIXTIME(" + (discord_webhooks_entry.deleted_at > 0 ? std::to_string(discord_webhooks_entry.deleted_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
implode(", ", update_values),
|
||||
PrimaryKey(),
|
||||
discord_webhooks_entry.id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static DiscordWebhooks InsertOne(
|
||||
Database& db,
|
||||
DiscordWebhooks discord_webhooks_entry
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_values;
|
||||
|
||||
insert_values.push_back(std::to_string(discord_webhooks_entry.id));
|
||||
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_name) + "'");
|
||||
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_url) + "'");
|
||||
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.created_at > 0 ? std::to_string(discord_webhooks_entry.created_at) : "null") + ")");
|
||||
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.deleted_at > 0 ? std::to_string(discord_webhooks_entry.deleted_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseInsert(),
|
||||
implode(",", insert_values)
|
||||
)
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
discord_webhooks_entry.id = results.LastInsertedID();
|
||||
return discord_webhooks_entry;
|
||||
}
|
||||
|
||||
discord_webhooks_entry = NewEntity();
|
||||
|
||||
return discord_webhooks_entry;
|
||||
}
|
||||
|
||||
static int InsertMany(
|
||||
Database& db,
|
||||
std::vector<DiscordWebhooks> discord_webhooks_entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &discord_webhooks_entry: discord_webhooks_entries) {
|
||||
std::vector<std::string> insert_values;
|
||||
|
||||
insert_values.push_back(std::to_string(discord_webhooks_entry.id));
|
||||
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_name) + "'");
|
||||
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_url) + "'");
|
||||
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.created_at > 0 ? std::to_string(discord_webhooks_entry.created_at) : "null") + ")");
|
||||
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.deleted_at > 0 ? std::to_string(discord_webhooks_entry.deleted_at) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> insert_values;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<DiscordWebhooks> All(Database& db)
|
||||
{
|
||||
std::vector<DiscordWebhooks> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
DiscordWebhooks entry{};
|
||||
|
||||
entry.id = atoi(row[0]);
|
||||
entry.webhook_name = row[1] ? row[1] : "";
|
||||
entry.webhook_url = row[2] ? row[2] : "";
|
||||
entry.created_at = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||
entry.deleted_at = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static std::vector<DiscordWebhooks> GetWhere(Database& db, std::string where_filter)
|
||||
{
|
||||
std::vector<DiscordWebhooks> all_entries;
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE {}",
|
||||
BaseSelect(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
DiscordWebhooks entry{};
|
||||
|
||||
entry.id = atoi(row[0]);
|
||||
entry.webhook_name = row[1] ? row[1] : "";
|
||||
entry.webhook_url = row[2] ? row[2] : "";
|
||||
entry.created_at = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||
entry.deleted_at = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
static int DeleteWhere(Database& db, std::string where_filter)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {}",
|
||||
TableName(),
|
||||
where_filter
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int Truncate(Database& db)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"TRUNCATE TABLE {}",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_BASE_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
int log_to_console;
|
||||
int log_to_file;
|
||||
int log_to_gmsay;
|
||||
int log_to_discord;
|
||||
int discord_webhook_id;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -39,6 +41,8 @@ public:
|
||||
"log_to_console",
|
||||
"log_to_file",
|
||||
"log_to_gmsay",
|
||||
"log_to_discord",
|
||||
"discord_webhook_id",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,6 +54,8 @@ public:
|
||||
"log_to_console",
|
||||
"log_to_file",
|
||||
"log_to_gmsay",
|
||||
"log_to_discord",
|
||||
"discord_webhook_id",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,6 +101,8 @@ public:
|
||||
entry.log_to_console = 0;
|
||||
entry.log_to_file = 0;
|
||||
entry.log_to_gmsay = 0;
|
||||
entry.log_to_discord = 0;
|
||||
entry.discord_webhook_id = 0;
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -135,6 +143,8 @@ public:
|
||||
entry.log_to_console = atoi(row[2]);
|
||||
entry.log_to_file = atoi(row[3]);
|
||||
entry.log_to_gmsay = atoi(row[4]);
|
||||
entry.log_to_discord = atoi(row[5]);
|
||||
entry.discord_webhook_id = atoi(row[6]);
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -173,6 +183,8 @@ public:
|
||||
update_values.push_back(columns[2] + " = " + std::to_string(logsys_categories_entry.log_to_console));
|
||||
update_values.push_back(columns[3] + " = " + std::to_string(logsys_categories_entry.log_to_file));
|
||||
update_values.push_back(columns[4] + " = " + std::to_string(logsys_categories_entry.log_to_gmsay));
|
||||
update_values.push_back(columns[5] + " = " + std::to_string(logsys_categories_entry.log_to_discord));
|
||||
update_values.push_back(columns[6] + " = " + std::to_string(logsys_categories_entry.discord_webhook_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -199,6 +211,8 @@ public:
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_console));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_file));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_gmsay));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_discord));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.discord_webhook_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -233,6 +247,8 @@ public:
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_console));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_file));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_gmsay));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_discord));
|
||||
insert_values.push_back(std::to_string(logsys_categories_entry.discord_webhook_id));
|
||||
|
||||
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||
}
|
||||
@@ -271,6 +287,8 @@ public:
|
||||
entry.log_to_console = atoi(row[2]);
|
||||
entry.log_to_file = atoi(row[3]);
|
||||
entry.log_to_gmsay = atoi(row[4]);
|
||||
entry.log_to_discord = atoi(row[5]);
|
||||
entry.discord_webhook_id = atoi(row[6]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
@@ -300,6 +318,8 @@ public:
|
||||
entry.log_to_console = atoi(row[2]);
|
||||
entry.log_to_file = atoi(row[3]);
|
||||
entry.log_to_gmsay = atoi(row[4]);
|
||||
entry.log_to_discord = atoi(row[5]);
|
||||
entry.discord_webhook_id = atoi(row[6]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -26,15 +26,16 @@ public:
|
||||
int race;
|
||||
int class_;
|
||||
int bodytype;
|
||||
int hp;
|
||||
int mana;
|
||||
int64 hp;
|
||||
int64 mana;
|
||||
int gender;
|
||||
int texture;
|
||||
int helmtexture;
|
||||
int herosforgemodel;
|
||||
float size;
|
||||
int hp_regen_rate;
|
||||
int mana_regen_rate;
|
||||
int64 hp_regen_rate;
|
||||
int64 hp_regen_per_second;
|
||||
int64 mana_regen_rate;
|
||||
int loottable_id;
|
||||
int merchant_id;
|
||||
int alt_currency_id;
|
||||
@@ -167,6 +168,7 @@ public:
|
||||
"herosforgemodel",
|
||||
"size",
|
||||
"hp_regen_rate",
|
||||
"hp_regen_per_second",
|
||||
"mana_regen_rate",
|
||||
"loottable_id",
|
||||
"merchant_id",
|
||||
@@ -296,6 +298,7 @@ public:
|
||||
"herosforgemodel",
|
||||
"size",
|
||||
"hp_regen_rate",
|
||||
"hp_regen_per_second",
|
||||
"mana_regen_rate",
|
||||
"loottable_id",
|
||||
"merchant_id",
|
||||
@@ -459,6 +462,7 @@ public:
|
||||
entry.herosforgemodel = 0;
|
||||
entry.size = 0;
|
||||
entry.hp_regen_rate = 0;
|
||||
entry.hp_regen_per_second = 0;
|
||||
entry.mana_regen_rate = 0;
|
||||
entry.loottable_id = 0;
|
||||
entry.merchant_id = 0;
|
||||
@@ -609,122 +613,123 @@ public:
|
||||
entry.race = atoi(row[4]);
|
||||
entry.class_ = atoi(row[5]);
|
||||
entry.bodytype = atoi(row[6]);
|
||||
entry.hp = atoi(row[7]);
|
||||
entry.mana = atoi(row[8]);
|
||||
entry.hp = strtoll(row[7], nullptr, 10);
|
||||
entry.mana = strtoll(row[8], nullptr, 10);
|
||||
entry.gender = atoi(row[9]);
|
||||
entry.texture = atoi(row[10]);
|
||||
entry.helmtexture = atoi(row[11]);
|
||||
entry.herosforgemodel = atoi(row[12]);
|
||||
entry.size = static_cast<float>(atof(row[13]));
|
||||
entry.hp_regen_rate = atoi(row[14]);
|
||||
entry.mana_regen_rate = atoi(row[15]);
|
||||
entry.loottable_id = atoi(row[16]);
|
||||
entry.merchant_id = atoi(row[17]);
|
||||
entry.alt_currency_id = atoi(row[18]);
|
||||
entry.npc_spells_id = atoi(row[19]);
|
||||
entry.npc_spells_effects_id = atoi(row[20]);
|
||||
entry.npc_faction_id = atoi(row[21]);
|
||||
entry.adventure_template_id = atoi(row[22]);
|
||||
entry.trap_template = atoi(row[23]);
|
||||
entry.mindmg = atoi(row[24]);
|
||||
entry.maxdmg = atoi(row[25]);
|
||||
entry.attack_count = atoi(row[26]);
|
||||
entry.npcspecialattks = row[27] ? row[27] : "";
|
||||
entry.special_abilities = row[28] ? row[28] : "";
|
||||
entry.aggroradius = atoi(row[29]);
|
||||
entry.assistradius = atoi(row[30]);
|
||||
entry.face = atoi(row[31]);
|
||||
entry.luclin_hairstyle = atoi(row[32]);
|
||||
entry.luclin_haircolor = atoi(row[33]);
|
||||
entry.luclin_eyecolor = atoi(row[34]);
|
||||
entry.luclin_eyecolor2 = atoi(row[35]);
|
||||
entry.luclin_beardcolor = atoi(row[36]);
|
||||
entry.luclin_beard = atoi(row[37]);
|
||||
entry.drakkin_heritage = atoi(row[38]);
|
||||
entry.drakkin_tattoo = atoi(row[39]);
|
||||
entry.drakkin_details = atoi(row[40]);
|
||||
entry.armortint_id = atoi(row[41]);
|
||||
entry.armortint_red = atoi(row[42]);
|
||||
entry.armortint_green = atoi(row[43]);
|
||||
entry.armortint_blue = atoi(row[44]);
|
||||
entry.d_melee_texture1 = atoi(row[45]);
|
||||
entry.d_melee_texture2 = atoi(row[46]);
|
||||
entry.ammo_idfile = row[47] ? row[47] : "";
|
||||
entry.prim_melee_type = atoi(row[48]);
|
||||
entry.sec_melee_type = atoi(row[49]);
|
||||
entry.ranged_type = atoi(row[50]);
|
||||
entry.runspeed = static_cast<float>(atof(row[51]));
|
||||
entry.MR = atoi(row[52]);
|
||||
entry.CR = atoi(row[53]);
|
||||
entry.DR = atoi(row[54]);
|
||||
entry.FR = atoi(row[55]);
|
||||
entry.PR = atoi(row[56]);
|
||||
entry.Corrup = atoi(row[57]);
|
||||
entry.PhR = atoi(row[58]);
|
||||
entry.see_invis = atoi(row[59]);
|
||||
entry.see_invis_undead = atoi(row[60]);
|
||||
entry.qglobal = atoi(row[61]);
|
||||
entry.AC = atoi(row[62]);
|
||||
entry.npc_aggro = atoi(row[63]);
|
||||
entry.spawn_limit = atoi(row[64]);
|
||||
entry.attack_speed = static_cast<float>(atof(row[65]));
|
||||
entry.attack_delay = atoi(row[66]);
|
||||
entry.findable = atoi(row[67]);
|
||||
entry.STR = atoi(row[68]);
|
||||
entry.STA = atoi(row[69]);
|
||||
entry.DEX = atoi(row[70]);
|
||||
entry.AGI = atoi(row[71]);
|
||||
entry._INT = atoi(row[72]);
|
||||
entry.WIS = atoi(row[73]);
|
||||
entry.CHA = atoi(row[74]);
|
||||
entry.see_hide = atoi(row[75]);
|
||||
entry.see_improved_hide = atoi(row[76]);
|
||||
entry.trackable = atoi(row[77]);
|
||||
entry.isbot = atoi(row[78]);
|
||||
entry.exclude = atoi(row[79]);
|
||||
entry.ATK = atoi(row[80]);
|
||||
entry.Accuracy = atoi(row[81]);
|
||||
entry.Avoidance = atoi(row[82]);
|
||||
entry.slow_mitigation = atoi(row[83]);
|
||||
entry.version = atoi(row[84]);
|
||||
entry.maxlevel = atoi(row[85]);
|
||||
entry.scalerate = atoi(row[86]);
|
||||
entry.private_corpse = atoi(row[87]);
|
||||
entry.unique_spawn_by_name = atoi(row[88]);
|
||||
entry.underwater = atoi(row[89]);
|
||||
entry.isquest = atoi(row[90]);
|
||||
entry.emoteid = atoi(row[91]);
|
||||
entry.spellscale = static_cast<float>(atof(row[92]));
|
||||
entry.healscale = static_cast<float>(atof(row[93]));
|
||||
entry.no_target_hotkey = atoi(row[94]);
|
||||
entry.raid_target = atoi(row[95]);
|
||||
entry.armtexture = atoi(row[96]);
|
||||
entry.bracertexture = atoi(row[97]);
|
||||
entry.handtexture = atoi(row[98]);
|
||||
entry.legtexture = atoi(row[99]);
|
||||
entry.feettexture = atoi(row[100]);
|
||||
entry.light = atoi(row[101]);
|
||||
entry.walkspeed = atoi(row[102]);
|
||||
entry.peqid = atoi(row[103]);
|
||||
entry.unique_ = atoi(row[104]);
|
||||
entry.fixed = atoi(row[105]);
|
||||
entry.ignore_despawn = atoi(row[106]);
|
||||
entry.show_name = atoi(row[107]);
|
||||
entry.untargetable = atoi(row[108]);
|
||||
entry.charm_ac = atoi(row[109]);
|
||||
entry.charm_min_dmg = atoi(row[110]);
|
||||
entry.charm_max_dmg = atoi(row[111]);
|
||||
entry.charm_attack_delay = atoi(row[112]);
|
||||
entry.charm_accuracy_rating = atoi(row[113]);
|
||||
entry.charm_avoidance_rating = atoi(row[114]);
|
||||
entry.charm_atk = atoi(row[115]);
|
||||
entry.skip_global_loot = atoi(row[116]);
|
||||
entry.rare_spawn = atoi(row[117]);
|
||||
entry.stuck_behavior = atoi(row[118]);
|
||||
entry.model = atoi(row[119]);
|
||||
entry.flymode = atoi(row[120]);
|
||||
entry.always_aggro = atoi(row[121]);
|
||||
entry.exp_mod = atoi(row[122]);
|
||||
entry.hp_regen_rate = strtoll(row[14], nullptr, 10);
|
||||
entry.hp_regen_per_second = strtoll(row[15], nullptr, 10);
|
||||
entry.mana_regen_rate = strtoll(row[16], nullptr, 10);
|
||||
entry.loottable_id = atoi(row[17]);
|
||||
entry.merchant_id = atoi(row[18]);
|
||||
entry.alt_currency_id = atoi(row[19]);
|
||||
entry.npc_spells_id = atoi(row[20]);
|
||||
entry.npc_spells_effects_id = atoi(row[21]);
|
||||
entry.npc_faction_id = atoi(row[22]);
|
||||
entry.adventure_template_id = atoi(row[23]);
|
||||
entry.trap_template = atoi(row[24]);
|
||||
entry.mindmg = atoi(row[25]);
|
||||
entry.maxdmg = atoi(row[26]);
|
||||
entry.attack_count = atoi(row[27]);
|
||||
entry.npcspecialattks = row[28] ? row[28] : "";
|
||||
entry.special_abilities = row[29] ? row[29] : "";
|
||||
entry.aggroradius = atoi(row[30]);
|
||||
entry.assistradius = atoi(row[31]);
|
||||
entry.face = atoi(row[32]);
|
||||
entry.luclin_hairstyle = atoi(row[33]);
|
||||
entry.luclin_haircolor = atoi(row[34]);
|
||||
entry.luclin_eyecolor = atoi(row[35]);
|
||||
entry.luclin_eyecolor2 = atoi(row[36]);
|
||||
entry.luclin_beardcolor = atoi(row[37]);
|
||||
entry.luclin_beard = atoi(row[38]);
|
||||
entry.drakkin_heritage = atoi(row[39]);
|
||||
entry.drakkin_tattoo = atoi(row[40]);
|
||||
entry.drakkin_details = atoi(row[41]);
|
||||
entry.armortint_id = atoi(row[42]);
|
||||
entry.armortint_red = atoi(row[43]);
|
||||
entry.armortint_green = atoi(row[44]);
|
||||
entry.armortint_blue = atoi(row[45]);
|
||||
entry.d_melee_texture1 = atoi(row[46]);
|
||||
entry.d_melee_texture2 = atoi(row[47]);
|
||||
entry.ammo_idfile = row[48] ? row[48] : "";
|
||||
entry.prim_melee_type = atoi(row[49]);
|
||||
entry.sec_melee_type = atoi(row[50]);
|
||||
entry.ranged_type = atoi(row[51]);
|
||||
entry.runspeed = static_cast<float>(atof(row[52]));
|
||||
entry.MR = atoi(row[53]);
|
||||
entry.CR = atoi(row[54]);
|
||||
entry.DR = atoi(row[55]);
|
||||
entry.FR = atoi(row[56]);
|
||||
entry.PR = atoi(row[57]);
|
||||
entry.Corrup = atoi(row[58]);
|
||||
entry.PhR = atoi(row[59]);
|
||||
entry.see_invis = atoi(row[60]);
|
||||
entry.see_invis_undead = atoi(row[61]);
|
||||
entry.qglobal = atoi(row[62]);
|
||||
entry.AC = atoi(row[63]);
|
||||
entry.npc_aggro = atoi(row[64]);
|
||||
entry.spawn_limit = atoi(row[65]);
|
||||
entry.attack_speed = static_cast<float>(atof(row[66]));
|
||||
entry.attack_delay = atoi(row[67]);
|
||||
entry.findable = atoi(row[68]);
|
||||
entry.STR = atoi(row[69]);
|
||||
entry.STA = atoi(row[70]);
|
||||
entry.DEX = atoi(row[71]);
|
||||
entry.AGI = atoi(row[72]);
|
||||
entry._INT = atoi(row[73]);
|
||||
entry.WIS = atoi(row[74]);
|
||||
entry.CHA = atoi(row[75]);
|
||||
entry.see_hide = atoi(row[76]);
|
||||
entry.see_improved_hide = atoi(row[77]);
|
||||
entry.trackable = atoi(row[78]);
|
||||
entry.isbot = atoi(row[79]);
|
||||
entry.exclude = atoi(row[80]);
|
||||
entry.ATK = atoi(row[81]);
|
||||
entry.Accuracy = atoi(row[82]);
|
||||
entry.Avoidance = atoi(row[83]);
|
||||
entry.slow_mitigation = atoi(row[84]);
|
||||
entry.version = atoi(row[85]);
|
||||
entry.maxlevel = atoi(row[86]);
|
||||
entry.scalerate = atoi(row[87]);
|
||||
entry.private_corpse = atoi(row[88]);
|
||||
entry.unique_spawn_by_name = atoi(row[89]);
|
||||
entry.underwater = atoi(row[90]);
|
||||
entry.isquest = atoi(row[91]);
|
||||
entry.emoteid = atoi(row[92]);
|
||||
entry.spellscale = static_cast<float>(atof(row[93]));
|
||||
entry.healscale = static_cast<float>(atof(row[94]));
|
||||
entry.no_target_hotkey = atoi(row[95]);
|
||||
entry.raid_target = atoi(row[96]);
|
||||
entry.armtexture = atoi(row[97]);
|
||||
entry.bracertexture = atoi(row[98]);
|
||||
entry.handtexture = atoi(row[99]);
|
||||
entry.legtexture = atoi(row[100]);
|
||||
entry.feettexture = atoi(row[101]);
|
||||
entry.light = atoi(row[102]);
|
||||
entry.walkspeed = atoi(row[103]);
|
||||
entry.peqid = atoi(row[104]);
|
||||
entry.unique_ = atoi(row[105]);
|
||||
entry.fixed = atoi(row[106]);
|
||||
entry.ignore_despawn = atoi(row[107]);
|
||||
entry.show_name = atoi(row[108]);
|
||||
entry.untargetable = atoi(row[109]);
|
||||
entry.charm_ac = atoi(row[110]);
|
||||
entry.charm_min_dmg = atoi(row[111]);
|
||||
entry.charm_max_dmg = atoi(row[112]);
|
||||
entry.charm_attack_delay = atoi(row[113]);
|
||||
entry.charm_accuracy_rating = atoi(row[114]);
|
||||
entry.charm_avoidance_rating = atoi(row[115]);
|
||||
entry.charm_atk = atoi(row[116]);
|
||||
entry.skip_global_loot = atoi(row[117]);
|
||||
entry.rare_spawn = atoi(row[118]);
|
||||
entry.stuck_behavior = atoi(row[119]);
|
||||
entry.model = atoi(row[120]);
|
||||
entry.flymode = atoi(row[121]);
|
||||
entry.always_aggro = atoi(row[122]);
|
||||
entry.exp_mod = atoi(row[123]);
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -772,114 +777,115 @@ public:
|
||||
update_values.push_back(columns[12] + " = " + std::to_string(npc_types_entry.herosforgemodel));
|
||||
update_values.push_back(columns[13] + " = " + std::to_string(npc_types_entry.size));
|
||||
update_values.push_back(columns[14] + " = " + std::to_string(npc_types_entry.hp_regen_rate));
|
||||
update_values.push_back(columns[15] + " = " + std::to_string(npc_types_entry.mana_regen_rate));
|
||||
update_values.push_back(columns[16] + " = " + std::to_string(npc_types_entry.loottable_id));
|
||||
update_values.push_back(columns[17] + " = " + std::to_string(npc_types_entry.merchant_id));
|
||||
update_values.push_back(columns[18] + " = " + std::to_string(npc_types_entry.alt_currency_id));
|
||||
update_values.push_back(columns[19] + " = " + std::to_string(npc_types_entry.npc_spells_id));
|
||||
update_values.push_back(columns[20] + " = " + std::to_string(npc_types_entry.npc_spells_effects_id));
|
||||
update_values.push_back(columns[21] + " = " + std::to_string(npc_types_entry.npc_faction_id));
|
||||
update_values.push_back(columns[22] + " = " + std::to_string(npc_types_entry.adventure_template_id));
|
||||
update_values.push_back(columns[23] + " = " + std::to_string(npc_types_entry.trap_template));
|
||||
update_values.push_back(columns[24] + " = " + std::to_string(npc_types_entry.mindmg));
|
||||
update_values.push_back(columns[25] + " = " + std::to_string(npc_types_entry.maxdmg));
|
||||
update_values.push_back(columns[26] + " = " + std::to_string(npc_types_entry.attack_count));
|
||||
update_values.push_back(columns[27] + " = '" + EscapeString(npc_types_entry.npcspecialattks) + "'");
|
||||
update_values.push_back(columns[28] + " = '" + EscapeString(npc_types_entry.special_abilities) + "'");
|
||||
update_values.push_back(columns[29] + " = " + std::to_string(npc_types_entry.aggroradius));
|
||||
update_values.push_back(columns[30] + " = " + std::to_string(npc_types_entry.assistradius));
|
||||
update_values.push_back(columns[31] + " = " + std::to_string(npc_types_entry.face));
|
||||
update_values.push_back(columns[32] + " = " + std::to_string(npc_types_entry.luclin_hairstyle));
|
||||
update_values.push_back(columns[33] + " = " + std::to_string(npc_types_entry.luclin_haircolor));
|
||||
update_values.push_back(columns[34] + " = " + std::to_string(npc_types_entry.luclin_eyecolor));
|
||||
update_values.push_back(columns[35] + " = " + std::to_string(npc_types_entry.luclin_eyecolor2));
|
||||
update_values.push_back(columns[36] + " = " + std::to_string(npc_types_entry.luclin_beardcolor));
|
||||
update_values.push_back(columns[37] + " = " + std::to_string(npc_types_entry.luclin_beard));
|
||||
update_values.push_back(columns[38] + " = " + std::to_string(npc_types_entry.drakkin_heritage));
|
||||
update_values.push_back(columns[39] + " = " + std::to_string(npc_types_entry.drakkin_tattoo));
|
||||
update_values.push_back(columns[40] + " = " + std::to_string(npc_types_entry.drakkin_details));
|
||||
update_values.push_back(columns[41] + " = " + std::to_string(npc_types_entry.armortint_id));
|
||||
update_values.push_back(columns[42] + " = " + std::to_string(npc_types_entry.armortint_red));
|
||||
update_values.push_back(columns[43] + " = " + std::to_string(npc_types_entry.armortint_green));
|
||||
update_values.push_back(columns[44] + " = " + std::to_string(npc_types_entry.armortint_blue));
|
||||
update_values.push_back(columns[45] + " = " + std::to_string(npc_types_entry.d_melee_texture1));
|
||||
update_values.push_back(columns[46] + " = " + std::to_string(npc_types_entry.d_melee_texture2));
|
||||
update_values.push_back(columns[47] + " = '" + EscapeString(npc_types_entry.ammo_idfile) + "'");
|
||||
update_values.push_back(columns[48] + " = " + std::to_string(npc_types_entry.prim_melee_type));
|
||||
update_values.push_back(columns[49] + " = " + std::to_string(npc_types_entry.sec_melee_type));
|
||||
update_values.push_back(columns[50] + " = " + std::to_string(npc_types_entry.ranged_type));
|
||||
update_values.push_back(columns[51] + " = " + std::to_string(npc_types_entry.runspeed));
|
||||
update_values.push_back(columns[52] + " = " + std::to_string(npc_types_entry.MR));
|
||||
update_values.push_back(columns[53] + " = " + std::to_string(npc_types_entry.CR));
|
||||
update_values.push_back(columns[54] + " = " + std::to_string(npc_types_entry.DR));
|
||||
update_values.push_back(columns[55] + " = " + std::to_string(npc_types_entry.FR));
|
||||
update_values.push_back(columns[56] + " = " + std::to_string(npc_types_entry.PR));
|
||||
update_values.push_back(columns[57] + " = " + std::to_string(npc_types_entry.Corrup));
|
||||
update_values.push_back(columns[58] + " = " + std::to_string(npc_types_entry.PhR));
|
||||
update_values.push_back(columns[59] + " = " + std::to_string(npc_types_entry.see_invis));
|
||||
update_values.push_back(columns[60] + " = " + std::to_string(npc_types_entry.see_invis_undead));
|
||||
update_values.push_back(columns[61] + " = " + std::to_string(npc_types_entry.qglobal));
|
||||
update_values.push_back(columns[62] + " = " + std::to_string(npc_types_entry.AC));
|
||||
update_values.push_back(columns[63] + " = " + std::to_string(npc_types_entry.npc_aggro));
|
||||
update_values.push_back(columns[64] + " = " + std::to_string(npc_types_entry.spawn_limit));
|
||||
update_values.push_back(columns[65] + " = " + std::to_string(npc_types_entry.attack_speed));
|
||||
update_values.push_back(columns[66] + " = " + std::to_string(npc_types_entry.attack_delay));
|
||||
update_values.push_back(columns[67] + " = " + std::to_string(npc_types_entry.findable));
|
||||
update_values.push_back(columns[68] + " = " + std::to_string(npc_types_entry.STR));
|
||||
update_values.push_back(columns[69] + " = " + std::to_string(npc_types_entry.STA));
|
||||
update_values.push_back(columns[70] + " = " + std::to_string(npc_types_entry.DEX));
|
||||
update_values.push_back(columns[71] + " = " + std::to_string(npc_types_entry.AGI));
|
||||
update_values.push_back(columns[72] + " = " + std::to_string(npc_types_entry._INT));
|
||||
update_values.push_back(columns[73] + " = " + std::to_string(npc_types_entry.WIS));
|
||||
update_values.push_back(columns[74] + " = " + std::to_string(npc_types_entry.CHA));
|
||||
update_values.push_back(columns[75] + " = " + std::to_string(npc_types_entry.see_hide));
|
||||
update_values.push_back(columns[76] + " = " + std::to_string(npc_types_entry.see_improved_hide));
|
||||
update_values.push_back(columns[77] + " = " + std::to_string(npc_types_entry.trackable));
|
||||
update_values.push_back(columns[78] + " = " + std::to_string(npc_types_entry.isbot));
|
||||
update_values.push_back(columns[79] + " = " + std::to_string(npc_types_entry.exclude));
|
||||
update_values.push_back(columns[80] + " = " + std::to_string(npc_types_entry.ATK));
|
||||
update_values.push_back(columns[81] + " = " + std::to_string(npc_types_entry.Accuracy));
|
||||
update_values.push_back(columns[82] + " = " + std::to_string(npc_types_entry.Avoidance));
|
||||
update_values.push_back(columns[83] + " = " + std::to_string(npc_types_entry.slow_mitigation));
|
||||
update_values.push_back(columns[84] + " = " + std::to_string(npc_types_entry.version));
|
||||
update_values.push_back(columns[85] + " = " + std::to_string(npc_types_entry.maxlevel));
|
||||
update_values.push_back(columns[86] + " = " + std::to_string(npc_types_entry.scalerate));
|
||||
update_values.push_back(columns[87] + " = " + std::to_string(npc_types_entry.private_corpse));
|
||||
update_values.push_back(columns[88] + " = " + std::to_string(npc_types_entry.unique_spawn_by_name));
|
||||
update_values.push_back(columns[89] + " = " + std::to_string(npc_types_entry.underwater));
|
||||
update_values.push_back(columns[90] + " = " + std::to_string(npc_types_entry.isquest));
|
||||
update_values.push_back(columns[91] + " = " + std::to_string(npc_types_entry.emoteid));
|
||||
update_values.push_back(columns[92] + " = " + std::to_string(npc_types_entry.spellscale));
|
||||
update_values.push_back(columns[93] + " = " + std::to_string(npc_types_entry.healscale));
|
||||
update_values.push_back(columns[94] + " = " + std::to_string(npc_types_entry.no_target_hotkey));
|
||||
update_values.push_back(columns[95] + " = " + std::to_string(npc_types_entry.raid_target));
|
||||
update_values.push_back(columns[96] + " = " + std::to_string(npc_types_entry.armtexture));
|
||||
update_values.push_back(columns[97] + " = " + std::to_string(npc_types_entry.bracertexture));
|
||||
update_values.push_back(columns[98] + " = " + std::to_string(npc_types_entry.handtexture));
|
||||
update_values.push_back(columns[99] + " = " + std::to_string(npc_types_entry.legtexture));
|
||||
update_values.push_back(columns[100] + " = " + std::to_string(npc_types_entry.feettexture));
|
||||
update_values.push_back(columns[101] + " = " + std::to_string(npc_types_entry.light));
|
||||
update_values.push_back(columns[102] + " = " + std::to_string(npc_types_entry.walkspeed));
|
||||
update_values.push_back(columns[103] + " = " + std::to_string(npc_types_entry.peqid));
|
||||
update_values.push_back(columns[104] + " = " + std::to_string(npc_types_entry.unique_));
|
||||
update_values.push_back(columns[105] + " = " + std::to_string(npc_types_entry.fixed));
|
||||
update_values.push_back(columns[106] + " = " + std::to_string(npc_types_entry.ignore_despawn));
|
||||
update_values.push_back(columns[107] + " = " + std::to_string(npc_types_entry.show_name));
|
||||
update_values.push_back(columns[108] + " = " + std::to_string(npc_types_entry.untargetable));
|
||||
update_values.push_back(columns[109] + " = " + std::to_string(npc_types_entry.charm_ac));
|
||||
update_values.push_back(columns[110] + " = " + std::to_string(npc_types_entry.charm_min_dmg));
|
||||
update_values.push_back(columns[111] + " = " + std::to_string(npc_types_entry.charm_max_dmg));
|
||||
update_values.push_back(columns[112] + " = " + std::to_string(npc_types_entry.charm_attack_delay));
|
||||
update_values.push_back(columns[113] + " = " + std::to_string(npc_types_entry.charm_accuracy_rating));
|
||||
update_values.push_back(columns[114] + " = " + std::to_string(npc_types_entry.charm_avoidance_rating));
|
||||
update_values.push_back(columns[115] + " = " + std::to_string(npc_types_entry.charm_atk));
|
||||
update_values.push_back(columns[116] + " = " + std::to_string(npc_types_entry.skip_global_loot));
|
||||
update_values.push_back(columns[117] + " = " + std::to_string(npc_types_entry.rare_spawn));
|
||||
update_values.push_back(columns[118] + " = " + std::to_string(npc_types_entry.stuck_behavior));
|
||||
update_values.push_back(columns[119] + " = " + std::to_string(npc_types_entry.model));
|
||||
update_values.push_back(columns[120] + " = " + std::to_string(npc_types_entry.flymode));
|
||||
update_values.push_back(columns[121] + " = " + std::to_string(npc_types_entry.always_aggro));
|
||||
update_values.push_back(columns[122] + " = " + std::to_string(npc_types_entry.exp_mod));
|
||||
update_values.push_back(columns[15] + " = " + std::to_string(npc_types_entry.hp_regen_per_second));
|
||||
update_values.push_back(columns[16] + " = " + std::to_string(npc_types_entry.mana_regen_rate));
|
||||
update_values.push_back(columns[17] + " = " + std::to_string(npc_types_entry.loottable_id));
|
||||
update_values.push_back(columns[18] + " = " + std::to_string(npc_types_entry.merchant_id));
|
||||
update_values.push_back(columns[19] + " = " + std::to_string(npc_types_entry.alt_currency_id));
|
||||
update_values.push_back(columns[20] + " = " + std::to_string(npc_types_entry.npc_spells_id));
|
||||
update_values.push_back(columns[21] + " = " + std::to_string(npc_types_entry.npc_spells_effects_id));
|
||||
update_values.push_back(columns[22] + " = " + std::to_string(npc_types_entry.npc_faction_id));
|
||||
update_values.push_back(columns[23] + " = " + std::to_string(npc_types_entry.adventure_template_id));
|
||||
update_values.push_back(columns[24] + " = " + std::to_string(npc_types_entry.trap_template));
|
||||
update_values.push_back(columns[25] + " = " + std::to_string(npc_types_entry.mindmg));
|
||||
update_values.push_back(columns[26] + " = " + std::to_string(npc_types_entry.maxdmg));
|
||||
update_values.push_back(columns[27] + " = " + std::to_string(npc_types_entry.attack_count));
|
||||
update_values.push_back(columns[28] + " = '" + EscapeString(npc_types_entry.npcspecialattks) + "'");
|
||||
update_values.push_back(columns[29] + " = '" + EscapeString(npc_types_entry.special_abilities) + "'");
|
||||
update_values.push_back(columns[30] + " = " + std::to_string(npc_types_entry.aggroradius));
|
||||
update_values.push_back(columns[31] + " = " + std::to_string(npc_types_entry.assistradius));
|
||||
update_values.push_back(columns[32] + " = " + std::to_string(npc_types_entry.face));
|
||||
update_values.push_back(columns[33] + " = " + std::to_string(npc_types_entry.luclin_hairstyle));
|
||||
update_values.push_back(columns[34] + " = " + std::to_string(npc_types_entry.luclin_haircolor));
|
||||
update_values.push_back(columns[35] + " = " + std::to_string(npc_types_entry.luclin_eyecolor));
|
||||
update_values.push_back(columns[36] + " = " + std::to_string(npc_types_entry.luclin_eyecolor2));
|
||||
update_values.push_back(columns[37] + " = " + std::to_string(npc_types_entry.luclin_beardcolor));
|
||||
update_values.push_back(columns[38] + " = " + std::to_string(npc_types_entry.luclin_beard));
|
||||
update_values.push_back(columns[39] + " = " + std::to_string(npc_types_entry.drakkin_heritage));
|
||||
update_values.push_back(columns[40] + " = " + std::to_string(npc_types_entry.drakkin_tattoo));
|
||||
update_values.push_back(columns[41] + " = " + std::to_string(npc_types_entry.drakkin_details));
|
||||
update_values.push_back(columns[42] + " = " + std::to_string(npc_types_entry.armortint_id));
|
||||
update_values.push_back(columns[43] + " = " + std::to_string(npc_types_entry.armortint_red));
|
||||
update_values.push_back(columns[44] + " = " + std::to_string(npc_types_entry.armortint_green));
|
||||
update_values.push_back(columns[45] + " = " + std::to_string(npc_types_entry.armortint_blue));
|
||||
update_values.push_back(columns[46] + " = " + std::to_string(npc_types_entry.d_melee_texture1));
|
||||
update_values.push_back(columns[47] + " = " + std::to_string(npc_types_entry.d_melee_texture2));
|
||||
update_values.push_back(columns[48] + " = '" + EscapeString(npc_types_entry.ammo_idfile) + "'");
|
||||
update_values.push_back(columns[49] + " = " + std::to_string(npc_types_entry.prim_melee_type));
|
||||
update_values.push_back(columns[50] + " = " + std::to_string(npc_types_entry.sec_melee_type));
|
||||
update_values.push_back(columns[51] + " = " + std::to_string(npc_types_entry.ranged_type));
|
||||
update_values.push_back(columns[52] + " = " + std::to_string(npc_types_entry.runspeed));
|
||||
update_values.push_back(columns[53] + " = " + std::to_string(npc_types_entry.MR));
|
||||
update_values.push_back(columns[54] + " = " + std::to_string(npc_types_entry.CR));
|
||||
update_values.push_back(columns[55] + " = " + std::to_string(npc_types_entry.DR));
|
||||
update_values.push_back(columns[56] + " = " + std::to_string(npc_types_entry.FR));
|
||||
update_values.push_back(columns[57] + " = " + std::to_string(npc_types_entry.PR));
|
||||
update_values.push_back(columns[58] + " = " + std::to_string(npc_types_entry.Corrup));
|
||||
update_values.push_back(columns[59] + " = " + std::to_string(npc_types_entry.PhR));
|
||||
update_values.push_back(columns[60] + " = " + std::to_string(npc_types_entry.see_invis));
|
||||
update_values.push_back(columns[61] + " = " + std::to_string(npc_types_entry.see_invis_undead));
|
||||
update_values.push_back(columns[62] + " = " + std::to_string(npc_types_entry.qglobal));
|
||||
update_values.push_back(columns[63] + " = " + std::to_string(npc_types_entry.AC));
|
||||
update_values.push_back(columns[64] + " = " + std::to_string(npc_types_entry.npc_aggro));
|
||||
update_values.push_back(columns[65] + " = " + std::to_string(npc_types_entry.spawn_limit));
|
||||
update_values.push_back(columns[66] + " = " + std::to_string(npc_types_entry.attack_speed));
|
||||
update_values.push_back(columns[67] + " = " + std::to_string(npc_types_entry.attack_delay));
|
||||
update_values.push_back(columns[68] + " = " + std::to_string(npc_types_entry.findable));
|
||||
update_values.push_back(columns[69] + " = " + std::to_string(npc_types_entry.STR));
|
||||
update_values.push_back(columns[70] + " = " + std::to_string(npc_types_entry.STA));
|
||||
update_values.push_back(columns[71] + " = " + std::to_string(npc_types_entry.DEX));
|
||||
update_values.push_back(columns[72] + " = " + std::to_string(npc_types_entry.AGI));
|
||||
update_values.push_back(columns[73] + " = " + std::to_string(npc_types_entry._INT));
|
||||
update_values.push_back(columns[74] + " = " + std::to_string(npc_types_entry.WIS));
|
||||
update_values.push_back(columns[75] + " = " + std::to_string(npc_types_entry.CHA));
|
||||
update_values.push_back(columns[76] + " = " + std::to_string(npc_types_entry.see_hide));
|
||||
update_values.push_back(columns[77] + " = " + std::to_string(npc_types_entry.see_improved_hide));
|
||||
update_values.push_back(columns[78] + " = " + std::to_string(npc_types_entry.trackable));
|
||||
update_values.push_back(columns[79] + " = " + std::to_string(npc_types_entry.isbot));
|
||||
update_values.push_back(columns[80] + " = " + std::to_string(npc_types_entry.exclude));
|
||||
update_values.push_back(columns[81] + " = " + std::to_string(npc_types_entry.ATK));
|
||||
update_values.push_back(columns[82] + " = " + std::to_string(npc_types_entry.Accuracy));
|
||||
update_values.push_back(columns[83] + " = " + std::to_string(npc_types_entry.Avoidance));
|
||||
update_values.push_back(columns[84] + " = " + std::to_string(npc_types_entry.slow_mitigation));
|
||||
update_values.push_back(columns[85] + " = " + std::to_string(npc_types_entry.version));
|
||||
update_values.push_back(columns[86] + " = " + std::to_string(npc_types_entry.maxlevel));
|
||||
update_values.push_back(columns[87] + " = " + std::to_string(npc_types_entry.scalerate));
|
||||
update_values.push_back(columns[88] + " = " + std::to_string(npc_types_entry.private_corpse));
|
||||
update_values.push_back(columns[89] + " = " + std::to_string(npc_types_entry.unique_spawn_by_name));
|
||||
update_values.push_back(columns[90] + " = " + std::to_string(npc_types_entry.underwater));
|
||||
update_values.push_back(columns[91] + " = " + std::to_string(npc_types_entry.isquest));
|
||||
update_values.push_back(columns[92] + " = " + std::to_string(npc_types_entry.emoteid));
|
||||
update_values.push_back(columns[93] + " = " + std::to_string(npc_types_entry.spellscale));
|
||||
update_values.push_back(columns[94] + " = " + std::to_string(npc_types_entry.healscale));
|
||||
update_values.push_back(columns[95] + " = " + std::to_string(npc_types_entry.no_target_hotkey));
|
||||
update_values.push_back(columns[96] + " = " + std::to_string(npc_types_entry.raid_target));
|
||||
update_values.push_back(columns[97] + " = " + std::to_string(npc_types_entry.armtexture));
|
||||
update_values.push_back(columns[98] + " = " + std::to_string(npc_types_entry.bracertexture));
|
||||
update_values.push_back(columns[99] + " = " + std::to_string(npc_types_entry.handtexture));
|
||||
update_values.push_back(columns[100] + " = " + std::to_string(npc_types_entry.legtexture));
|
||||
update_values.push_back(columns[101] + " = " + std::to_string(npc_types_entry.feettexture));
|
||||
update_values.push_back(columns[102] + " = " + std::to_string(npc_types_entry.light));
|
||||
update_values.push_back(columns[103] + " = " + std::to_string(npc_types_entry.walkspeed));
|
||||
update_values.push_back(columns[104] + " = " + std::to_string(npc_types_entry.peqid));
|
||||
update_values.push_back(columns[105] + " = " + std::to_string(npc_types_entry.unique_));
|
||||
update_values.push_back(columns[106] + " = " + std::to_string(npc_types_entry.fixed));
|
||||
update_values.push_back(columns[107] + " = " + std::to_string(npc_types_entry.ignore_despawn));
|
||||
update_values.push_back(columns[108] + " = " + std::to_string(npc_types_entry.show_name));
|
||||
update_values.push_back(columns[109] + " = " + std::to_string(npc_types_entry.untargetable));
|
||||
update_values.push_back(columns[110] + " = " + std::to_string(npc_types_entry.charm_ac));
|
||||
update_values.push_back(columns[111] + " = " + std::to_string(npc_types_entry.charm_min_dmg));
|
||||
update_values.push_back(columns[112] + " = " + std::to_string(npc_types_entry.charm_max_dmg));
|
||||
update_values.push_back(columns[113] + " = " + std::to_string(npc_types_entry.charm_attack_delay));
|
||||
update_values.push_back(columns[114] + " = " + std::to_string(npc_types_entry.charm_accuracy_rating));
|
||||
update_values.push_back(columns[115] + " = " + std::to_string(npc_types_entry.charm_avoidance_rating));
|
||||
update_values.push_back(columns[116] + " = " + std::to_string(npc_types_entry.charm_atk));
|
||||
update_values.push_back(columns[117] + " = " + std::to_string(npc_types_entry.skip_global_loot));
|
||||
update_values.push_back(columns[118] + " = " + std::to_string(npc_types_entry.rare_spawn));
|
||||
update_values.push_back(columns[119] + " = " + std::to_string(npc_types_entry.stuck_behavior));
|
||||
update_values.push_back(columns[120] + " = " + std::to_string(npc_types_entry.model));
|
||||
update_values.push_back(columns[121] + " = " + std::to_string(npc_types_entry.flymode));
|
||||
update_values.push_back(columns[122] + " = " + std::to_string(npc_types_entry.always_aggro));
|
||||
update_values.push_back(columns[123] + " = " + std::to_string(npc_types_entry.exp_mod));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -916,6 +922,7 @@ public:
|
||||
insert_values.push_back(std::to_string(npc_types_entry.herosforgemodel));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.size));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.hp_regen_rate));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.hp_regen_per_second));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.mana_regen_rate));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.loottable_id));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.merchant_id));
|
||||
@@ -1068,6 +1075,7 @@ public:
|
||||
insert_values.push_back(std::to_string(npc_types_entry.herosforgemodel));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.size));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.hp_regen_rate));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.hp_regen_per_second));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.mana_regen_rate));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.loottable_id));
|
||||
insert_values.push_back(std::to_string(npc_types_entry.merchant_id));
|
||||
@@ -1216,122 +1224,123 @@ public:
|
||||
entry.race = atoi(row[4]);
|
||||
entry.class_ = atoi(row[5]);
|
||||
entry.bodytype = atoi(row[6]);
|
||||
entry.hp = atoi(row[7]);
|
||||
entry.mana = atoi(row[8]);
|
||||
entry.hp = strtoll(row[7], nullptr, 10);
|
||||
entry.mana = strtoll(row[8], nullptr, 10);
|
||||
entry.gender = atoi(row[9]);
|
||||
entry.texture = atoi(row[10]);
|
||||
entry.helmtexture = atoi(row[11]);
|
||||
entry.herosforgemodel = atoi(row[12]);
|
||||
entry.size = static_cast<float>(atof(row[13]));
|
||||
entry.hp_regen_rate = atoi(row[14]);
|
||||
entry.mana_regen_rate = atoi(row[15]);
|
||||
entry.loottable_id = atoi(row[16]);
|
||||
entry.merchant_id = atoi(row[17]);
|
||||
entry.alt_currency_id = atoi(row[18]);
|
||||
entry.npc_spells_id = atoi(row[19]);
|
||||
entry.npc_spells_effects_id = atoi(row[20]);
|
||||
entry.npc_faction_id = atoi(row[21]);
|
||||
entry.adventure_template_id = atoi(row[22]);
|
||||
entry.trap_template = atoi(row[23]);
|
||||
entry.mindmg = atoi(row[24]);
|
||||
entry.maxdmg = atoi(row[25]);
|
||||
entry.attack_count = atoi(row[26]);
|
||||
entry.npcspecialattks = row[27] ? row[27] : "";
|
||||
entry.special_abilities = row[28] ? row[28] : "";
|
||||
entry.aggroradius = atoi(row[29]);
|
||||
entry.assistradius = atoi(row[30]);
|
||||
entry.face = atoi(row[31]);
|
||||
entry.luclin_hairstyle = atoi(row[32]);
|
||||
entry.luclin_haircolor = atoi(row[33]);
|
||||
entry.luclin_eyecolor = atoi(row[34]);
|
||||
entry.luclin_eyecolor2 = atoi(row[35]);
|
||||
entry.luclin_beardcolor = atoi(row[36]);
|
||||
entry.luclin_beard = atoi(row[37]);
|
||||
entry.drakkin_heritage = atoi(row[38]);
|
||||
entry.drakkin_tattoo = atoi(row[39]);
|
||||
entry.drakkin_details = atoi(row[40]);
|
||||
entry.armortint_id = atoi(row[41]);
|
||||
entry.armortint_red = atoi(row[42]);
|
||||
entry.armortint_green = atoi(row[43]);
|
||||
entry.armortint_blue = atoi(row[44]);
|
||||
entry.d_melee_texture1 = atoi(row[45]);
|
||||
entry.d_melee_texture2 = atoi(row[46]);
|
||||
entry.ammo_idfile = row[47] ? row[47] : "";
|
||||
entry.prim_melee_type = atoi(row[48]);
|
||||
entry.sec_melee_type = atoi(row[49]);
|
||||
entry.ranged_type = atoi(row[50]);
|
||||
entry.runspeed = static_cast<float>(atof(row[51]));
|
||||
entry.MR = atoi(row[52]);
|
||||
entry.CR = atoi(row[53]);
|
||||
entry.DR = atoi(row[54]);
|
||||
entry.FR = atoi(row[55]);
|
||||
entry.PR = atoi(row[56]);
|
||||
entry.Corrup = atoi(row[57]);
|
||||
entry.PhR = atoi(row[58]);
|
||||
entry.see_invis = atoi(row[59]);
|
||||
entry.see_invis_undead = atoi(row[60]);
|
||||
entry.qglobal = atoi(row[61]);
|
||||
entry.AC = atoi(row[62]);
|
||||
entry.npc_aggro = atoi(row[63]);
|
||||
entry.spawn_limit = atoi(row[64]);
|
||||
entry.attack_speed = static_cast<float>(atof(row[65]));
|
||||
entry.attack_delay = atoi(row[66]);
|
||||
entry.findable = atoi(row[67]);
|
||||
entry.STR = atoi(row[68]);
|
||||
entry.STA = atoi(row[69]);
|
||||
entry.DEX = atoi(row[70]);
|
||||
entry.AGI = atoi(row[71]);
|
||||
entry._INT = atoi(row[72]);
|
||||
entry.WIS = atoi(row[73]);
|
||||
entry.CHA = atoi(row[74]);
|
||||
entry.see_hide = atoi(row[75]);
|
||||
entry.see_improved_hide = atoi(row[76]);
|
||||
entry.trackable = atoi(row[77]);
|
||||
entry.isbot = atoi(row[78]);
|
||||
entry.exclude = atoi(row[79]);
|
||||
entry.ATK = atoi(row[80]);
|
||||
entry.Accuracy = atoi(row[81]);
|
||||
entry.Avoidance = atoi(row[82]);
|
||||
entry.slow_mitigation = atoi(row[83]);
|
||||
entry.version = atoi(row[84]);
|
||||
entry.maxlevel = atoi(row[85]);
|
||||
entry.scalerate = atoi(row[86]);
|
||||
entry.private_corpse = atoi(row[87]);
|
||||
entry.unique_spawn_by_name = atoi(row[88]);
|
||||
entry.underwater = atoi(row[89]);
|
||||
entry.isquest = atoi(row[90]);
|
||||
entry.emoteid = atoi(row[91]);
|
||||
entry.spellscale = static_cast<float>(atof(row[92]));
|
||||
entry.healscale = static_cast<float>(atof(row[93]));
|
||||
entry.no_target_hotkey = atoi(row[94]);
|
||||
entry.raid_target = atoi(row[95]);
|
||||
entry.armtexture = atoi(row[96]);
|
||||
entry.bracertexture = atoi(row[97]);
|
||||
entry.handtexture = atoi(row[98]);
|
||||
entry.legtexture = atoi(row[99]);
|
||||
entry.feettexture = atoi(row[100]);
|
||||
entry.light = atoi(row[101]);
|
||||
entry.walkspeed = atoi(row[102]);
|
||||
entry.peqid = atoi(row[103]);
|
||||
entry.unique_ = atoi(row[104]);
|
||||
entry.fixed = atoi(row[105]);
|
||||
entry.ignore_despawn = atoi(row[106]);
|
||||
entry.show_name = atoi(row[107]);
|
||||
entry.untargetable = atoi(row[108]);
|
||||
entry.charm_ac = atoi(row[109]);
|
||||
entry.charm_min_dmg = atoi(row[110]);
|
||||
entry.charm_max_dmg = atoi(row[111]);
|
||||
entry.charm_attack_delay = atoi(row[112]);
|
||||
entry.charm_accuracy_rating = atoi(row[113]);
|
||||
entry.charm_avoidance_rating = atoi(row[114]);
|
||||
entry.charm_atk = atoi(row[115]);
|
||||
entry.skip_global_loot = atoi(row[116]);
|
||||
entry.rare_spawn = atoi(row[117]);
|
||||
entry.stuck_behavior = atoi(row[118]);
|
||||
entry.model = atoi(row[119]);
|
||||
entry.flymode = atoi(row[120]);
|
||||
entry.always_aggro = atoi(row[121]);
|
||||
entry.exp_mod = atoi(row[122]);
|
||||
entry.hp_regen_rate = strtoll(row[14], nullptr, 10);
|
||||
entry.hp_regen_per_second = strtoll(row[15], nullptr, 10);
|
||||
entry.mana_regen_rate = strtoll(row[16], nullptr, 10);
|
||||
entry.loottable_id = atoi(row[17]);
|
||||
entry.merchant_id = atoi(row[18]);
|
||||
entry.alt_currency_id = atoi(row[19]);
|
||||
entry.npc_spells_id = atoi(row[20]);
|
||||
entry.npc_spells_effects_id = atoi(row[21]);
|
||||
entry.npc_faction_id = atoi(row[22]);
|
||||
entry.adventure_template_id = atoi(row[23]);
|
||||
entry.trap_template = atoi(row[24]);
|
||||
entry.mindmg = atoi(row[25]);
|
||||
entry.maxdmg = atoi(row[26]);
|
||||
entry.attack_count = atoi(row[27]);
|
||||
entry.npcspecialattks = row[28] ? row[28] : "";
|
||||
entry.special_abilities = row[29] ? row[29] : "";
|
||||
entry.aggroradius = atoi(row[30]);
|
||||
entry.assistradius = atoi(row[31]);
|
||||
entry.face = atoi(row[32]);
|
||||
entry.luclin_hairstyle = atoi(row[33]);
|
||||
entry.luclin_haircolor = atoi(row[34]);
|
||||
entry.luclin_eyecolor = atoi(row[35]);
|
||||
entry.luclin_eyecolor2 = atoi(row[36]);
|
||||
entry.luclin_beardcolor = atoi(row[37]);
|
||||
entry.luclin_beard = atoi(row[38]);
|
||||
entry.drakkin_heritage = atoi(row[39]);
|
||||
entry.drakkin_tattoo = atoi(row[40]);
|
||||
entry.drakkin_details = atoi(row[41]);
|
||||
entry.armortint_id = atoi(row[42]);
|
||||
entry.armortint_red = atoi(row[43]);
|
||||
entry.armortint_green = atoi(row[44]);
|
||||
entry.armortint_blue = atoi(row[45]);
|
||||
entry.d_melee_texture1 = atoi(row[46]);
|
||||
entry.d_melee_texture2 = atoi(row[47]);
|
||||
entry.ammo_idfile = row[48] ? row[48] : "";
|
||||
entry.prim_melee_type = atoi(row[49]);
|
||||
entry.sec_melee_type = atoi(row[50]);
|
||||
entry.ranged_type = atoi(row[51]);
|
||||
entry.runspeed = static_cast<float>(atof(row[52]));
|
||||
entry.MR = atoi(row[53]);
|
||||
entry.CR = atoi(row[54]);
|
||||
entry.DR = atoi(row[55]);
|
||||
entry.FR = atoi(row[56]);
|
||||
entry.PR = atoi(row[57]);
|
||||
entry.Corrup = atoi(row[58]);
|
||||
entry.PhR = atoi(row[59]);
|
||||
entry.see_invis = atoi(row[60]);
|
||||
entry.see_invis_undead = atoi(row[61]);
|
||||
entry.qglobal = atoi(row[62]);
|
||||
entry.AC = atoi(row[63]);
|
||||
entry.npc_aggro = atoi(row[64]);
|
||||
entry.spawn_limit = atoi(row[65]);
|
||||
entry.attack_speed = static_cast<float>(atof(row[66]));
|
||||
entry.attack_delay = atoi(row[67]);
|
||||
entry.findable = atoi(row[68]);
|
||||
entry.STR = atoi(row[69]);
|
||||
entry.STA = atoi(row[70]);
|
||||
entry.DEX = atoi(row[71]);
|
||||
entry.AGI = atoi(row[72]);
|
||||
entry._INT = atoi(row[73]);
|
||||
entry.WIS = atoi(row[74]);
|
||||
entry.CHA = atoi(row[75]);
|
||||
entry.see_hide = atoi(row[76]);
|
||||
entry.see_improved_hide = atoi(row[77]);
|
||||
entry.trackable = atoi(row[78]);
|
||||
entry.isbot = atoi(row[79]);
|
||||
entry.exclude = atoi(row[80]);
|
||||
entry.ATK = atoi(row[81]);
|
||||
entry.Accuracy = atoi(row[82]);
|
||||
entry.Avoidance = atoi(row[83]);
|
||||
entry.slow_mitigation = atoi(row[84]);
|
||||
entry.version = atoi(row[85]);
|
||||
entry.maxlevel = atoi(row[86]);
|
||||
entry.scalerate = atoi(row[87]);
|
||||
entry.private_corpse = atoi(row[88]);
|
||||
entry.unique_spawn_by_name = atoi(row[89]);
|
||||
entry.underwater = atoi(row[90]);
|
||||
entry.isquest = atoi(row[91]);
|
||||
entry.emoteid = atoi(row[92]);
|
||||
entry.spellscale = static_cast<float>(atof(row[93]));
|
||||
entry.healscale = static_cast<float>(atof(row[94]));
|
||||
entry.no_target_hotkey = atoi(row[95]);
|
||||
entry.raid_target = atoi(row[96]);
|
||||
entry.armtexture = atoi(row[97]);
|
||||
entry.bracertexture = atoi(row[98]);
|
||||
entry.handtexture = atoi(row[99]);
|
||||
entry.legtexture = atoi(row[100]);
|
||||
entry.feettexture = atoi(row[101]);
|
||||
entry.light = atoi(row[102]);
|
||||
entry.walkspeed = atoi(row[103]);
|
||||
entry.peqid = atoi(row[104]);
|
||||
entry.unique_ = atoi(row[105]);
|
||||
entry.fixed = atoi(row[106]);
|
||||
entry.ignore_despawn = atoi(row[107]);
|
||||
entry.show_name = atoi(row[108]);
|
||||
entry.untargetable = atoi(row[109]);
|
||||
entry.charm_ac = atoi(row[110]);
|
||||
entry.charm_min_dmg = atoi(row[111]);
|
||||
entry.charm_max_dmg = atoi(row[112]);
|
||||
entry.charm_attack_delay = atoi(row[113]);
|
||||
entry.charm_accuracy_rating = atoi(row[114]);
|
||||
entry.charm_avoidance_rating = atoi(row[115]);
|
||||
entry.charm_atk = atoi(row[116]);
|
||||
entry.skip_global_loot = atoi(row[117]);
|
||||
entry.rare_spawn = atoi(row[118]);
|
||||
entry.stuck_behavior = atoi(row[119]);
|
||||
entry.model = atoi(row[120]);
|
||||
entry.flymode = atoi(row[121]);
|
||||
entry.always_aggro = atoi(row[122]);
|
||||
entry.exp_mod = atoi(row[123]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
@@ -1363,122 +1372,123 @@ public:
|
||||
entry.race = atoi(row[4]);
|
||||
entry.class_ = atoi(row[5]);
|
||||
entry.bodytype = atoi(row[6]);
|
||||
entry.hp = atoi(row[7]);
|
||||
entry.mana = atoi(row[8]);
|
||||
entry.hp = strtoll(row[7], nullptr, 10);
|
||||
entry.mana = strtoll(row[8], nullptr, 10);
|
||||
entry.gender = atoi(row[9]);
|
||||
entry.texture = atoi(row[10]);
|
||||
entry.helmtexture = atoi(row[11]);
|
||||
entry.herosforgemodel = atoi(row[12]);
|
||||
entry.size = static_cast<float>(atof(row[13]));
|
||||
entry.hp_regen_rate = atoi(row[14]);
|
||||
entry.mana_regen_rate = atoi(row[15]);
|
||||
entry.loottable_id = atoi(row[16]);
|
||||
entry.merchant_id = atoi(row[17]);
|
||||
entry.alt_currency_id = atoi(row[18]);
|
||||
entry.npc_spells_id = atoi(row[19]);
|
||||
entry.npc_spells_effects_id = atoi(row[20]);
|
||||
entry.npc_faction_id = atoi(row[21]);
|
||||
entry.adventure_template_id = atoi(row[22]);
|
||||
entry.trap_template = atoi(row[23]);
|
||||
entry.mindmg = atoi(row[24]);
|
||||
entry.maxdmg = atoi(row[25]);
|
||||
entry.attack_count = atoi(row[26]);
|
||||
entry.npcspecialattks = row[27] ? row[27] : "";
|
||||
entry.special_abilities = row[28] ? row[28] : "";
|
||||
entry.aggroradius = atoi(row[29]);
|
||||
entry.assistradius = atoi(row[30]);
|
||||
entry.face = atoi(row[31]);
|
||||
entry.luclin_hairstyle = atoi(row[32]);
|
||||
entry.luclin_haircolor = atoi(row[33]);
|
||||
entry.luclin_eyecolor = atoi(row[34]);
|
||||
entry.luclin_eyecolor2 = atoi(row[35]);
|
||||
entry.luclin_beardcolor = atoi(row[36]);
|
||||
entry.luclin_beard = atoi(row[37]);
|
||||
entry.drakkin_heritage = atoi(row[38]);
|
||||
entry.drakkin_tattoo = atoi(row[39]);
|
||||
entry.drakkin_details = atoi(row[40]);
|
||||
entry.armortint_id = atoi(row[41]);
|
||||
entry.armortint_red = atoi(row[42]);
|
||||
entry.armortint_green = atoi(row[43]);
|
||||
entry.armortint_blue = atoi(row[44]);
|
||||
entry.d_melee_texture1 = atoi(row[45]);
|
||||
entry.d_melee_texture2 = atoi(row[46]);
|
||||
entry.ammo_idfile = row[47] ? row[47] : "";
|
||||
entry.prim_melee_type = atoi(row[48]);
|
||||
entry.sec_melee_type = atoi(row[49]);
|
||||
entry.ranged_type = atoi(row[50]);
|
||||
entry.runspeed = static_cast<float>(atof(row[51]));
|
||||
entry.MR = atoi(row[52]);
|
||||
entry.CR = atoi(row[53]);
|
||||
entry.DR = atoi(row[54]);
|
||||
entry.FR = atoi(row[55]);
|
||||
entry.PR = atoi(row[56]);
|
||||
entry.Corrup = atoi(row[57]);
|
||||
entry.PhR = atoi(row[58]);
|
||||
entry.see_invis = atoi(row[59]);
|
||||
entry.see_invis_undead = atoi(row[60]);
|
||||
entry.qglobal = atoi(row[61]);
|
||||
entry.AC = atoi(row[62]);
|
||||
entry.npc_aggro = atoi(row[63]);
|
||||
entry.spawn_limit = atoi(row[64]);
|
||||
entry.attack_speed = static_cast<float>(atof(row[65]));
|
||||
entry.attack_delay = atoi(row[66]);
|
||||
entry.findable = atoi(row[67]);
|
||||
entry.STR = atoi(row[68]);
|
||||
entry.STA = atoi(row[69]);
|
||||
entry.DEX = atoi(row[70]);
|
||||
entry.AGI = atoi(row[71]);
|
||||
entry._INT = atoi(row[72]);
|
||||
entry.WIS = atoi(row[73]);
|
||||
entry.CHA = atoi(row[74]);
|
||||
entry.see_hide = atoi(row[75]);
|
||||
entry.see_improved_hide = atoi(row[76]);
|
||||
entry.trackable = atoi(row[77]);
|
||||
entry.isbot = atoi(row[78]);
|
||||
entry.exclude = atoi(row[79]);
|
||||
entry.ATK = atoi(row[80]);
|
||||
entry.Accuracy = atoi(row[81]);
|
||||
entry.Avoidance = atoi(row[82]);
|
||||
entry.slow_mitigation = atoi(row[83]);
|
||||
entry.version = atoi(row[84]);
|
||||
entry.maxlevel = atoi(row[85]);
|
||||
entry.scalerate = atoi(row[86]);
|
||||
entry.private_corpse = atoi(row[87]);
|
||||
entry.unique_spawn_by_name = atoi(row[88]);
|
||||
entry.underwater = atoi(row[89]);
|
||||
entry.isquest = atoi(row[90]);
|
||||
entry.emoteid = atoi(row[91]);
|
||||
entry.spellscale = static_cast<float>(atof(row[92]));
|
||||
entry.healscale = static_cast<float>(atof(row[93]));
|
||||
entry.no_target_hotkey = atoi(row[94]);
|
||||
entry.raid_target = atoi(row[95]);
|
||||
entry.armtexture = atoi(row[96]);
|
||||
entry.bracertexture = atoi(row[97]);
|
||||
entry.handtexture = atoi(row[98]);
|
||||
entry.legtexture = atoi(row[99]);
|
||||
entry.feettexture = atoi(row[100]);
|
||||
entry.light = atoi(row[101]);
|
||||
entry.walkspeed = atoi(row[102]);
|
||||
entry.peqid = atoi(row[103]);
|
||||
entry.unique_ = atoi(row[104]);
|
||||
entry.fixed = atoi(row[105]);
|
||||
entry.ignore_despawn = atoi(row[106]);
|
||||
entry.show_name = atoi(row[107]);
|
||||
entry.untargetable = atoi(row[108]);
|
||||
entry.charm_ac = atoi(row[109]);
|
||||
entry.charm_min_dmg = atoi(row[110]);
|
||||
entry.charm_max_dmg = atoi(row[111]);
|
||||
entry.charm_attack_delay = atoi(row[112]);
|
||||
entry.charm_accuracy_rating = atoi(row[113]);
|
||||
entry.charm_avoidance_rating = atoi(row[114]);
|
||||
entry.charm_atk = atoi(row[115]);
|
||||
entry.skip_global_loot = atoi(row[116]);
|
||||
entry.rare_spawn = atoi(row[117]);
|
||||
entry.stuck_behavior = atoi(row[118]);
|
||||
entry.model = atoi(row[119]);
|
||||
entry.flymode = atoi(row[120]);
|
||||
entry.always_aggro = atoi(row[121]);
|
||||
entry.exp_mod = atoi(row[122]);
|
||||
entry.hp_regen_rate = strtoll(row[14], nullptr, 10);
|
||||
entry.hp_regen_per_second = strtoll(row[15], nullptr, 10);
|
||||
entry.mana_regen_rate = strtoll(row[16], nullptr, 10);
|
||||
entry.loottable_id = atoi(row[17]);
|
||||
entry.merchant_id = atoi(row[18]);
|
||||
entry.alt_currency_id = atoi(row[19]);
|
||||
entry.npc_spells_id = atoi(row[20]);
|
||||
entry.npc_spells_effects_id = atoi(row[21]);
|
||||
entry.npc_faction_id = atoi(row[22]);
|
||||
entry.adventure_template_id = atoi(row[23]);
|
||||
entry.trap_template = atoi(row[24]);
|
||||
entry.mindmg = atoi(row[25]);
|
||||
entry.maxdmg = atoi(row[26]);
|
||||
entry.attack_count = atoi(row[27]);
|
||||
entry.npcspecialattks = row[28] ? row[28] : "";
|
||||
entry.special_abilities = row[29] ? row[29] : "";
|
||||
entry.aggroradius = atoi(row[30]);
|
||||
entry.assistradius = atoi(row[31]);
|
||||
entry.face = atoi(row[32]);
|
||||
entry.luclin_hairstyle = atoi(row[33]);
|
||||
entry.luclin_haircolor = atoi(row[34]);
|
||||
entry.luclin_eyecolor = atoi(row[35]);
|
||||
entry.luclin_eyecolor2 = atoi(row[36]);
|
||||
entry.luclin_beardcolor = atoi(row[37]);
|
||||
entry.luclin_beard = atoi(row[38]);
|
||||
entry.drakkin_heritage = atoi(row[39]);
|
||||
entry.drakkin_tattoo = atoi(row[40]);
|
||||
entry.drakkin_details = atoi(row[41]);
|
||||
entry.armortint_id = atoi(row[42]);
|
||||
entry.armortint_red = atoi(row[43]);
|
||||
entry.armortint_green = atoi(row[44]);
|
||||
entry.armortint_blue = atoi(row[45]);
|
||||
entry.d_melee_texture1 = atoi(row[46]);
|
||||
entry.d_melee_texture2 = atoi(row[47]);
|
||||
entry.ammo_idfile = row[48] ? row[48] : "";
|
||||
entry.prim_melee_type = atoi(row[49]);
|
||||
entry.sec_melee_type = atoi(row[50]);
|
||||
entry.ranged_type = atoi(row[51]);
|
||||
entry.runspeed = static_cast<float>(atof(row[52]));
|
||||
entry.MR = atoi(row[53]);
|
||||
entry.CR = atoi(row[54]);
|
||||
entry.DR = atoi(row[55]);
|
||||
entry.FR = atoi(row[56]);
|
||||
entry.PR = atoi(row[57]);
|
||||
entry.Corrup = atoi(row[58]);
|
||||
entry.PhR = atoi(row[59]);
|
||||
entry.see_invis = atoi(row[60]);
|
||||
entry.see_invis_undead = atoi(row[61]);
|
||||
entry.qglobal = atoi(row[62]);
|
||||
entry.AC = atoi(row[63]);
|
||||
entry.npc_aggro = atoi(row[64]);
|
||||
entry.spawn_limit = atoi(row[65]);
|
||||
entry.attack_speed = static_cast<float>(atof(row[66]));
|
||||
entry.attack_delay = atoi(row[67]);
|
||||
entry.findable = atoi(row[68]);
|
||||
entry.STR = atoi(row[69]);
|
||||
entry.STA = atoi(row[70]);
|
||||
entry.DEX = atoi(row[71]);
|
||||
entry.AGI = atoi(row[72]);
|
||||
entry._INT = atoi(row[73]);
|
||||
entry.WIS = atoi(row[74]);
|
||||
entry.CHA = atoi(row[75]);
|
||||
entry.see_hide = atoi(row[76]);
|
||||
entry.see_improved_hide = atoi(row[77]);
|
||||
entry.trackable = atoi(row[78]);
|
||||
entry.isbot = atoi(row[79]);
|
||||
entry.exclude = atoi(row[80]);
|
||||
entry.ATK = atoi(row[81]);
|
||||
entry.Accuracy = atoi(row[82]);
|
||||
entry.Avoidance = atoi(row[83]);
|
||||
entry.slow_mitigation = atoi(row[84]);
|
||||
entry.version = atoi(row[85]);
|
||||
entry.maxlevel = atoi(row[86]);
|
||||
entry.scalerate = atoi(row[87]);
|
||||
entry.private_corpse = atoi(row[88]);
|
||||
entry.unique_spawn_by_name = atoi(row[89]);
|
||||
entry.underwater = atoi(row[90]);
|
||||
entry.isquest = atoi(row[91]);
|
||||
entry.emoteid = atoi(row[92]);
|
||||
entry.spellscale = static_cast<float>(atof(row[93]));
|
||||
entry.healscale = static_cast<float>(atof(row[94]));
|
||||
entry.no_target_hotkey = atoi(row[95]);
|
||||
entry.raid_target = atoi(row[96]);
|
||||
entry.armtexture = atoi(row[97]);
|
||||
entry.bracertexture = atoi(row[98]);
|
||||
entry.handtexture = atoi(row[99]);
|
||||
entry.legtexture = atoi(row[100]);
|
||||
entry.feettexture = atoi(row[101]);
|
||||
entry.light = atoi(row[102]);
|
||||
entry.walkspeed = atoi(row[103]);
|
||||
entry.peqid = atoi(row[104]);
|
||||
entry.unique_ = atoi(row[105]);
|
||||
entry.fixed = atoi(row[106]);
|
||||
entry.ignore_despawn = atoi(row[107]);
|
||||
entry.show_name = atoi(row[108]);
|
||||
entry.untargetable = atoi(row[109]);
|
||||
entry.charm_ac = atoi(row[110]);
|
||||
entry.charm_min_dmg = atoi(row[111]);
|
||||
entry.charm_max_dmg = atoi(row[112]);
|
||||
entry.charm_attack_delay = atoi(row[113]);
|
||||
entry.charm_accuracy_rating = atoi(row[114]);
|
||||
entry.charm_avoidance_rating = atoi(row[115]);
|
||||
entry.charm_atk = atoi(row[116]);
|
||||
entry.skip_global_loot = atoi(row[117]);
|
||||
entry.rare_spawn = atoi(row[118]);
|
||||
entry.stuck_behavior = atoi(row[119]);
|
||||
entry.model = atoi(row[120]);
|
||||
entry.flymode = atoi(row[121]);
|
||||
entry.always_aggro = atoi(row[122]);
|
||||
entry.exp_mod = atoi(row[123]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
std::string spell_list;
|
||||
std::string description_override;
|
||||
int goalid;
|
||||
std::string goal_match_list;
|
||||
int goalmethod;
|
||||
int goalcount;
|
||||
int delivertonpc;
|
||||
@@ -54,6 +55,7 @@ public:
|
||||
"spell_list",
|
||||
"description_override",
|
||||
"goalid",
|
||||
"goal_match_list",
|
||||
"goalmethod",
|
||||
"goalcount",
|
||||
"delivertonpc",
|
||||
@@ -75,6 +77,7 @@ public:
|
||||
"spell_list",
|
||||
"description_override",
|
||||
"goalid",
|
||||
"goal_match_list",
|
||||
"goalmethod",
|
||||
"goalcount",
|
||||
"delivertonpc",
|
||||
@@ -130,6 +133,7 @@ public:
|
||||
entry.spell_list = "0";
|
||||
entry.description_override = "";
|
||||
entry.goalid = 0;
|
||||
entry.goal_match_list = "";
|
||||
entry.goalmethod = 0;
|
||||
entry.goalcount = 1;
|
||||
entry.delivertonpc = 0;
|
||||
@@ -180,11 +184,12 @@ public:
|
||||
entry.spell_list = row[7] ? row[7] : "";
|
||||
entry.description_override = row[8] ? row[8] : "";
|
||||
entry.goalid = atoi(row[9]);
|
||||
entry.goalmethod = atoi(row[10]);
|
||||
entry.goalcount = atoi(row[11]);
|
||||
entry.delivertonpc = atoi(row[12]);
|
||||
entry.zones = row[13] ? row[13] : "";
|
||||
entry.optional = atoi(row[14]);
|
||||
entry.goal_match_list = row[10] ? row[10] : "";
|
||||
entry.goalmethod = atoi(row[11]);
|
||||
entry.goalcount = atoi(row[12]);
|
||||
entry.delivertonpc = atoi(row[13]);
|
||||
entry.zones = row[14] ? row[14] : "";
|
||||
entry.optional = atoi(row[15]);
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -228,11 +233,12 @@ public:
|
||||
update_values.push_back(columns[7] + " = '" + EscapeString(task_activities_entry.spell_list) + "'");
|
||||
update_values.push_back(columns[8] + " = '" + EscapeString(task_activities_entry.description_override) + "'");
|
||||
update_values.push_back(columns[9] + " = " + std::to_string(task_activities_entry.goalid));
|
||||
update_values.push_back(columns[10] + " = " + std::to_string(task_activities_entry.goalmethod));
|
||||
update_values.push_back(columns[11] + " = " + std::to_string(task_activities_entry.goalcount));
|
||||
update_values.push_back(columns[12] + " = " + std::to_string(task_activities_entry.delivertonpc));
|
||||
update_values.push_back(columns[13] + " = '" + EscapeString(task_activities_entry.zones) + "'");
|
||||
update_values.push_back(columns[14] + " = " + std::to_string(task_activities_entry.optional));
|
||||
update_values.push_back(columns[10] + " = '" + EscapeString(task_activities_entry.goal_match_list) + "'");
|
||||
update_values.push_back(columns[11] + " = " + std::to_string(task_activities_entry.goalmethod));
|
||||
update_values.push_back(columns[12] + " = " + std::to_string(task_activities_entry.goalcount));
|
||||
update_values.push_back(columns[13] + " = " + std::to_string(task_activities_entry.delivertonpc));
|
||||
update_values.push_back(columns[14] + " = '" + EscapeString(task_activities_entry.zones) + "'");
|
||||
update_values.push_back(columns[15] + " = " + std::to_string(task_activities_entry.optional));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -264,6 +270,7 @@ public:
|
||||
insert_values.push_back("'" + EscapeString(task_activities_entry.spell_list) + "'");
|
||||
insert_values.push_back("'" + EscapeString(task_activities_entry.description_override) + "'");
|
||||
insert_values.push_back(std::to_string(task_activities_entry.goalid));
|
||||
insert_values.push_back("'" + EscapeString(task_activities_entry.goal_match_list) + "'");
|
||||
insert_values.push_back(std::to_string(task_activities_entry.goalmethod));
|
||||
insert_values.push_back(std::to_string(task_activities_entry.goalcount));
|
||||
insert_values.push_back(std::to_string(task_activities_entry.delivertonpc));
|
||||
@@ -308,6 +315,7 @@ public:
|
||||
insert_values.push_back("'" + EscapeString(task_activities_entry.spell_list) + "'");
|
||||
insert_values.push_back("'" + EscapeString(task_activities_entry.description_override) + "'");
|
||||
insert_values.push_back(std::to_string(task_activities_entry.goalid));
|
||||
insert_values.push_back("'" + EscapeString(task_activities_entry.goal_match_list) + "'");
|
||||
insert_values.push_back(std::to_string(task_activities_entry.goalmethod));
|
||||
insert_values.push_back(std::to_string(task_activities_entry.goalcount));
|
||||
insert_values.push_back(std::to_string(task_activities_entry.delivertonpc));
|
||||
@@ -356,11 +364,12 @@ public:
|
||||
entry.spell_list = row[7] ? row[7] : "";
|
||||
entry.description_override = row[8] ? row[8] : "";
|
||||
entry.goalid = atoi(row[9]);
|
||||
entry.goalmethod = atoi(row[10]);
|
||||
entry.goalcount = atoi(row[11]);
|
||||
entry.delivertonpc = atoi(row[12]);
|
||||
entry.zones = row[13] ? row[13] : "";
|
||||
entry.optional = atoi(row[14]);
|
||||
entry.goal_match_list = row[10] ? row[10] : "";
|
||||
entry.goalmethod = atoi(row[11]);
|
||||
entry.goalcount = atoi(row[12]);
|
||||
entry.delivertonpc = atoi(row[13]);
|
||||
entry.zones = row[14] ? row[14] : "";
|
||||
entry.optional = atoi(row[15]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
@@ -395,11 +404,12 @@ public:
|
||||
entry.spell_list = row[7] ? row[7] : "";
|
||||
entry.description_override = row[8] ? row[8] : "";
|
||||
entry.goalid = atoi(row[9]);
|
||||
entry.goalmethod = atoi(row[10]);
|
||||
entry.goalcount = atoi(row[11]);
|
||||
entry.delivertonpc = atoi(row[12]);
|
||||
entry.zones = row[13] ? row[13] : "";
|
||||
entry.optional = atoi(row[14]);
|
||||
entry.goal_match_list = row[10] ? row[10] : "";
|
||||
entry.goalmethod = atoi(row[11]);
|
||||
entry.goalcount = atoi(row[12]);
|
||||
entry.delivertonpc = atoi(row[13]);
|
||||
entry.zones = row[14] ? row[14] : "";
|
||||
entry.optional = atoi(row[15]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 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_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||
#define EQEMU_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../string_util.h"
|
||||
#include "base/base_discord_webhooks_repository.h"
|
||||
|
||||
class DiscordWebhooksRepository: public BaseDiscordWebhooksRepository {
|
||||
public:
|
||||
|
||||
/**
|
||||
* This file was auto generated and can be modified and extended upon
|
||||
*
|
||||
* Base repository methods are automatically
|
||||
* generated in the "base" version of this repository. The base repository
|
||||
* is immutable and to be left untouched, while methods in this class
|
||||
* are used as extension methods for more specific persistence-layer
|
||||
* accessors or mutators.
|
||||
*
|
||||
* Base Methods (Subject to be expanded upon in time)
|
||||
*
|
||||
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||
*
|
||||
* InsertOne
|
||||
* UpdateOne
|
||||
* DeleteOne
|
||||
* FindOne
|
||||
* GetWhere(std::string where_filter)
|
||||
* DeleteWhere(std::string where_filter)
|
||||
* InsertMany
|
||||
* All
|
||||
*
|
||||
* Example custom methods in a repository
|
||||
*
|
||||
* DiscordWebhooksRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||
* DiscordWebhooksRepository::GetWhereNeverExpires()
|
||||
* DiscordWebhooksRepository::GetWhereXAndY()
|
||||
* DiscordWebhooksRepository::DeleteWhereXAndY()
|
||||
*
|
||||
* Most of the above could be covered by base methods, but if you as a developer
|
||||
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||
* method and encapsulate filters there
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||
@@ -109,10 +109,10 @@ public:
|
||||
entry.gridid = atoi(row[0]);
|
||||
entry.zoneid = atoi(row[1]);
|
||||
entry.number = atoi(row[2]);
|
||||
entry.x = atof(row[3]);
|
||||
entry.y = atof(row[4]);
|
||||
entry.z = atof(row[5]);
|
||||
entry.heading = atof(row[6]);
|
||||
entry.x = static_cast<float>(atof(row[3]));
|
||||
entry.y = static_cast<float>(atof(row[4]));
|
||||
entry.z = static_cast<float>(atof(row[5]));
|
||||
entry.heading = static_cast<float>(atof(row[6]));
|
||||
entry.pause = atoi(row[7]);
|
||||
entry.centerpoint = atoi(row[8]);
|
||||
|
||||
|
||||
+9
-9
@@ -246,7 +246,7 @@ const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) {
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
int ruleset_id = 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);
|
||||
@@ -309,7 +309,7 @@ bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool r
|
||||
}
|
||||
|
||||
void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
|
||||
|
||||
if (ruleset_name != nullptr) {
|
||||
//saving to a specific name
|
||||
if (m_activeName != ruleset_name) {
|
||||
@@ -347,7 +347,7 @@ void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
return;
|
||||
if (type == BoolRule && strcasecmp(_GetRuleName(type, index), "World:UseClientBasedExpansionSettings") == 0)
|
||||
return;
|
||||
|
||||
|
||||
switch (type) {
|
||||
case IntRule:
|
||||
sprintf(value_string, "%d", m_RuleIntValues[index]);
|
||||
@@ -432,7 +432,7 @@ bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bo
|
||||
|
||||
// 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()) {
|
||||
|
||||
@@ -440,7 +440,7 @@ bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bo
|
||||
std::tuple<int, std::string, std::string, std::string>(
|
||||
ruleset_id, // `ruleset_id`
|
||||
rd_iter.first, // `rule_name`
|
||||
rd_iter.second.first, // `rule_value`
|
||||
rd_iter.second.first, // `rule_value`
|
||||
EscapeString(*rd_iter.second.second) // `notes`
|
||||
)
|
||||
);
|
||||
@@ -481,7 +481,7 @@ bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bo
|
||||
ruleset_id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update)
|
||||
|
||||
// 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()) {
|
||||
|
||||
@@ -539,7 +539,7 @@ bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update)
|
||||
|
||||
LogInfo("[{}] Orphaned Rule(s) Deleted from [All Rulesets] (-1)", orphaned_rule_entries.size());
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -586,7 +586,7 @@ bool RuleManager::RestoreRuleNotes(Database *db)
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
++update_count;
|
||||
}
|
||||
|
||||
|
||||
+20
-41
@@ -150,8 +150,6 @@ RULE_INT(Character, InvSnapshotMinRetryM, 30, "Time to re-attempt an inventory s
|
||||
RULE_INT(Character, InvSnapshotHistoryD, 30, "Time to keep snapshot entries (days)")
|
||||
RULE_BOOL(Character, RestrictSpellScribing, false, "Setting whether to restrict spell scribing to allowable races/classes of spell scroll")
|
||||
RULE_BOOL(Character, UseStackablePickPocketing, true, "Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots")
|
||||
RULE_BOOL(Character, EnableAvoidanceCap, false, "Setting whether the avoidance cap should be activated")
|
||||
RULE_INT(Character, AvoidanceCap, 750, "750 Is a pretty good value, seen people dodge all attacks beyond 1,000 Avoidance")
|
||||
RULE_BOOL(Character, AllowMQTarget, false, "Disables putting players in the 'hackers' list for targeting beyond the clip plane or attempting to target something untargetable")
|
||||
RULE_BOOL(Character, UseOldBindWound, false, "Uses the original bind wound behavior")
|
||||
RULE_BOOL(Character, GrantHoTTOnCreate, false, "Grant Health of Target's Target leadership AA on character creation")
|
||||
@@ -350,7 +348,6 @@ RULE_INT(Spells, MaxTotalSlotsPET, 30, "Maximum total of pet slots. The default
|
||||
RULE_BOOL (Spells, EnableBlockedBuffs, true, "Allow blocked spells")
|
||||
RULE_INT(Spells, ReflectType, 4, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells")
|
||||
RULE_BOOL(Spells, ReflectMessagesClose, true, "True (Live functionality) is for Reflect messages to show to players within close proximity. False shows just player reflecting")
|
||||
RULE_INT(Spells, VirusSpreadDistance, 30, "The distance a viral spell will jump to its next victim")
|
||||
RULE_BOOL(Spells, LiveLikeFocusEffects, true, "Determines whether specific healing, dmg and mana reduction focuses are randomized")
|
||||
RULE_INT(Spells, BaseImmunityLevel, 55, "The level that targets start to be immune to stun, fear and mez spells with a maximum level of 0")
|
||||
RULE_BOOL(Spells, NPCIgnoreBaseImmunity, true, "Whether or not NPC get to ignore the BaseImmunityLevel for their spells")
|
||||
@@ -417,6 +414,9 @@ RULE_BOOL(Spells, CompoundLifetapHeals, true, "True: Lifetap heals calculate dam
|
||||
RULE_BOOL(Spells, UseFadingMemoriesMaxLevel, false, "Enables to limit field in spell data to set the max level that over which an NPC will ignore fading memories effect and not lose aggro.")
|
||||
RULE_BOOL(Spells, FixBeaconHeading, false, "Beacon spells use casters heading to fix live bug. False: Live like heading always 0.")
|
||||
RULE_BOOL(Spells, UseSpellImpliedTargeting, false, "Replicates EQ2-style targeting behavior for spells. Spells will 'pass through' inappropriate targets to target's target if it is appropriate.")
|
||||
RULE_BOOL(Spells, BuffsFadeOnDeath, true, "Disable to keep buffs from fading on death")
|
||||
RULE_BOOL(Spells, IllusionsAlwaysPersist, false, "Allows Illusions to persist beyond death and zoning always.")
|
||||
RULE_BOOL(Spells, UseItemCastMessage, false, "Enable to use the \"item begins to glow\" messages when casting from an item.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
@@ -441,17 +441,6 @@ RULE_REAL(Combat, AvgProcsPerMinute, 2.0, "Average proc rate per minute")
|
||||
RULE_REAL(Combat, ProcPerMinDexContrib, 0.075, "Increases the probability of a proc increased by DEX by the value indicated")
|
||||
RULE_REAL(Combat, BaseProcChance, 0.035, "Base chance for procs")
|
||||
RULE_REAL(Combat, ProcDexDivideBy, 11000, "Divisor for the probability of a proc increased by dexterity")
|
||||
RULE_REAL(Combat, BaseHitChance, 69.0, "Base chance to hit")
|
||||
RULE_REAL(Combat, NPCBonusHitChance, 26.0, "Bonus chance to hit for NPC")
|
||||
RULE_REAL(Combat, HitFalloffMinor, 5.0, "Hit will fall off up to value over the initial level range (percent)")
|
||||
RULE_REAL(Combat, HitFalloffModerate, 7.0, "Hit will fall off up to value over the three levels after the initial level range (percent)")
|
||||
RULE_REAL(Combat, HitFalloffMajor, 50.0, "Hit will fall off sharply if we're outside the minor and moderate range")
|
||||
RULE_REAL(Combat, HitBonusPerLevel, 1.2, "You gain this percentage of hit for every level you are above your target")
|
||||
RULE_REAL(Combat, WeaponSkillFalloff, 0.33, "For every weapon skill point that's not maxed you lose this percentage of hit")
|
||||
RULE_REAL(Combat, ArcheryHitPenalty, 0.25, "Archery has a hit penalty to try to help balance it with the plethora of long term +hit modifiers for it")
|
||||
RULE_REAL(Combat, AgiHitFactor, 0.01, "Factor with which agility is taken into account in the hit probability. Higher is better")
|
||||
RULE_REAL(Combat, MinChancetoHit, 5.0, "Minimum percentage chance to hit with regular melee/ranged")
|
||||
RULE_REAL(Combat, MaxChancetoHit, 95.0, "Maximum percentage chance to hit with regular melee/ranged")
|
||||
RULE_INT(Combat, MinRangedAttackDist, 25, "Minimum Distance to use Ranged Attacks")
|
||||
RULE_BOOL(Combat, ArcheryBonusRequiresStationary, true, "does the 2x archery bonus chance require a stationary npc")
|
||||
RULE_REAL(Combat, ArcheryNPCMultiplier, 1.0, "Value is multiplied by the regular dmg to get the archery dmg")
|
||||
@@ -460,40 +449,13 @@ RULE_INT(Combat, MaxRampageTargets, 3, "Maximum number of people hit with rampag
|
||||
RULE_INT(Combat, DefaultRampageTargets, 1, "Default number of people to hit with rampage")
|
||||
RULE_BOOL(Combat, RampageHitsTarget, false, "Rampage will hit the target if it still has targets left")
|
||||
RULE_INT(Combat, MaxFlurryHits, 2, "Maximum number of extra hits from flurry")
|
||||
RULE_REAL(Combat, NPCACFactor, 2.25, "If UseIntervalAC is enabled, the armor class for NPC is divided by this value")
|
||||
RULE_INT(Combat, ClothACSoftcap, 75, "If OldACSoftcapRules is true: armorclass softcap for cloth armor")
|
||||
RULE_INT(Combat, LeatherACSoftcap, 100, "If OldACSoftcapRules is true: armorclass softcap for leather armor")
|
||||
RULE_INT(Combat, MonkACSoftcap, 120, "If OldACSoftcapRules is true: armorclass softcap for monks")
|
||||
RULE_INT(Combat, ChainACSoftcap, 200, "If OldACSoftcapRules is true: armorclass softcap for chain armor")
|
||||
RULE_INT(Combat, PlateACSoftcap, 300, "If OldACSoftcapRules is true: armorclass softcap for plate armor")
|
||||
RULE_REAL(Combat, AAMitigationACFactor, 3.0, "If OldACSoftcapRules: AA mitgation armorclass factor")
|
||||
RULE_REAL(Combat, WarriorACSoftcapReturn, 0.45, "If OldACSoftcapRules: warrior armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, KnightACSoftcapReturn, 0.33, "If OldACSoftcapRules: SHD/PAL/MNK armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, LowPlateChainACSoftcapReturn, 0.23, "If OldACSoftcapRules: CLR/BRD/BSK/ROG/SHA/MNK armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, LowChainLeatherACSoftcapReturn, 0.17, "If OldACSoftcapRules: RNG/BST armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, CasterACSoftcapReturn, 0.06, "If OldACSoftcapRules: WIZ/MAG/NEC/ENC/DRU armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, MiscACSoftcapReturn, 0.3, "If OldACSoftcapRules true/false: unspecified classes armorclass softcap increase-factor")
|
||||
RULE_BOOL(Combat, OldACSoftcapRules, false, "Setting if the old softcap values should be used")
|
||||
RULE_BOOL(Combat, UseOldDamageIntervalRules, false, "Use old damage formulas for everything")
|
||||
RULE_REAL(Combat, WarACSoftcapReturn, 0.3448, "WAR armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, ClrRngMnkBrdACSoftcapReturn, 0.3030, "CLR/RNG/MNK/BRD armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, PalShdACSoftcapReturn, 0.3226, "SHD/PAL armorclass softcap increase-factor")
|
||||
RULE_REAL(Combat, DruNecWizEncMagACSoftcapReturn, 0.2000, "DRU/NEC/WIZ/ENC/MAG softcap increase-factor")
|
||||
RULE_REAL(Combat, RogShmBstBerACSoftcapReturn, 0.2500, "ROG/SHM/BST/BER softcap increase-factor")
|
||||
RULE_REAL(Combat, SoftcapFactor, 1.88, "When UseIntervalAC is enabled, the softcap for mitigation capability is multiplied by this value")
|
||||
RULE_REAL(Combat, ACthac0Factor, 0.55, "If a mob is attacked and the attack roll is greater than his defense roll, the attack rating is multiplied by this value")
|
||||
RULE_REAL(Combat, ACthac20Factor, 0.55, "If a mob is attacked and his defense roll is greater than the attack roll, the attack rating is multiplied by this value")
|
||||
RULE_INT(Combat, HitCapPre20, 40, "Hit cap before level 20. Live has it capped at 40")
|
||||
RULE_INT(Combat, HitCapPre10, 20, "Hit cap before level 10. Live has it capped at 20")
|
||||
RULE_INT(Combat, MinHastedDelay, 400, "Minimum hasted combat delay")
|
||||
RULE_REAL(Combat, AvgDefProcsPerMinute, 2.0, "Average defense procs per minute")
|
||||
RULE_REAL(Combat, DefProcPerMinAgiContrib, 0.075, "How much agility contributes to defensive proc rate")
|
||||
RULE_INT(Combat, SpecialAttackACBonus, 15, "Percent amount of damage per AC gained for certain special attacks (damage = AC*SpecialAttackACBonus/100)")
|
||||
RULE_INT(Combat, NPCFlurryChance, 20, "Chance for NPC to flurry")
|
||||
RULE_BOOL(Combat, TauntOverLevel, 1, "Allows you to taunt NPC's over warriors level")
|
||||
RULE_REAL(Combat, TauntSkillFalloff, 0.33, "For every taunt skill point that's not maxed you lose this percentage chance to taunt")
|
||||
RULE_BOOL(Combat, EXPFromDmgShield, false, "Determine if damage from a damage shield counts for experience gain")
|
||||
RULE_INT(Combat, MonkACBonusWeight, 15, "Usually, a monk under this weight threshold gets an AC bonus")
|
||||
RULE_INT(Combat, QuiverHasteCap, 1000, "Quiver haste cap 1000 on live for a while, currently 700 on live")
|
||||
RULE_INT(Combat, BerserkerFrenzyStart, 35, "Percentage Health Points below which Warrior and Berserker start frenzy")
|
||||
RULE_INT(Combat, BerserkerFrenzyEnd, 45, "Percentage Health Points above which Warrior and Berserker end frenzy")
|
||||
@@ -518,6 +480,10 @@ RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing
|
||||
RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
|
||||
RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
|
||||
RULE_BOOL(Combat, UseLiveRiposteMechanics, false, "Set to true to disable SPA 173 SE_RiposteChance from making those with the effect on them immune to enrage, can longer riposte from a riposte.")
|
||||
RULE_INT(Combat, FrontalStunImmunityClasses, 0, "Bitmask for Classes than have frontal stun immunity, No Races (0) by default.")
|
||||
RULE_BOOL(Combat, NPCsUseFrontalStunImmunityClasses, false, "Enable or disable NPCs using frontal stun immunity Classes from Combat:FrontalStunImmunityClasses, false by default.")
|
||||
RULE_INT(Combat, FrontalStunImmunityRaces, 512, "Bitmask for Races than have frontal stun immunity, Ogre (512) only by default.")
|
||||
RULE_BOOL(Combat, NPCsUseFrontalStunImmunityRaces, true, "Enable or disable NPCs using frontal stun immunity Races from Combat:FrontalStunImmunityRaces, true by default.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
@@ -550,6 +516,7 @@ RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditat
|
||||
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if enabled")
|
||||
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
|
||||
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
|
||||
RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Aggro)
|
||||
@@ -839,6 +806,18 @@ RULE_CATEGORY(Doors)
|
||||
RULE_BOOL(Doors, RequireKeyOnCursor, false, "Enable this to require pre-keyring keys to be on player cursor to open doors.")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Items)
|
||||
RULE_BOOL(Items, DisableAttuneable, false, "Enable this to disable Attuneable Items")
|
||||
RULE_BOOL(Items, DisableBardFocusEffects, false, "Enable this to disable Bard Focus Effects on Items")
|
||||
RULE_BOOL(Items, DisableLore, false, "Enable this to disable Lore Items")
|
||||
RULE_BOOL(Items, DisableNoDrop, false, "Enable this to disable No Drop Items")
|
||||
RULE_BOOL(Items, DisableNoPet, false, "Enable this to disable No Pet Items")
|
||||
RULE_BOOL(Items, DisableNoRent, false, "Enable this to disable No Rent Items")
|
||||
RULE_BOOL(Items, DisableNoTransfer, false, "Enable this to disable No Transfer Items")
|
||||
RULE_BOOL(Items, DisablePotionBelt, false, "Enable this to disable Potion Belt Items")
|
||||
RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell Focus Effects on Items")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
#undef RULE_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
+59
-31
@@ -83,17 +83,15 @@
|
||||
#define ServerOP_UpdateSpawn 0x003f
|
||||
#define ServerOP_SpawnStatusChange 0x0040
|
||||
#define ServerOP_DropClient 0x0041 // DropClient
|
||||
#define ServerOP_ReloadTasks 0x0060
|
||||
#define ServerOP_DepopAllPlayersCorpses 0x0061
|
||||
#define ServerOP_ReloadTitles 0x0062
|
||||
#define ServerOP_QGlobalUpdate 0x0063
|
||||
#define ServerOP_QGlobalDelete 0x0064
|
||||
#define ServerOP_DepopPlayerCorpse 0x0065
|
||||
#define ServerOP_RequestTellQueue 0x0066 // client asks for it's tell queues
|
||||
#define ServerOP_ChangeSharedMem 0x0067
|
||||
#define ServerOP_WebInterfaceEvent 0x0068
|
||||
#define ServerOP_WebInterfaceSubscribe 0x0069
|
||||
#define ServerOP_WebInterfaceUnsubscribe 0x0070
|
||||
#define ServerOP_DepopAllPlayersCorpses 0x0060
|
||||
#define ServerOP_QGlobalUpdate 0x0061
|
||||
#define ServerOP_QGlobalDelete 0x0062
|
||||
#define ServerOP_DepopPlayerCorpse 0x0063
|
||||
#define ServerOP_RequestTellQueue 0x0064 // client asks for it's tell queues
|
||||
#define ServerOP_ChangeSharedMem 0x0065
|
||||
#define ServerOP_WebInterfaceEvent 0x0066
|
||||
#define ServerOP_WebInterfaceSubscribe 0x0067
|
||||
#define ServerOP_WebInterfaceUnsubscribe 0x0068
|
||||
|
||||
#define ServerOP_RaidAdd 0x0100 //in use
|
||||
#define ServerOP_RaidRemove 0x0101 //in use
|
||||
@@ -213,21 +211,37 @@
|
||||
#define ServerOP_LauncherZoneStatus 0x3002
|
||||
#define ServerOP_DoZoneCommand 0x3003
|
||||
|
||||
#define ServerOP_UCSMessage 0x4000
|
||||
#define ServerOP_UCSMailMessage 0x4001
|
||||
#define ServerOP_ReloadRules 0x4002
|
||||
#define ServerOP_ReloadRulesWorld 0x4003
|
||||
#define ServerOP_CameraShake 0x4004
|
||||
#define ServerOP_QueryServGeneric 0x4005
|
||||
#define ServerOP_ReloadWorld 0x4006
|
||||
#define ServerOP_ReloadLogs 0x4007
|
||||
#define ServerOP_ReloadPerlExportSettings 0x4008
|
||||
#define ServerOP_UCSServerStatusRequest 0x4009
|
||||
#define ServerOP_UCSServerStatusReply 0x4010
|
||||
#define ServerOP_HotReloadQuests 0x4011
|
||||
#define ServerOP_UpdateSchedulerEvents 0x4012
|
||||
#define ServerOP_ReloadContentFlags 0x4013
|
||||
#define ServerOP_ReloadVariablesWorld 0x4014
|
||||
#define ServerOP_CameraShake 0x4000
|
||||
#define ServerOP_HotReloadQuests 0x4001
|
||||
#define ServerOP_QueryServGeneric 0x4002
|
||||
#define ServerOP_UCSMailMessage 0x4003
|
||||
#define ServerOP_UCSMessage 0x4004
|
||||
#define ServerOP_UCSServerStatusReply 0x4005
|
||||
#define ServerOP_UCSServerStatusRequest 0x4006
|
||||
#define ServerOP_UpdateSchedulerEvents 0x4007
|
||||
#define ServerOP_DiscordWebhookMessage 0x4008
|
||||
|
||||
#define ServerOP_ReloadAAData 0x4100
|
||||
#define ServerOP_ReloadAlternateCurrencies 0x4101
|
||||
#define ServerOP_ReloadBlockedSpells 0x4102
|
||||
#define ServerOP_ReloadContentFlags 0x4103
|
||||
#define ServerOP_ReloadDoors 0x4104
|
||||
#define ServerOP_ReloadGroundSpawns 0x4105
|
||||
#define ServerOP_ReloadLevelEXPMods 0x4106
|
||||
#define ServerOP_ReloadLogs 0x4107
|
||||
#define ServerOP_ReloadMerchants 0x4108
|
||||
#define ServerOP_ReloadNPCEmotes 0x4109
|
||||
#define ServerOP_ReloadObjects 0x4110
|
||||
#define ServerOP_ReloadPerlExportSettings 0x4111
|
||||
#define ServerOP_ReloadRules 0x4112
|
||||
#define ServerOP_ReloadStaticZoneData 0x4113
|
||||
#define ServerOP_ReloadTasks 0x4114
|
||||
#define ServerOP_ReloadTitles 0x4115
|
||||
#define ServerOP_ReloadTraps 0x4116
|
||||
#define ServerOP_ReloadVariables 0x4117
|
||||
#define ServerOP_ReloadVeteranRewards 0x4118
|
||||
#define ServerOP_ReloadWorld 0x4119
|
||||
#define ServerOP_ReloadZonePoints 0x4120
|
||||
|
||||
#define ServerOP_CZDialogueWindow 0x4500
|
||||
#define ServerOP_CZLDoNUpdate 0x4501
|
||||
@@ -727,8 +741,8 @@ struct ServerMultiLineMsg_Struct {
|
||||
};
|
||||
|
||||
struct ServerLock_Struct {
|
||||
char myname[64]; // User that did it
|
||||
uint8 mode; // 0 = Unlocked ; 1 = Locked
|
||||
char character_name[64];
|
||||
bool is_locked;
|
||||
};
|
||||
|
||||
struct ServerMotd_Struct {
|
||||
@@ -1006,8 +1020,8 @@ struct ServerOP_Consent_Struct {
|
||||
};
|
||||
|
||||
struct ReloadTasks_Struct {
|
||||
uint32 Command;
|
||||
uint32 Parameter;
|
||||
uint8 reload_type;
|
||||
uint32 task_id;
|
||||
};
|
||||
|
||||
struct ServerDepopAllPlayersCorpses_Struct
|
||||
@@ -1436,6 +1450,11 @@ struct QSMerchantLogTransaction_Struct {
|
||||
QSTransactionItems_Struct items[0];
|
||||
};
|
||||
|
||||
struct DiscordWebhookMessage_Struct {
|
||||
uint32 webhook_id;
|
||||
char message[2000];
|
||||
};
|
||||
|
||||
struct QSGeneralQuery_Struct {
|
||||
char QueryString[0];
|
||||
};
|
||||
@@ -1600,7 +1619,7 @@ struct WWTaskUpdate_Struct {
|
||||
};
|
||||
|
||||
struct ReloadWorld_Struct {
|
||||
uint32 Option;
|
||||
uint8 global_repop;
|
||||
};
|
||||
|
||||
struct HotReloadQuestsStruct {
|
||||
@@ -1770,6 +1789,15 @@ struct ServerDzCreateSerialized_Struct {
|
||||
char cereal_data[0];
|
||||
};
|
||||
|
||||
struct ServerFlagUpdate_Struct {
|
||||
uint32 account_id;
|
||||
int16 admin;
|
||||
};
|
||||
|
||||
struct ServerOOCMute_Struct {
|
||||
bool is_muted;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
||||
+295
-225
@@ -38,6 +38,7 @@
|
||||
#include "shareddb.h"
|
||||
#include "string_util.h"
|
||||
#include "eqemu_config.h"
|
||||
#include "data_verification.h"
|
||||
#include "repositories/criteria/content_filter_criteria.h"
|
||||
|
||||
namespace ItemField
|
||||
@@ -634,18 +635,18 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
|
||||
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
||||
|
||||
aug[0] = (uint32)atoul(row[4]);
|
||||
aug[1] = (uint32)atoul(row[5]);
|
||||
aug[2] = (uint32)atoul(row[6]);
|
||||
aug[3] = (uint32)atoul(row[7]);
|
||||
aug[4] = (uint32)atoul(row[8]);
|
||||
aug[5] = (uint32)atoul(row[9]);
|
||||
aug[0] = std::stoul(row[4]);
|
||||
aug[1] = std::stoul(row[5]);
|
||||
aug[2] = std::stoul(row[6]);
|
||||
aug[3] = std::stoul(row[7]);
|
||||
aug[4] = std::stoul(row[8]);
|
||||
aug[5] = std::stoul(row[9]);
|
||||
|
||||
bool instnodrop = (row[10] && (uint16)atoi(row[10])) ? true : false;
|
||||
|
||||
uint32 ornament_icon = (uint32)atoul(row[12]);
|
||||
uint32 ornament_idfile = (uint32)atoul(row[13]);
|
||||
uint32 ornament_hero_model = (uint32)atoul(row[14]);
|
||||
uint32 ornament_icon = std::stoul(row[12]);
|
||||
uint32 ornament_idfile = std::stoul(row[13]);
|
||||
uint32 ornament_hero_model = std::stoul(row[14]);
|
||||
|
||||
const EQ::ItemData *item = GetItem(item_id);
|
||||
|
||||
@@ -788,9 +789,9 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQ::InventoryPr
|
||||
aug[5] = (uint32)atoi(row[9]);
|
||||
|
||||
bool instnodrop = (row[10] && (uint16)atoi(row[10])) ? true : false;
|
||||
uint32 ornament_icon = (uint32)atoul(row[12]);
|
||||
uint32 ornament_idfile = (uint32)atoul(row[13]);
|
||||
uint32 ornament_hero_model = (uint32)atoul(row[14]);
|
||||
uint32 ornament_icon = std::stoul(row[12]);
|
||||
uint32 ornament_idfile = std::stoul(row[13]);
|
||||
uint32 ornament_hero_model = std::stoul(row[14]);
|
||||
|
||||
const EQ::ItemData *item = GetItem(item_id);
|
||||
int16 put_slot_id = INVALID_INDEX;
|
||||
@@ -943,29 +944,41 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
|
||||
{
|
||||
EQ::FixedMemoryHashSet<EQ::ItemData> hash(reinterpret_cast<uint8 *>(data), size, items, max_item_id);
|
||||
|
||||
std::string ndbuffer;
|
||||
bool disableNoRent = false;
|
||||
if (GetVariable("disablenorent", ndbuffer)) {
|
||||
if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
|
||||
disableNoRent = true;
|
||||
std::string variable_buffer;
|
||||
|
||||
bool disable_attuneable = RuleB(Items, DisableAttuneable);
|
||||
bool disable_bard_focus_effects = RuleB(Items, DisableBardFocusEffects);
|
||||
bool disable_lore = RuleB(Items, DisableLore);
|
||||
bool disable_no_drop = RuleB(Items, DisableNoDrop);
|
||||
bool disable_no_pet = RuleB(Items, DisableNoPet);
|
||||
bool disable_no_rent = RuleB(Items, DisableNoRent);
|
||||
bool disable_no_transfer = RuleB(Items, DisableNoTransfer);
|
||||
bool disable_potion_belt = RuleB(Items, DisablePotionBelt);
|
||||
bool disable_spell_focus_effects = RuleB(Items, DisableSpellFocusEffects);
|
||||
|
||||
// Old Variable Code
|
||||
if (GetVariable("disablelore", variable_buffer)) {
|
||||
if (variable_buffer == "1") {
|
||||
disable_lore = true;
|
||||
}
|
||||
}
|
||||
bool disableNoDrop = false;
|
||||
if (GetVariable("disablenodrop", ndbuffer)) {
|
||||
if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
|
||||
disableNoDrop = true;
|
||||
|
||||
if (GetVariable("disablenodrop", variable_buffer)) {
|
||||
if (variable_buffer == "1") {
|
||||
disable_no_drop = true;
|
||||
}
|
||||
}
|
||||
bool disableLoreGroup = false;
|
||||
if (GetVariable("disablelore", ndbuffer)) {
|
||||
if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
|
||||
disableLoreGroup = true;
|
||||
|
||||
if (GetVariable("disablenorent", variable_buffer)) {
|
||||
if (variable_buffer == "1") {
|
||||
disable_no_rent = true;
|
||||
}
|
||||
}
|
||||
bool disableNoTransfer = false;
|
||||
if (GetVariable("disablenotransfer", ndbuffer)) {
|
||||
if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') {
|
||||
disableNoTransfer = true;
|
||||
|
||||
|
||||
if (GetVariable("disablenotransfer", variable_buffer)) {
|
||||
if (variable_buffer == "1") {
|
||||
disable_no_transfer = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -984,212 +997,269 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
memset(&item, 0, sizeof(EQ::ItemData));
|
||||
|
||||
item.ItemClass = (uint8)atoi(row[ItemField::itemclass]);
|
||||
strcpy(item.Name, row[ItemField::name]);
|
||||
strcpy(item.Lore, row[ItemField::lore]);
|
||||
strcpy(item.IDFile, row[ItemField::idfile]);
|
||||
// Unique Identifier
|
||||
item.ID = std::stoul(row[ItemField::id]);
|
||||
|
||||
item.ID = (uint32)atoul(row[ItemField::id]);
|
||||
item.Weight = (int32)atoi(row[ItemField::weight]);
|
||||
item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]);
|
||||
item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]);
|
||||
item.Size = (uint8)atoi(row[ItemField::size]);
|
||||
item.Slots = (uint32)atoul(row[ItemField::slots]);
|
||||
item.Price = (uint32)atoul(row[ItemField::price]);
|
||||
item.Icon = (uint32)atoul(row[ItemField::icon]);
|
||||
item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0);
|
||||
item.Tradeskills = (atoi(row[ItemField::tradeskills]) == 0) ? false : true;
|
||||
item.CR = (int8)atoi(row[ItemField::cr]);
|
||||
item.DR = (int8)atoi(row[ItemField::dr]);
|
||||
item.PR = (int8)atoi(row[ItemField::pr]);
|
||||
item.MR = (int8)atoi(row[ItemField::mr]);
|
||||
item.FR = (int8)atoi(row[ItemField::fr]);
|
||||
item.AStr = (int8)atoi(row[ItemField::astr]);
|
||||
item.ASta = (int8)atoi(row[ItemField::asta]);
|
||||
item.AAgi = (int8)atoi(row[ItemField::aagi]);
|
||||
item.ADex = (int8)atoi(row[ItemField::adex]);
|
||||
item.ACha = (int8)atoi(row[ItemField::acha]);
|
||||
item.AInt = (int8)atoi(row[ItemField::aint]);
|
||||
item.AWis = (int8)atoi(row[ItemField::awis]);
|
||||
item.HP = (int32)atoul(row[ItemField::hp]);
|
||||
item.Mana = (int32)atoul(row[ItemField::mana]);
|
||||
item.AC = (int32)atoul(row[ItemField::ac]);
|
||||
item.Deity = (uint32)atoul(row[ItemField::deity]);
|
||||
item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]);
|
||||
item.SkillModMax = (int32)atoul(row[ItemField::skillmodmax]);
|
||||
item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]);
|
||||
item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]);
|
||||
item.BaneDmgAmt = (int32)atoul(row[ItemField::banedmgamt]);
|
||||
item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]);
|
||||
item.Magic = (atoi(row[ItemField::magic]) == 0) ? false : true;
|
||||
item.CastTime_ = (int32)atoul(row[ItemField::casttime_]);
|
||||
item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]);
|
||||
item.BardType = (uint32)atoul(row[ItemField::bardtype]);
|
||||
item.BardValue = (int32)atoul(row[ItemField::bardvalue]);
|
||||
item.Light = (int8)atoi(row[ItemField::light]);
|
||||
item.Delay = (uint8)atoi(row[ItemField::delay]);
|
||||
item.RecLevel = (uint8)atoi(row[ItemField::reclevel]);
|
||||
item.RecSkill = (uint8)atoi(row[ItemField::recskill]);
|
||||
item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]);
|
||||
item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]);
|
||||
item.Range = (uint8)atoi(row[ItemField::range]);
|
||||
item.Damage = (uint32)atoi(row[ItemField::damage]);
|
||||
item.Color = (uint32)atoul(row[ItemField::color]);
|
||||
item.Classes = (uint32)atoul(row[ItemField::classes]);
|
||||
item.Races = (uint32)atoul(row[ItemField::races]);
|
||||
// Name and Lore
|
||||
strn0cpy(item.Name, row[ItemField::name], sizeof(item.Name));
|
||||
strn0cpy(item.Lore, row[ItemField::lore], sizeof(item.Lore));
|
||||
|
||||
item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]);
|
||||
item.ItemType = (uint8)atoi(row[ItemField::itemtype]);
|
||||
item.SubType = atoi(row[ItemField::subtype]);
|
||||
item.Material = (uint8)atoi(row[ItemField::material]);
|
||||
item.HerosForgeModel = (uint32)atoi(row[ItemField::herosforgemodel]);
|
||||
item.SellRate = (float)atof(row[ItemField::sellrate]);
|
||||
item.CastTime = (uint32)atoul(row[ItemField::casttime]);
|
||||
item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]);
|
||||
item.ProcRate = (int32)atoi(row[ItemField::procrate]);
|
||||
item.CombatEffects = (int8)atoi(row[ItemField::combateffects]);
|
||||
item.Shielding = (int8)atoi(row[ItemField::shielding]);
|
||||
item.StunResist = (int8)atoi(row[ItemField::stunresist]);
|
||||
item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]);
|
||||
item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]);
|
||||
item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]);
|
||||
item.SpellShield = (int8)atoi(row[ItemField::spellshield]);
|
||||
item.Avoidance = (int8)atoi(row[ItemField::avoidance]);
|
||||
item.Accuracy = (int8)atoi(row[ItemField::accuracy]);
|
||||
item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]);
|
||||
item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]);
|
||||
item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]);
|
||||
item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]);
|
||||
item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]);
|
||||
item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]);
|
||||
item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]);
|
||||
item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]);
|
||||
item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]);
|
||||
// Flags
|
||||
item.ArtifactFlag = std::stoi(row[ItemField::artifactflag]) ? true : false;
|
||||
item.Attuneable = disable_attuneable ? false : std::stoi(row[ItemField::attuneable]) ? true : false;
|
||||
item.BenefitFlag = std::stoi(row[ItemField::benefitflag]) ? true : false;
|
||||
item.FVNoDrop = std::stoi(row[ItemField::fvnodrop]) ? true : false;
|
||||
item.Magic = std::stoi(row[ItemField::magic]) ? true : false;
|
||||
item.NoDrop = disable_no_drop ? static_cast<uint8>(255) : static_cast<uint8>(std::stoul(row[ItemField::nodrop]));
|
||||
item.NoPet = disable_no_pet ? false : std::stoi(row[ItemField::nopet]) ? true : false;
|
||||
item.NoRent = disable_no_rent ? static_cast<uint8>(255) : static_cast<uint8>(std::stoul(row[ItemField::norent]));
|
||||
item.NoTransfer = disable_no_transfer ? false : std::stoi(row[ItemField::notransfer]) ? true : false;
|
||||
item.PendingLoreFlag = std::stoi(row[ItemField::pendingloreflag]) ? true : false;
|
||||
item.QuestItemFlag = std::stoi(row[ItemField::questitemflag]) ? true : false;
|
||||
item.Stackable = std::stoi(row[ItemField::stackable]) ? true : false;
|
||||
item.Tradeskills = std::stoi(row[ItemField::tradeskills]) ? true : false;
|
||||
item.SummonedFlag = std::stoi(row[ItemField::summonedflag]) ? true : false;
|
||||
|
||||
strcpy(item.CharmFile, row[ItemField::charmfile]);
|
||||
// Lore
|
||||
item.LoreGroup = disable_lore ? 0 : std::stoi(row[ItemField::loregroup]);
|
||||
item.LoreFlag = disable_lore ? false : item.LoreGroup != 0;
|
||||
|
||||
item.AugType = (uint32)atoul(row[ItemField::augtype]);
|
||||
item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]);
|
||||
item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]);
|
||||
item.AugSlotUnk2[0] = 0;
|
||||
item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]);
|
||||
item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]);
|
||||
item.AugSlotUnk2[1] = 0;
|
||||
item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]);
|
||||
item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]);
|
||||
item.AugSlotUnk2[2] = 0;
|
||||
item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]);
|
||||
item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]);
|
||||
item.AugSlotUnk2[3] = 0;
|
||||
item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]);
|
||||
item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]);
|
||||
item.AugSlotUnk2[4] = 0;
|
||||
item.AugSlotType[5] = (uint8)atoi(row[ItemField::augslot6type]);
|
||||
item.AugSlotVisible[5] = (uint8)atoi(row[ItemField::augslot6visible]);
|
||||
item.AugSlotUnk2[5] = 0;
|
||||
// Type
|
||||
item.AugType = std::stoul(row[ItemField::augtype]);
|
||||
item.ItemType = static_cast<uint8>(std::stoul(row[ItemField::itemtype]));
|
||||
item.SubType = std::stoi(row[ItemField::subtype]);
|
||||
|
||||
item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]);
|
||||
item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]);
|
||||
item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]);
|
||||
item.BagType = (uint8)atoi(row[ItemField::bagtype]);
|
||||
item.BagSlots = (uint8)std::min(atoi(row[ItemField::bagslots]), 10); // FIXME: remove when big bags supported
|
||||
item.BagSize = (uint8)atoi(row[ItemField::bagsize]);
|
||||
item.BagWR = (uint8)atoi(row[ItemField::bagwr]);
|
||||
item.Book = (uint8)atoi(row[ItemField::book]);
|
||||
item.BookType = (uint32)atoul(row[ItemField::booktype]);
|
||||
// Miscellaneous
|
||||
item.ExpendableArrow = static_cast<uint16>(std::stoul(row[ItemField::expendablearrow]));
|
||||
item.Light = static_cast<int8>(std::stoi(row[ItemField::light]));
|
||||
item.MaxCharges = static_cast<int16>(std::stoi(row[ItemField::maxcharges]));
|
||||
item.Size = static_cast<uint8>(std::stoul(row[ItemField::size]));
|
||||
item.StackSize = static_cast<int16>(std::stoi(row[ItemField::stacksize]));
|
||||
item.Weight = std::stoi(row[ItemField::weight]);
|
||||
|
||||
strcpy(item.Filename, row[ItemField::filename]);
|
||||
// Potion Belt
|
||||
item.PotionBelt = disable_potion_belt ? false : std::stoi(row[ItemField::potionbelt]) ? true : false;
|
||||
item.PotionBeltSlots = disable_potion_belt ? 0 : static_cast<uint8>(std::stoul(row[ItemField::potionbeltslots]));
|
||||
|
||||
item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]);
|
||||
item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]);
|
||||
item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]);
|
||||
item.LoreFlag = item.LoreGroup != 0;
|
||||
item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag]) == 0) ? false : true;
|
||||
item.ArtifactFlag = (atoi(row[ItemField::artifactflag]) == 0) ? false : true;
|
||||
item.SummonedFlag = (atoi(row[ItemField::summonedflag]) == 0) ? false : true;
|
||||
item.Favor = (uint32)atoul(row[ItemField::favor]);
|
||||
item.FVNoDrop = (atoi(row[ItemField::fvnodrop]) == 0) ? false : true;
|
||||
item.Endur = (uint32)atoul(row[ItemField::endur]);
|
||||
item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]);
|
||||
item.Attack = (uint32)atoul(row[ItemField::attack]);
|
||||
item.Regen = (uint32)atoul(row[ItemField::regen]);
|
||||
item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]);
|
||||
item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]);
|
||||
item.Haste = (uint32)atoul(row[ItemField::haste]);
|
||||
item.DamageShield = (uint32)atoul(row[ItemField::damageshield]);
|
||||
item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]);
|
||||
item.RecastType = (int)atoi(row[ItemField::recasttype]);
|
||||
item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]);
|
||||
item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]);
|
||||
item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true;
|
||||
item.NoPet = (atoi(row[ItemField::nopet]) == 0) ? false : true;
|
||||
item.PointType = (uint32)atoul(row[ItemField::pointtype]);
|
||||
item.PotionBelt = (atoi(row[ItemField::potionbelt]) == 0) ? false : true;
|
||||
item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots]) == 0) ? false : true;
|
||||
item.StackSize = (uint16)atoi(row[ItemField::stacksize]);
|
||||
item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer]) == 0) ? false : true;
|
||||
item.Stackable = (atoi(row[ItemField::stackable]) == 0) ? false : true;
|
||||
item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]);
|
||||
item.Click.Type = (uint8)atoul(row[ItemField::clicktype]);
|
||||
item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]);
|
||||
item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]);
|
||||
// Merchant
|
||||
item.Favor = std::stoul(row[ItemField::favor]);
|
||||
item.GuildFavor = std::stoul(row[ItemField::guildfavor]);
|
||||
item.Price = std::stoul(row[ItemField::price]);
|
||||
item.SellRate = std::stof(row[ItemField::sellrate]);
|
||||
|
||||
// Display
|
||||
item.Color = std::stoul(row[ItemField::color]);
|
||||
item.EliteMaterial = std::stoul(row[ItemField::elitematerial]);
|
||||
item.HerosForgeModel = std::stoul(row[ItemField::herosforgemodel]);
|
||||
item.Icon = std::stoul(row[ItemField::icon]);
|
||||
strn0cpy(item.IDFile, row[ItemField::idfile], sizeof(item.IDFile));
|
||||
item.Material = static_cast<uint8>(std::stoul(row[ItemField::material]));
|
||||
|
||||
strcpy(item.CharmFile, row[ItemField::charmfile]);
|
||||
// Resists
|
||||
item.CR = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::cr]), -128, 127));
|
||||
item.DR = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::dr]), -128, 127));
|
||||
item.FR = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::fr]), -128, 127));
|
||||
item.MR = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::mr]), -128, 127));
|
||||
item.PR = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::pr]), -128, 127));
|
||||
item.SVCorruption = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::svcorruption]), -128, 127));
|
||||
|
||||
item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]);
|
||||
item.Proc.Type = (uint8)atoul(row[ItemField::proctype]);
|
||||
item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]);
|
||||
item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]);
|
||||
item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]);
|
||||
item.Worn.Type = (uint8)atoul(row[ItemField::worntype]);
|
||||
item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]);
|
||||
item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]);
|
||||
item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]);
|
||||
item.Focus.Type = (uint8)atoul(row[ItemField::focustype]);
|
||||
item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]);
|
||||
item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]);
|
||||
item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]);
|
||||
item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]);
|
||||
item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]);
|
||||
item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]);
|
||||
item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]);
|
||||
item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]);
|
||||
item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]);
|
||||
item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]);
|
||||
item.QuestItemFlag = (atoi(row[ItemField::questitemflag]) == 0) ? false : true;
|
||||
item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]);
|
||||
item.Purity = (uint32)atoul(row[ItemField::purity]);
|
||||
item.EvolvingItem = (uint8)atoul(row[ItemField::evoitem]);
|
||||
item.EvolvingID = (uint8)atoul(row[ItemField::evoid]);
|
||||
item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]);
|
||||
item.EvolvingMax = (uint8)atoul(row[ItemField::evomax]);
|
||||
item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]);
|
||||
item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]);
|
||||
item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]);
|
||||
item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]);
|
||||
item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]);
|
||||
item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]);
|
||||
item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]);
|
||||
item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]);
|
||||
item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]);
|
||||
item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]);
|
||||
item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]);
|
||||
item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]);
|
||||
item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]);
|
||||
item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]);
|
||||
item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]);
|
||||
item.HealAmt = (int32)atoi(row[ItemField::healamt]);
|
||||
item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]);
|
||||
item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]);
|
||||
item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]);
|
||||
item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]);
|
||||
item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]);
|
||||
// Heroic Resists
|
||||
item.HeroicCR = std::stoi(row[ItemField::heroic_cr]);
|
||||
item.HeroicDR = std::stoi(row[ItemField::heroic_dr]);
|
||||
item.HeroicFR = std::stoi(row[ItemField::heroic_fr]);
|
||||
item.HeroicMR = std::stoi(row[ItemField::heroic_mr]);
|
||||
item.HeroicPR = std::stoi(row[ItemField::heroic_pr]);
|
||||
item.HeroicSVCorrup = std::stoi(row[ItemField::heroic_svcorrup]);
|
||||
|
||||
strcpy(item.ClickName, row[ItemField::clickname]);
|
||||
strcpy(item.ProcName, row[ItemField::procname]);
|
||||
strcpy(item.WornName, row[ItemField::wornname]);
|
||||
strcpy(item.FocusName, row[ItemField::focusname]);
|
||||
strcpy(item.ScrollName, row[ItemField::scrollname]);
|
||||
// Stats
|
||||
item.AAgi = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::aagi]), -128, 127));
|
||||
item.ACha = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::acha]), -128, 127));
|
||||
item.ADex = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::adex]), -128, 127));
|
||||
item.AInt = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::aint]), -128, 127));
|
||||
item.ASta = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::asta]), -128, 127));
|
||||
item.AStr = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::astr]), -128, 127));
|
||||
item.AWis = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::awis]), -128, 127));
|
||||
|
||||
// Heroic Stats
|
||||
item.HeroicAgi = std::stoi(row[ItemField::heroic_agi]);
|
||||
item.HeroicCha = std::stoi(row[ItemField::heroic_cha]);
|
||||
item.HeroicDex = std::stoi(row[ItemField::heroic_dex]);
|
||||
item.HeroicInt = std::stoi(row[ItemField::heroic_int]);
|
||||
item.HeroicSta = std::stoi(row[ItemField::heroic_sta]);
|
||||
item.HeroicStr = std::stoi(row[ItemField::heroic_str]);
|
||||
item.HeroicWis = std::stoi(row[ItemField::heroic_wis]);
|
||||
|
||||
// Health, Mana, and Endurance
|
||||
item.HP = std::stoi(row[ItemField::hp]);
|
||||
item.Regen = std::stoul(row[ItemField::regen]);
|
||||
item.Mana = std::stoi(row[ItemField::mana]);
|
||||
item.ManaRegen = std::stoul(row[ItemField::manaregen]);
|
||||
item.Endur = std::stoul(row[ItemField::endur]);
|
||||
item.EnduranceRegen = std::stoul(row[ItemField::enduranceregen]);
|
||||
|
||||
// Bane Damage
|
||||
item.BaneDmgAmt = std::stoi(row[ItemField::banedmgamt]);
|
||||
item.BaneDmgBody = std::stoul(row[ItemField::banedmgbody]);
|
||||
item.BaneDmgRace = std::stoul(row[ItemField::banedmgrace]);
|
||||
item.BaneDmgRaceAmt = std::stoul(row[ItemField::banedmgraceamt]);
|
||||
|
||||
// Elemental Damage
|
||||
item.ElemDmgType = static_cast<uint8>(std::stoul(row[ItemField::elemdmgtype]));
|
||||
item.ElemDmgAmt = static_cast<uint8>(std::stoul(row[ItemField::elemdmgamt]));
|
||||
|
||||
// Combat
|
||||
item.BackstabDmg = std::stoul(row[ItemField::backstabdmg]);
|
||||
item.Damage = std::stoul(row[ItemField::damage]);
|
||||
item.Delay = static_cast<uint8>(std::stoul(row[ItemField::delay]));
|
||||
item.Range = static_cast<uint8>(std::stoul(row[ItemField::range]));
|
||||
|
||||
// Combat Stats
|
||||
item.AC = std::stoi(row[ItemField::ac]);
|
||||
item.Accuracy = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::accuracy]), -128, 127));
|
||||
item.Attack = std::stoi(row[ItemField::attack]);
|
||||
item.Avoidance = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::avoidance]), -128, 127));
|
||||
item.Clairvoyance = std::stoul(row[ItemField::clairvoyance]);
|
||||
item.CombatEffects = StringIsNumber(row[ItemField::combateffects]) ? static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::combateffects]), -128, 127)) : 0;
|
||||
item.DamageShield = std::stoi(row[ItemField::damageshield]);
|
||||
item.DotShielding = std::stoi(row[ItemField::dotshielding]);
|
||||
item.DSMitigation = std::stoul(row[ItemField::dsmitigation]);
|
||||
item.Haste = std::stoi(row[ItemField::haste]);
|
||||
item.HealAmt = std::stoi(row[ItemField::healamt]);
|
||||
item.Purity = std::stoul(row[ItemField::purity]);
|
||||
item.Shielding = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::shielding]), -128, 127));
|
||||
item.SpellDmg = std::stoi(row[ItemField::spelldmg]);
|
||||
item.SpellShield = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::spellshield]), -128, 127));
|
||||
item.StrikeThrough = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::strikethrough]), -128, 127));
|
||||
item.StunResist = static_cast<int8>(EQ::Clamp(std::stoi(row[ItemField::stunresist]), -128, 127));
|
||||
|
||||
// Restrictions
|
||||
item.AugRestrict = std::stoul(row[ItemField::augrestrict]);
|
||||
item.Classes = std::stoul(row[ItemField::classes]);
|
||||
item.Deity = std::stoul(row[ItemField::deity]);
|
||||
item.ItemClass = static_cast<uint8>(std::stoul(row[ItemField::itemclass]));
|
||||
item.Races = std::stoul(row[ItemField::races]);
|
||||
item.RecLevel = static_cast<uint8>(std::stoul(row[ItemField::reclevel]));
|
||||
item.RecSkill = static_cast<uint8>(std::stoul(row[ItemField::recskill]));
|
||||
item.ReqLevel = static_cast<uint8>(std::stoul(row[ItemField::reqlevel]));
|
||||
item.Slots = std::stoul(row[ItemField::slots]);
|
||||
|
||||
// Skill Modifier
|
||||
item.SkillModValue = std::stoi(row[ItemField::skillmodvalue]);
|
||||
item.SkillModMax = std::stoi(row[ItemField::skillmodmax]);
|
||||
item.SkillModType = std::stoul(row[ItemField::skillmodtype]);
|
||||
|
||||
// Extra Damage Skill
|
||||
item.ExtraDmgSkill = std::stoul(row[ItemField::extradmgskill]);
|
||||
item.ExtraDmgAmt = std::stoul(row[ItemField::extradmgamt]);
|
||||
|
||||
// Bard
|
||||
item.BardType = std::stoul(row[ItemField::bardtype]);
|
||||
item.BardValue = std::stoi(row[ItemField::bardvalue]);
|
||||
|
||||
// Faction
|
||||
item.FactionAmt1 = std::stoi(row[ItemField::factionamt1]);
|
||||
item.FactionMod1 = std::stoi(row[ItemField::factionmod1]);
|
||||
item.FactionAmt2 = std::stoi(row[ItemField::factionamt2]);
|
||||
item.FactionMod2 = std::stoi(row[ItemField::factionmod2]);
|
||||
item.FactionAmt3 = std::stoi(row[ItemField::factionamt3]);
|
||||
item.FactionMod3 = std::stoi(row[ItemField::factionmod3]);
|
||||
item.FactionAmt4 = std::stoi(row[ItemField::factionamt4]);
|
||||
item.FactionMod4 = std::stoi(row[ItemField::factionmod4]);
|
||||
|
||||
// Augment
|
||||
item.AugDistiller = std::stoul(row[ItemField::augdistiller]);
|
||||
item.AugSlotType[0] = static_cast<uint8>(std::stoul(row[ItemField::augslot1type]));
|
||||
item.AugSlotVisible[0] = static_cast<uint8>(std::stoul(row[ItemField::augslot1visible]));
|
||||
item.AugSlotType[1] = static_cast<uint8>(std::stoul(row[ItemField::augslot2type]));
|
||||
item.AugSlotVisible[1] = static_cast<uint8>(std::stoul(row[ItemField::augslot2visible]));
|
||||
item.AugSlotType[2] = static_cast<uint8>(std::stoul(row[ItemField::augslot3type]));
|
||||
item.AugSlotVisible[2] = static_cast<uint8>(std::stoul(row[ItemField::augslot3visible]));
|
||||
item.AugSlotType[3] = static_cast<uint8>(std::stoul(row[ItemField::augslot4type]));
|
||||
item.AugSlotVisible[3] = static_cast<uint8>(std::stoul(row[ItemField::augslot4visible]));
|
||||
item.AugSlotType[4] = static_cast<uint8>(std::stoul(row[ItemField::augslot5type]));
|
||||
item.AugSlotVisible[4] = static_cast<uint8>(std::stoul(row[ItemField::augslot5visible]));
|
||||
item.AugSlotType[5] = static_cast<uint8>(std::stoul(row[ItemField::augslot6type]));
|
||||
item.AugSlotVisible[5] = static_cast<uint8>(std::stoul(row[ItemField::augslot6visible]));
|
||||
|
||||
// Augment Unknowns
|
||||
for (uint8 i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
||||
item.AugSlotUnk2[i] = 0;
|
||||
}
|
||||
|
||||
// LDoN
|
||||
item.LDoNTheme = std::stoul(row[ItemField::ldontheme]);
|
||||
item.LDoNPrice = std::stoul(row[ItemField::ldonprice]);
|
||||
item.LDoNSellBackRate = std::stoul(row[ItemField::ldonsellbackrate]);
|
||||
item.LDoNSold = std::stoul(row[ItemField::ldonsold]);
|
||||
item.PointType = std::stoul(row[ItemField::pointtype]);
|
||||
|
||||
// Bag
|
||||
item.BagSize = static_cast<uint8>(std::stoul(row[ItemField::bagsize]));
|
||||
item.BagSlots = static_cast<uint8>(EQ::Clamp(std::stoi(row[ItemField::bagslots]), 0, 10)); // Will need to be changed from std::min to just use database value when bag slots are increased
|
||||
item.BagType = static_cast<uint8>(std::stoul(row[ItemField::bagtype]));
|
||||
item.BagWR = static_cast<uint8>(EQ::Clamp(std::stoi(row[ItemField::bagwr]), 0, 100));
|
||||
|
||||
// Bard Effect
|
||||
item.Bard.Effect = disable_bard_focus_effects ? 0 : std::stoi(row[ItemField::bardeffect]);
|
||||
item.Bard.Type = disable_bard_focus_effects ? 0 : static_cast<uint8>(std::stoul(row[ItemField::bardtype]));
|
||||
item.Bard.Level = disable_bard_focus_effects ? 0 : static_cast<uint8>(std::stoul(row[ItemField::bardlevel]));
|
||||
item.Bard.Level2 = disable_bard_focus_effects ? 0 : static_cast<uint8>(std::stoul(row[ItemField::bardlevel2]));
|
||||
|
||||
// Book
|
||||
item.Book = static_cast<uint8>(std::stoul(row[ItemField::book]));
|
||||
item.BookType = std::stoul(row[ItemField::booktype]);
|
||||
|
||||
// Click Effect
|
||||
item.CastTime = std::stoul(row[ItemField::casttime]);
|
||||
item.CastTime_ = std::stoi(row[ItemField::casttime_]);
|
||||
item.Click.Effect = std::stoul(row[ItemField::clickeffect]);
|
||||
item.Click.Type = static_cast<uint8>(std::stoul(row[ItemField::clicktype]));
|
||||
item.Click.Level = static_cast<uint8>(std::stoul(row[ItemField::clicklevel]));
|
||||
item.Click.Level2 = static_cast<uint8>(std::stoul(row[ItemField::clicklevel2]));
|
||||
strn0cpy(item.ClickName, row[ItemField::clickname], sizeof(item.ClickName));
|
||||
item.RecastDelay = std::stoul(row[ItemField::recastdelay]);
|
||||
item.RecastType = std::stoi(row[ItemField::recasttype]);
|
||||
|
||||
// Focus Effect
|
||||
item.Focus.Effect = disable_spell_focus_effects ? 0 : std::stoi(row[ItemField::focuseffect]);
|
||||
item.Focus.Type = disable_spell_focus_effects ? 0 : static_cast<uint8>(std::stoul(row[ItemField::focustype]));
|
||||
item.Focus.Level = disable_spell_focus_effects ? 0 : static_cast<uint8>(std::stoul(row[ItemField::focuslevel]));
|
||||
item.Focus.Level2 = disable_spell_focus_effects ? 0 : static_cast<uint8>(std::stoul(row[ItemField::focuslevel2]));
|
||||
strn0cpy(item.FocusName, disable_spell_focus_effects ? "" : row[ItemField::focusname], sizeof(item.FocusName));
|
||||
|
||||
// Proc Effect
|
||||
item.Proc.Effect = std::stoi(row[ItemField::proceffect]);
|
||||
item.Proc.Type = static_cast<uint8>(std::stoul(row[ItemField::proctype]));
|
||||
item.Proc.Level = static_cast<uint8>(std::stoul(row[ItemField::proclevel]));
|
||||
item.Proc.Level2 = static_cast<uint8>(std::stoul(row[ItemField::proclevel2]));
|
||||
strn0cpy(item.ProcName, row[ItemField::procname], sizeof(item.ProcName));
|
||||
item.ProcRate = std::stoi(row[ItemField::procrate]);
|
||||
|
||||
// Scroll Effect
|
||||
item.Scroll.Effect = std::stoi(row[ItemField::scrolleffect]);
|
||||
item.Scroll.Type = static_cast<uint8>(std::stoul(row[ItemField::scrolltype]));
|
||||
item.Scroll.Level = static_cast<uint8>(std::stoul(row[ItemField::scrolllevel]));
|
||||
item.Scroll.Level2 = static_cast<uint8>(std::stoul(row[ItemField::scrolllevel2]));
|
||||
strn0cpy(item.ScrollName, row[ItemField::scrollname], sizeof(item.ScrollName));
|
||||
|
||||
// Worn Effect
|
||||
item.Worn.Effect = std::stoi(row[ItemField::worneffect]);
|
||||
item.Worn.Type = static_cast<uint8>(std::stoul(row[ItemField::worntype]));
|
||||
item.Worn.Level = static_cast<uint8>(std::stoul(row[ItemField::wornlevel]));
|
||||
item.Worn.Level2 = static_cast<uint8>(std::stoul(row[ItemField::wornlevel2]));
|
||||
strn0cpy(item.WornName, row[ItemField::wornname], sizeof(item.WornName));
|
||||
|
||||
// Evolving Item
|
||||
item.EvolvingID = std::stoul(row[ItemField::evoid]);
|
||||
item.EvolvingItem = static_cast<uint8>(std::stoul(row[ItemField::evoitem]));
|
||||
item.EvolvingLevel = static_cast<uint8>(std::stoul(row[ItemField::evolvinglevel]));
|
||||
item.EvolvingMax = static_cast<uint8>(std::stoul(row[ItemField::evomax]));
|
||||
|
||||
// Scripting
|
||||
item.CharmFileID = StringIsNumber(row[ItemField::charmfileid]) ? std::stoul(row[ItemField::charmfileid]) : 0;
|
||||
strn0cpy(item.CharmFile, row[ItemField::charmfile], sizeof(item.CharmFile));
|
||||
strn0cpy(item.Filename, row[ItemField::filename], sizeof(item.Filename));
|
||||
item.ScriptFileID = std::stoul(row[ItemField::scriptfileid]);
|
||||
|
||||
try {
|
||||
hash.insert(item.ID, item);
|
||||
|
||||
+12
-8
@@ -101,14 +101,18 @@ bool IsSacrificeSpell(uint16 spell_id)
|
||||
|
||||
bool IsLifetapSpell(uint16 spell_id)
|
||||
{
|
||||
// Ancient Lifebane: 2115
|
||||
if (IsValidSpell(spell_id) &&
|
||||
(spells[spell_id].target_type == ST_Tap ||
|
||||
spells[spell_id].target_type == ST_TargetAETap ||
|
||||
spell_id == 2115))
|
||||
return true;
|
||||
if (
|
||||
IsValidSpell(spell_id) &&
|
||||
(
|
||||
spells[spell_id].target_type == ST_Tap ||
|
||||
spells[spell_id].target_type == ST_TargetAETap ||
|
||||
spell_id == SPELL_ANCIENT_LIFEBANE
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMezSpell(uint16 spell_id)
|
||||
@@ -139,7 +143,7 @@ bool IsEvacSpell(uint16 spellid)
|
||||
|
||||
bool IsDamageSpell(uint16 spellid)
|
||||
{
|
||||
if (spells[spellid].target_type == ST_Tap)
|
||||
if (IsLifetapSpell(spellid))
|
||||
return false;
|
||||
|
||||
for (int o = 0; o < EFFECT_COUNT; o++) {
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
#define SPELL_ILLUSION_FEMALE 1731
|
||||
#define SPELL_ILLUSION_MALE 1732
|
||||
#define SPELL_UNSUMMON_SELF 892
|
||||
#define SPELL_ANCIENT_LIFEBANE 2115
|
||||
|
||||
//spellgroup ids
|
||||
#define SPELLGROUP_FRENZIED_BURNOUT 2754
|
||||
|
||||
+48
-27
@@ -575,9 +575,9 @@ char *RemoveApostrophes(const char *s)
|
||||
return NewString;
|
||||
}
|
||||
|
||||
const char *ConvertArray(int input, char *returnchar)
|
||||
const char *ConvertArray(int64 input, char *returnchar)
|
||||
{
|
||||
sprintf(returnchar, "%i", input);
|
||||
sprintf(returnchar, "%lld", input);
|
||||
return returnchar;
|
||||
}
|
||||
|
||||
@@ -1192,76 +1192,97 @@ std::string ConvertMoneyToString(uint32 platinum, uint32 gold, uint32 silver, ui
|
||||
if (copper && silver && gold && platinum) { // CSGP
|
||||
money_string = fmt::format(
|
||||
"{} Platinum, {} Gold, {} Silver, and {} Copper",
|
||||
platinum,
|
||||
gold,
|
||||
silver,
|
||||
copper
|
||||
commify(std::to_string(platinum)),
|
||||
commify(std::to_string(gold)),
|
||||
commify(std::to_string(silver)),
|
||||
commify(std::to_string(copper))
|
||||
);
|
||||
} else if (copper && silver && gold && !platinum) { // CSG
|
||||
money_string = fmt::format(
|
||||
"{} Gold, {} Silver, and {} Copper",
|
||||
gold,
|
||||
silver,
|
||||
copper
|
||||
commify(std::to_string(gold)),
|
||||
commify(std::to_string(silver)),
|
||||
commify(std::to_string(copper))
|
||||
);
|
||||
} else if (copper && silver && !gold && !platinum) { // CS
|
||||
money_string = fmt::format(
|
||||
"{} Silver and {} Copper",
|
||||
silver,
|
||||
copper
|
||||
commify(std::to_string(silver)),
|
||||
commify(std::to_string(copper))
|
||||
);
|
||||
} else if (!copper && silver && gold && platinum) { // SGP
|
||||
money_string = fmt::format(
|
||||
"{} Platinum, {} Gold, and {} Silver",
|
||||
platinum,
|
||||
gold,
|
||||
silver
|
||||
commify(std::to_string(platinum)),
|
||||
commify(std::to_string(gold)),
|
||||
commify(std::to_string(silver))
|
||||
);
|
||||
} else if (!copper && silver && gold && !platinum) { // SG
|
||||
money_string = fmt::format(
|
||||
"{} Gold and {} Silver",
|
||||
gold,
|
||||
silver
|
||||
commify(std::to_string(gold)),
|
||||
commify(std::to_string(silver))
|
||||
);
|
||||
} else if (copper && !silver && gold && platinum) { // CGP
|
||||
money_string = fmt::format(
|
||||
"{} Platinum, {} Gold, and {} Copper",
|
||||
platinum,
|
||||
gold,
|
||||
copper
|
||||
commify(std::to_string(platinum)),
|
||||
commify(std::to_string(gold)),
|
||||
commify(std::to_string(copper))
|
||||
);
|
||||
} else if (copper && !silver && gold && !platinum) { // CG
|
||||
money_string = fmt::format(
|
||||
"{} Gold and {} Copper",
|
||||
gold,
|
||||
copper
|
||||
commify(std::to_string(gold)),
|
||||
commify(std::to_string(copper))
|
||||
);
|
||||
} else if (!copper && !silver && gold && platinum) { // GP
|
||||
money_string = fmt::format(
|
||||
"{} Platinum and {} Gold",
|
||||
platinum,
|
||||
gold
|
||||
commify(std::to_string(platinum)),
|
||||
commify(std::to_string(gold))
|
||||
);
|
||||
} else if (!copper && !silver && !gold && platinum) { // P
|
||||
money_string = fmt::format(
|
||||
"{} Platinum",
|
||||
platinum
|
||||
commify(std::to_string(platinum))
|
||||
);
|
||||
} else if (!copper && !silver && gold && !platinum) { // G
|
||||
money_string = fmt::format(
|
||||
"{} Gold",
|
||||
gold
|
||||
commify(std::to_string(gold))
|
||||
);
|
||||
} else if (!copper && silver && !gold && !platinum) { // S
|
||||
money_string = fmt::format(
|
||||
"{} Silver",
|
||||
silver
|
||||
commify(std::to_string(silver))
|
||||
);
|
||||
} else if (copper && !silver && !gold && !platinum) { // C
|
||||
money_string = fmt::format(
|
||||
"{} Copper",
|
||||
copper
|
||||
commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
return money_string;
|
||||
}
|
||||
|
||||
std::string commify(const std::string &number) {
|
||||
std::string temp_string;
|
||||
|
||||
auto string_length = static_cast<int>(number.length());
|
||||
|
||||
int i = 0;
|
||||
for (i = string_length - 3; i >= 0; i -= 3) {
|
||||
if (i > 0) {
|
||||
temp_string = "," + number.substr(static_cast<unsigned long>(i), 3) + temp_string;
|
||||
} else {
|
||||
temp_string = number.substr(static_cast<unsigned long>(i), 3) + temp_string;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
temp_string = number.substr(0, static_cast<unsigned long>(3 + i)) + temp_string;
|
||||
}
|
||||
|
||||
return temp_string;
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ std::string JoinString(const std::vector<std::string>& ar, const std::string &de
|
||||
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string);
|
||||
std::string replace_string(std::string subject, const std::string &search, const std::string &replace);
|
||||
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver);
|
||||
std::string commify(const std::string &number);
|
||||
|
||||
//const char based
|
||||
|
||||
@@ -203,7 +204,7 @@ bool strn0cpyt(char* dest, const char* source, uint32 size);
|
||||
char *CleanMobName(const char *in, char *out);
|
||||
char *RemoveApostrophes(const char *s);
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size);
|
||||
const char *ConvertArray(int input, char *returnchar);
|
||||
const char *ConvertArray(int64 input, char *returnchar);
|
||||
const char *ConvertArrayF(float input, char *returnchar);
|
||||
const char *MakeLowerString(const char *source);
|
||||
uint32 hextoi(const char* num);
|
||||
|
||||
@@ -61,6 +61,7 @@ struct ActivityInformation {
|
||||
int skill_id; // older clients, first id from above
|
||||
int spell_id; // older clients, first id from above
|
||||
int goal_id;
|
||||
std::string goal_match_list;
|
||||
TaskMethodType goal_method;
|
||||
int goal_count;
|
||||
int deliver_to_npc;
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9178
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9185
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_SUBDIRECTORY(luabind)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
IF(EQEMU_BUILD_PERL)
|
||||
ADD_SUBDIRECTORY(perlbind)
|
||||
ENDIF(EQEMU_BUILD_PERL)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
*
|
||||
!.gitignore
|
||||
!.editorconfig
|
||||
!CMakeLists.txt
|
||||
!LICENSE
|
||||
!README.md
|
||||
|
||||
!.github/
|
||||
!.github/**
|
||||
|
||||
!doc/
|
||||
!doc/**
|
||||
|
||||
!include/
|
||||
!include/**
|
||||
|
||||
!src/
|
||||
!src/*
|
||||
|
||||
!test/
|
||||
!test/*
|
||||
@@ -0,0 +1,64 @@
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
project(perlbind LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".so" ".a")
|
||||
|
||||
find_package(PerlLibs)
|
||||
|
||||
set(PERLBIND_HEADERS
|
||||
include/perlbind/array.h
|
||||
include/perlbind/forward.h
|
||||
include/perlbind/function.h
|
||||
include/perlbind/hash.h
|
||||
include/perlbind/interpreter.h
|
||||
include/perlbind/iterator.h
|
||||
include/perlbind/package.h
|
||||
include/perlbind/perlbind.h
|
||||
include/perlbind/scalar.h
|
||||
include/perlbind/stack.h
|
||||
include/perlbind/stack_push.h
|
||||
include/perlbind/stack_read.h
|
||||
include/perlbind/subcaller.h
|
||||
include/perlbind/traits.h
|
||||
include/perlbind/typemap.h
|
||||
include/perlbind/types.h
|
||||
include/perlbind/util.h
|
||||
include/perlbind/version.h
|
||||
)
|
||||
|
||||
set(PERLBIND_SOURCES
|
||||
src/function.cpp
|
||||
src/hash.cpp
|
||||
src/interpreter.cpp
|
||||
src/package.cpp
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(PERLBIND_SOURCES ${PERLBIND_SOURCES} src/perlbind.natvis)
|
||||
endif()
|
||||
|
||||
add_library(perlbind ${PERLBIND_SOURCES} ${PERLBIND_HEADERS})
|
||||
|
||||
target_include_directories(perlbind PUBLIC
|
||||
${PERL_INCLUDE_PATH}
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
option(PERLBIND_BUILD_TESTS "Build tests" OFF)
|
||||
option(PERLBIND_ENABLE_ASAN "Build with address sanitizer" OFF)
|
||||
|
||||
if(PERLBIND_ENABLE_ASAN)
|
||||
target_compile_options(perlbind PRIVATE -fsanitize=address -fno-omit-frame-pointer)
|
||||
target_link_options(perlbind PRIVATE -fsanitize=address -fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
if(PERLBIND_BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT tests)
|
||||
|
||||
target_include_directories(tests PRIVATE
|
||||
${PERL_INCLUDE_PATH}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
endif()
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2022 hg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "iterator.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
struct array : public type_base
|
||||
{
|
||||
using iterator = detail::array_iterator;
|
||||
|
||||
~array() noexcept
|
||||
{
|
||||
SvREFCNT_dec(m_av);
|
||||
}
|
||||
|
||||
array() noexcept
|
||||
: type_base(), m_av(newAV()) {}
|
||||
array(PerlInterpreter* interp) noexcept
|
||||
: type_base(interp), m_av(newAV()) {}
|
||||
array(const array& other) noexcept
|
||||
: type_base(other.my_perl), m_av(copy_array(other.m_av)) {}
|
||||
array(array&& other) noexcept
|
||||
: type_base(other.my_perl), m_av(other.m_av)
|
||||
{
|
||||
other.m_av = newAV();
|
||||
}
|
||||
array(AV*& value) noexcept
|
||||
: type_base(), m_av(copy_array(value)) {}
|
||||
array(AV*&& value) noexcept
|
||||
: type_base(), m_av(value) {} // take ownership
|
||||
array(scalar ref)
|
||||
: type_base(ref.my_perl)
|
||||
{
|
||||
if (!ref.is_array_ref())
|
||||
throw std::runtime_error("cannot construct array from non-array reference");
|
||||
|
||||
reset(reinterpret_cast<AV*>(SvREFCNT_inc(*ref)));
|
||||
}
|
||||
array(scalar_proxy proxy)
|
||||
: array(scalar(SvREFCNT_inc(proxy.sv()))) {}
|
||||
|
||||
array& operator=(const array& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
m_av = copy_array(other.m_av);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
array& operator=(array&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
std::swap(m_av, other.m_av);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
array& operator=(AV*& value) noexcept
|
||||
{
|
||||
if (m_av != value)
|
||||
m_av = copy_array(value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
array& operator=(AV*&& value) noexcept
|
||||
{
|
||||
reset(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator AV*() const { return m_av; }
|
||||
operator SV*() const { return reinterpret_cast<SV*>(m_av); }
|
||||
|
||||
AV* release() noexcept
|
||||
{
|
||||
AV* tmp = m_av;
|
||||
m_av = newAV();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void reset(AV* value) noexcept
|
||||
{
|
||||
SvREFCNT_dec(m_av);
|
||||
m_av = value;
|
||||
}
|
||||
|
||||
void clear() noexcept { av_clear(m_av); } // decreases refcnt of all SV elements
|
||||
scalar pop_back() noexcept { return av_pop(m_av); }
|
||||
scalar pop_front() noexcept { return av_shift(m_av); }
|
||||
void push_back(const scalar& value) { av_push(m_av, newSVsv(value)); }
|
||||
void push_back(scalar&& value) { av_push(m_av, value.release()); }
|
||||
void reserve(size_t count) { av_extend(m_av, count > 0 ? count - 1 : 0); }
|
||||
size_t size() const { return av_len(m_av) + 1; }
|
||||
SV* sv() const { return reinterpret_cast<SV*>(m_av); }
|
||||
|
||||
// returns a proxy that takes ownership of one reference to the SV element
|
||||
// extends the array and creates an undef SV if index out of range
|
||||
scalar_proxy operator[](size_t index)
|
||||
{
|
||||
SV** sv = av_fetch(m_av, index, 1);
|
||||
return scalar_proxy(my_perl, SvREFCNT_inc(*sv));
|
||||
}
|
||||
|
||||
iterator begin() const noexcept { return { my_perl, m_av, 0 }; }
|
||||
iterator end() const noexcept { return { my_perl, m_av, size() }; }
|
||||
|
||||
private:
|
||||
AV* copy_array(AV* other)
|
||||
{
|
||||
return av_make(av_len(other)+1, AvARRAY(other));
|
||||
}
|
||||
|
||||
AV* m_av = nullptr;
|
||||
};
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class xsub_stack;
|
||||
struct function_base;
|
||||
struct array_iterator;
|
||||
struct hash_iterator;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class interpreter;
|
||||
class package;
|
||||
struct scalar;
|
||||
struct scalar_proxy;
|
||||
struct reference;
|
||||
struct array;
|
||||
struct hash;
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,144 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
// traits for function and class method exports
|
||||
template <typename Ret, typename Class, typename... Args>
|
||||
struct base_traits
|
||||
{
|
||||
using return_t = Ret;
|
||||
using sig_t = util::type_name<Args...>;
|
||||
using stack_tuple = std::conditional_t<std::is_void<Class>::value,
|
||||
std::tuple<Args...>,
|
||||
std::tuple<Class*, Args...>>;
|
||||
static constexpr int arity = sizeof...(Args);
|
||||
static constexpr int stack_arity = sizeof...(Args) + (std::is_void<Class>::value ? 0 : 1);
|
||||
static constexpr int vararg_count = count_of<array, Args...>::value +
|
||||
count_of<hash, Args...>::value;
|
||||
static constexpr bool is_vararg = vararg_count > 0;
|
||||
static constexpr bool is_vararg_last = is_last<array, Args...>::value ||
|
||||
is_last<hash, Args...>::value;
|
||||
|
||||
static_assert(!is_vararg || (vararg_count == 1 && is_vararg_last),
|
||||
"A function may only accept a single array or hash and it must be "
|
||||
"be the last parameter. Prefer using reference parameters instead.");
|
||||
};
|
||||
|
||||
template <typename T, bool = std::is_class<T>::value>
|
||||
struct function_traits : public function_traits<decltype(&T::operator()), true> {};
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
struct function_traits<Ret(*)(Args...), false> : base_traits<Ret, void, Args...>
|
||||
{
|
||||
using type = Ret(*)(Args...);
|
||||
};
|
||||
|
||||
template <typename Ret, typename Class, typename... Args>
|
||||
struct function_traits<Ret(Class::*)(Args...), false> : base_traits<Ret, Class, Args...>
|
||||
{
|
||||
using type = Ret(Class::*)(Args...);
|
||||
};
|
||||
|
||||
template <typename Ret, typename Class, typename... Args>
|
||||
struct function_traits<Ret(Class::*)(Args...) const, false> : base_traits<Ret, Class, Args...>
|
||||
{
|
||||
using type = Ret(Class::*)(Args...) const;
|
||||
};
|
||||
|
||||
template <typename Ret, typename Class, typename... Args>
|
||||
struct function_traits<Ret(Class::*)(Args...) const, true> : base_traits<Ret, void, Args...>
|
||||
{
|
||||
using type = Ret(*)(Args...);
|
||||
};
|
||||
|
||||
// represents a bound native function
|
||||
struct function_base
|
||||
{
|
||||
virtual ~function_base() = default;
|
||||
virtual std::string get_signature() const = 0;
|
||||
virtual bool is_compatible(xsub_stack&) const = 0;
|
||||
virtual void call(xsub_stack&) const = 0;
|
||||
|
||||
static const MGVTBL mgvtbl;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct function : public function_base, function_traits<T>
|
||||
{
|
||||
using target_t = typename function::type;
|
||||
using return_t = typename function::return_t;
|
||||
|
||||
function() = delete;
|
||||
function(PerlInterpreter* interp, T func)
|
||||
: my_perl(interp), m_func(func) {}
|
||||
|
||||
std::string get_signature() const override
|
||||
{
|
||||
return util::type_name<target_t>::str();
|
||||
};
|
||||
|
||||
bool is_compatible(xsub_stack& stack) const override
|
||||
{
|
||||
return function::is_vararg || stack.check_types(typename function::stack_tuple{});
|
||||
}
|
||||
|
||||
void call(xsub_stack& stack) const override
|
||||
{
|
||||
if (!function::is_vararg && stack.size() != function::stack_arity)
|
||||
{
|
||||
using sig = typename function::sig_t;
|
||||
int count = std::is_member_function_pointer<T>::value ? stack.size() - 1 : stack.size();
|
||||
SV* err = newSVpvf("'%s(%s)' called with %d argument(s), expected %d\n argument(s): (%s)\n",
|
||||
stack.name().c_str(), sig::str().c_str(), count, function::arity, stack.types().c_str());
|
||||
err = sv_2mortal(err);
|
||||
throw std::runtime_error(SvPV_nolen(err));
|
||||
}
|
||||
|
||||
call_impl(stack, std::is_void<function::return_t>());
|
||||
}
|
||||
|
||||
private:
|
||||
void call_impl(xsub_stack& stack, std::false_type) const
|
||||
{
|
||||
return_t result = apply(m_func, stack.convert_stack(typename function::stack_tuple{}));
|
||||
stack.push_return(std::move(result));
|
||||
}
|
||||
|
||||
void call_impl(xsub_stack& stack, std::true_type) const
|
||||
{
|
||||
apply(m_func, stack.convert_stack(typename function::stack_tuple{}));
|
||||
}
|
||||
|
||||
// c++14 call function template with tuple arg unpacking (c++17 can use std::apply())
|
||||
template <typename F, typename Tuple, size_t... I>
|
||||
auto call_func(F func, Tuple&& t, std::index_sequence<I...>) const
|
||||
{
|
||||
return func(std::get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
template <typename F, typename Tuple, size_t... I>
|
||||
auto call_member(F method, Tuple&& t, std::index_sequence<I...>) const
|
||||
{
|
||||
return (std::get<0>(t)->*method)(std::get<I + 1>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
template <typename F, typename Tuple, std::enable_if_t<!std::is_member_function_pointer<F>::value, bool> = true>
|
||||
auto apply(F func, Tuple&& t) const
|
||||
{
|
||||
using make_sequence = std::make_index_sequence<std::tuple_size<Tuple>::value>;
|
||||
return call_func(func, std::forward<Tuple>(t), make_sequence{});
|
||||
}
|
||||
|
||||
template <typename F, typename Tuple, std::enable_if_t<std::is_member_function_pointer<F>::value, bool> = true>
|
||||
auto apply(F func, Tuple&& t) const
|
||||
{
|
||||
using make_sequence = std::make_index_sequence<std::tuple_size<Tuple>::value - 1>;
|
||||
return call_member(func, std::forward<Tuple>(t), make_sequence{});
|
||||
}
|
||||
|
||||
PerlInterpreter* my_perl = nullptr;
|
||||
T m_func;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
struct hash : public type_base
|
||||
{
|
||||
using iterator = detail::hash_iterator;
|
||||
|
||||
~hash() noexcept
|
||||
{
|
||||
SvREFCNT_dec(m_hv);
|
||||
}
|
||||
|
||||
hash() noexcept
|
||||
: type_base(), m_hv(newHV()) {}
|
||||
hash(PerlInterpreter* interp) noexcept
|
||||
: type_base(interp), m_hv(newHV()) {}
|
||||
hash(const hash& other) noexcept
|
||||
: type_base(other.my_perl), m_hv(copy_hash(other.m_hv)) {}
|
||||
hash(hash&& other) noexcept
|
||||
: type_base(other.my_perl), m_hv(other.m_hv)
|
||||
{
|
||||
other.m_hv = newHV();
|
||||
}
|
||||
hash(HV*& value) noexcept
|
||||
: type_base(), m_hv(copy_hash(value)) {}
|
||||
hash(HV*&& value) noexcept
|
||||
: type_base(), m_hv(value) {} // take ownership
|
||||
hash(scalar ref);
|
||||
hash(scalar_proxy proxy);
|
||||
|
||||
hash& operator=(const hash& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
m_hv = copy_hash(other.m_hv);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
hash& operator=(hash&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
std::swap(m_hv, other.m_hv);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
hash& operator=(HV*& value) noexcept
|
||||
{
|
||||
if (m_hv != value)
|
||||
m_hv = copy_hash(value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
hash& operator=(HV*&& value) noexcept
|
||||
{
|
||||
reset(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator HV*() const { return m_hv; }
|
||||
operator SV*() const { return reinterpret_cast<SV*>(m_hv); }
|
||||
|
||||
HV* release() noexcept
|
||||
{
|
||||
HV* tmp = m_hv;
|
||||
m_hv = newHV();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void reset(HV* value) noexcept
|
||||
{
|
||||
SvREFCNT_dec(m_hv);
|
||||
m_hv = value;
|
||||
}
|
||||
|
||||
scalar at(const char* key);
|
||||
scalar at(const std::string& key);
|
||||
void clear() noexcept { hv_clear(m_hv); }
|
||||
bool exists(const char* key) const
|
||||
{
|
||||
return hv_exists(m_hv, key, static_cast<I32>(strlen(key)));
|
||||
}
|
||||
bool exists(const std::string& key) const
|
||||
{
|
||||
return hv_exists(m_hv, key.c_str(), static_cast<I32>(key.size()));
|
||||
}
|
||||
void insert(const char* key, scalar value);
|
||||
void insert(const std::string& key, scalar value);
|
||||
void remove(const char* key)
|
||||
{
|
||||
hv_delete(m_hv, key, static_cast<I32>(strlen(key)), 0);
|
||||
}
|
||||
void remove(const std::string& key)
|
||||
{
|
||||
hv_delete(m_hv, key.c_str(), static_cast<I32>(key.size()), 0);
|
||||
}
|
||||
size_t size() const { return HvTOTALKEYS(m_hv); }
|
||||
SV* sv() const { return reinterpret_cast<SV*>(m_hv); }
|
||||
|
||||
// returns a proxy that takes ownership of one reference to the SV value
|
||||
// creates an undef SV entry for the key if it doesn't exist
|
||||
scalar_proxy operator[](const std::string& key);
|
||||
|
||||
iterator begin() const noexcept;
|
||||
iterator end() const noexcept;
|
||||
iterator find(const char* key);
|
||||
iterator find(const std::string& key);
|
||||
|
||||
private:
|
||||
scalar at(const char* key, size_t size);
|
||||
iterator find(const char* key, size_t size);
|
||||
void insert(const char* key, size_t size, scalar value);
|
||||
|
||||
HV* copy_hash(HV* other) noexcept;
|
||||
|
||||
HV* m_hv = nullptr;
|
||||
};
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
class interpreter
|
||||
{
|
||||
public:
|
||||
interpreter();
|
||||
interpreter(PerlInterpreter* interp) : my_perl(interp) {}
|
||||
interpreter(int argc, const char** argv);
|
||||
interpreter(const interpreter& other) = delete;
|
||||
interpreter(interpreter&& other) = delete;
|
||||
interpreter& operator=(const interpreter& other) = delete;
|
||||
interpreter& operator=(interpreter&& other) = delete;
|
||||
~interpreter();
|
||||
|
||||
PerlInterpreter* get() const { return my_perl; }
|
||||
|
||||
void load_script(std::string packagename, std::string filename);
|
||||
void eval(const char* str);
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T call_sub(const char* subname, Args&&... args) const
|
||||
{
|
||||
detail::sub_caller caller(my_perl);
|
||||
return caller.call_sub<T>(subname, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// returns interface to add bindings to package name
|
||||
package new_package(const char* name)
|
||||
{
|
||||
return package(my_perl, name);
|
||||
}
|
||||
|
||||
// registers type for blessing objects, returns interface
|
||||
template <typename T>
|
||||
class_<T> new_class(const char* name)
|
||||
{
|
||||
static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value,
|
||||
"new_class<T> 'T' should not be a pointer or reference");
|
||||
|
||||
auto typemap = detail::typemap::get(my_perl);
|
||||
auto type_id = detail::usertype<T*>::id();
|
||||
typemap[type_id] = name;
|
||||
|
||||
return class_<T>(my_perl, name);
|
||||
}
|
||||
|
||||
// helper to bind functions in default main:: package
|
||||
template <typename T>
|
||||
void add(const char* name, T&& func)
|
||||
{
|
||||
new_package("main").add(name, std::forward<T>(func));
|
||||
}
|
||||
|
||||
private:
|
||||
void init(int argc, const char** argv);
|
||||
|
||||
bool m_is_owner = false;
|
||||
PerlInterpreter* my_perl = nullptr;
|
||||
};
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
struct array_iterator
|
||||
{
|
||||
array_iterator() = default;
|
||||
array_iterator(PerlInterpreter* interp, AV* av, size_t index)
|
||||
: my_perl(interp), m_av(av), m_index(index), m_scalar(interp)
|
||||
{
|
||||
fetch();
|
||||
}
|
||||
|
||||
bool operator!=(const array_iterator& other) const
|
||||
{
|
||||
return m_index != other.m_index;
|
||||
}
|
||||
|
||||
array_iterator& operator++()
|
||||
{
|
||||
++m_index;
|
||||
fetch();
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar* operator->()
|
||||
{
|
||||
return &m_scalar;
|
||||
}
|
||||
|
||||
scalar& operator*()
|
||||
{
|
||||
return m_scalar;
|
||||
}
|
||||
|
||||
private:
|
||||
void fetch()
|
||||
{
|
||||
SV** sv = av_fetch(m_av, m_index, 0);
|
||||
if (sv)
|
||||
m_scalar = SvREFCNT_inc(*sv);
|
||||
}
|
||||
|
||||
PerlInterpreter* my_perl;
|
||||
AV* m_av;
|
||||
size_t m_index;
|
||||
scalar m_scalar;
|
||||
};
|
||||
|
||||
struct hash_iterator
|
||||
{
|
||||
hash_iterator() = default;
|
||||
hash_iterator(PerlInterpreter* interp, HV* hv, HE* he)
|
||||
: my_perl(interp), m_hv(hv), m_he(he)
|
||||
{
|
||||
fetch();
|
||||
}
|
||||
|
||||
bool operator==(const hash_iterator& other) const
|
||||
{
|
||||
return m_he == other.m_he;
|
||||
}
|
||||
|
||||
bool operator!=(const hash_iterator& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
hash_iterator& operator++()
|
||||
{
|
||||
m_he = hv_iternext(m_hv);
|
||||
fetch();
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::pair<const char*, scalar>* operator->()
|
||||
{
|
||||
return &m_pair;
|
||||
}
|
||||
|
||||
std::pair<const char*, scalar>& operator*()
|
||||
{
|
||||
return m_pair;
|
||||
}
|
||||
|
||||
private:
|
||||
void fetch()
|
||||
{
|
||||
if (m_he)
|
||||
m_pair = { HePV(m_he, PL_na), scalar(my_perl, SvREFCNT_inc(HeVAL(m_he))) };
|
||||
}
|
||||
|
||||
PerlInterpreter* my_perl;
|
||||
HV* m_hv;
|
||||
HE* m_he;
|
||||
std::pair<const char*, scalar> m_pair;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
class package
|
||||
{
|
||||
public:
|
||||
virtual ~package() = default;
|
||||
package() = delete;
|
||||
package(PerlInterpreter* interp, const char* name)
|
||||
: my_perl(interp), m_name(name), m_stash(gv_stashpv(name, GV_ADD))
|
||||
{}
|
||||
|
||||
// bind a function pointer to a function name in the package
|
||||
// overloads with same name must be explicit (default parameters not supported)
|
||||
// overloads have a runtime lookup cost and chooses the first compatible overload
|
||||
template <typename T>
|
||||
void add(const char* name, T func)
|
||||
{
|
||||
// ownership of function object is given to perl
|
||||
auto function = new detail::function<T>(my_perl, func);
|
||||
add_impl(name, static_cast<detail::function_base*>(function));
|
||||
}
|
||||
|
||||
// specify a base class name for object inheritance (must be registered)
|
||||
// calling object methods missing from the package will search parent classes
|
||||
// base classes are searched in registered order and include any grandparents
|
||||
void add_base_class(const char* name)
|
||||
{
|
||||
std::string package_isa = m_name + "::ISA";
|
||||
AV* av = get_av(package_isa.c_str(), GV_ADD);
|
||||
array isa_array = reinterpret_cast<AV*>(SvREFCNT_inc(av));
|
||||
isa_array.push_back(name);
|
||||
}
|
||||
|
||||
// add a constant value to this package namespace
|
||||
template <typename T>
|
||||
void add_const(const char* name, T&& value)
|
||||
{
|
||||
newCONSTSUB(m_stash, name, scalar(value).release());
|
||||
}
|
||||
|
||||
private:
|
||||
void add_impl(const char* name, detail::function_base* function);
|
||||
|
||||
std::string m_name;
|
||||
PerlInterpreter* my_perl = nullptr;
|
||||
HV* m_stash = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct class_ : public package
|
||||
{
|
||||
using package::package;
|
||||
};
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
// Defining PERLBIND_STRICT_NUMERIC_TYPES will enable strict type checks
|
||||
// for integers and floats.This is required for overloads that depend on
|
||||
// int and float type differences.
|
||||
// #define PERLBIND_STRICT_NUMERIC_TYPES
|
||||
|
||||
// Defining PERLBIND_NO_STRICT_SCALAR_TYPES will disable strict type checks
|
||||
// for all int, float, and string function arguments. These types will only
|
||||
// be checked for scalar validity and converted to the function's expected
|
||||
// paramter type. This will break overloads that depend on distinct types.
|
||||
// This option overrides PERLBIND_STRICT_NUMERIC_TYPES.
|
||||
//#define PERLBIND_NO_STRICT_SCALAR_TYPES
|
||||
|
||||
// defining PERL_NO_GET_CONTEXT gets context from local variable "my_perl"
|
||||
// instead of calling Perl_get_context() in macros
|
||||
#define PERL_NO_GET_CONTEXT
|
||||
|
||||
#define WIN32IO_IS_STDIO
|
||||
#if _MSC_VER
|
||||
#define __inline__ __inline
|
||||
// perl 5.30+ defines HAS_BUILTIN_EXPECT for msvc which breaks builds
|
||||
#define __builtin_expect(expr,val) (expr)
|
||||
// avoid INT64_C and UINT64_C redefinition warnings
|
||||
#if PERL_VERSION < 28
|
||||
#include <cstdint>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
#include <XSUB.h>
|
||||
|
||||
// short name perl macros that cause issues
|
||||
#undef Move
|
||||
#undef Copy
|
||||
#undef Zero
|
||||
#undef list
|
||||
#undef seed
|
||||
#undef do_open
|
||||
#undef do_close
|
||||
|
||||
#include <perlbind/version.h>
|
||||
#include <perlbind/forward.h>
|
||||
#include <perlbind/util.h>
|
||||
#include <perlbind/traits.h>
|
||||
#include <perlbind/hash.h>
|
||||
#include <perlbind/typemap.h>
|
||||
#include <perlbind/scalar.h>
|
||||
#include <perlbind/array.h>
|
||||
#include <perlbind/stack.h>
|
||||
#include <perlbind/subcaller.h>
|
||||
#include <perlbind/function.h>
|
||||
#include <perlbind/package.h>
|
||||
#include <perlbind/interpreter.h>
|
||||
@@ -0,0 +1,254 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
struct scalar : type_base
|
||||
{
|
||||
virtual ~scalar() noexcept
|
||||
{
|
||||
SvREFCNT_dec(m_sv);
|
||||
}
|
||||
|
||||
scalar() noexcept
|
||||
: type_base(), m_sv(newSV(0)) {} // nothing allocated
|
||||
scalar(PerlInterpreter* interp) noexcept
|
||||
: type_base(interp), m_sv(newSV(0)) {}
|
||||
scalar(PerlInterpreter* interp, SV*&& sv) noexcept
|
||||
: type_base(interp), m_sv(sv) {}
|
||||
scalar(const scalar& other) noexcept
|
||||
: type_base(other.my_perl), m_sv(newSVsv(other.m_sv)) {}
|
||||
scalar(scalar&& other) noexcept
|
||||
: type_base(other.my_perl), m_sv(other.m_sv)
|
||||
{
|
||||
other.m_sv = newSV(0);
|
||||
}
|
||||
scalar(SV*& value) noexcept
|
||||
: type_base(), m_sv(newSVsv(value)) {}
|
||||
scalar(SV*&& value) noexcept
|
||||
: type_base(), m_sv(value) {}
|
||||
scalar(const char* value) noexcept
|
||||
: type_base(), m_sv(newSVpv(value, 0)) {}
|
||||
scalar(const std::string& value) noexcept
|
||||
: type_base(), m_sv(newSVpvn(value.c_str(), value.size())) {}
|
||||
|
||||
template <typename T, std::enable_if_t<detail::is_signed_integral_or_enum<T>::value, bool> = true>
|
||||
scalar(T value) noexcept : type_base(), m_sv(newSViv(static_cast<IV>(value))) {}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
|
||||
scalar(T value) noexcept : type_base(), m_sv(newSVuv(value)) {}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
scalar(T value) noexcept : type_base(), m_sv(newSVnv(value)) {}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
||||
scalar(T value) noexcept : type_base(), m_sv(newSV(0))
|
||||
{
|
||||
*this = std::move(value);
|
||||
}
|
||||
|
||||
scalar& operator=(const scalar& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
sv_setsv(m_sv, other.m_sv);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar& operator=(scalar&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
std::swap(m_sv, other.m_sv);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar& operator=(SV*& value) noexcept
|
||||
{
|
||||
sv_setsv(m_sv, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar& operator=(SV*&& value) noexcept
|
||||
{
|
||||
reset(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar& operator=(const char* value) noexcept
|
||||
{
|
||||
sv_setpv(m_sv, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar& operator=(const std::string& value) noexcept
|
||||
{
|
||||
sv_setpvn(m_sv, value.c_str(), value.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<detail::is_signed_integral_or_enum<T>::value, bool> = true>
|
||||
scalar& operator=(T value) noexcept
|
||||
{
|
||||
sv_setiv(m_sv, static_cast<IV>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
|
||||
scalar& operator=(T value) noexcept
|
||||
{
|
||||
sv_setuv(m_sv, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
scalar& operator=(T value) noexcept
|
||||
{
|
||||
sv_setnv(m_sv, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
||||
scalar& operator=(T value) noexcept
|
||||
{
|
||||
// bless if it's in the typemap
|
||||
const char* type_name = detail::typemap::template get_name<T>(my_perl);
|
||||
sv_setref_pv(m_sv, type_name, static_cast<void*>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator SV*() const { return m_sv; }
|
||||
operator void*() const { return m_sv; }
|
||||
operator const char*() const { return SvPV_nolen(m_sv); }
|
||||
operator std::string() const { return SvPV_nolen(m_sv); }
|
||||
template <typename T, std::enable_if_t<detail::is_signed_integral_or_enum<T>::value, bool> = true>
|
||||
operator T() const { return static_cast<T>(SvIV(m_sv)); }
|
||||
template <typename T, std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
|
||||
operator T() const { return static_cast<T>(SvUV(m_sv)); }
|
||||
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
operator T() const { return static_cast<T>(SvNV(m_sv)); }
|
||||
template <typename T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
||||
operator T() const
|
||||
{
|
||||
const char* type_name = detail::typemap::template get_name<T>(my_perl);
|
||||
if (type_name && sv_isobject(m_sv) && sv_derived_from(m_sv, type_name))
|
||||
{
|
||||
IV tmp = SvIV(SvRV(m_sv));
|
||||
return INT2PTR(T, tmp);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T as() const { return static_cast<T>(*this); }
|
||||
|
||||
// release ownership of SV
|
||||
SV* release() noexcept
|
||||
{
|
||||
SV* tmp = m_sv;
|
||||
m_sv = newSV(0);
|
||||
return tmp;
|
||||
}
|
||||
// take ownership of an SV
|
||||
void reset(SV* value) noexcept
|
||||
{
|
||||
SvREFCNT_dec(m_sv);
|
||||
m_sv = value;
|
||||
}
|
||||
|
||||
SV* sv() const { return m_sv; }
|
||||
SV* deref() const { return SvRV(m_sv); }
|
||||
size_t size() const { return SvPOK(m_sv) ? sv_len(m_sv) : 0; }
|
||||
svtype type() const { return SvTYPE(m_sv); }
|
||||
const char* c_str() const { return SvPV_nolen(m_sv); }
|
||||
|
||||
SV* operator*() { return SvRV(m_sv); }
|
||||
|
||||
bool is_null() const { return type() == SVt_NULL; } //SvOK(m_sv)
|
||||
bool is_integer() const { return SvIOK(m_sv); }
|
||||
bool is_float() const { return SvNOK(m_sv); }
|
||||
bool is_string() const { return SvPOK(m_sv); }
|
||||
bool is_reference() const { return SvROK(m_sv); }
|
||||
bool is_scalar_ref() const { return SvROK(m_sv) && SvTYPE(SvRV(m_sv)) < SVt_PVAV; }
|
||||
bool is_array_ref() const { return SvROK(m_sv) && SvTYPE(SvRV(m_sv)) == SVt_PVAV; }
|
||||
bool is_hash_ref() const { return SvROK(m_sv) && SvTYPE(SvRV(m_sv)) == SVt_PVHV; }
|
||||
|
||||
protected:
|
||||
SV* m_sv = nullptr;
|
||||
};
|
||||
|
||||
// references are scalars that take ownership of one new reference to a value
|
||||
// use reset() to take ownership of an existing RV
|
||||
struct reference : public scalar
|
||||
{
|
||||
reference() = default;
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_base_of<type_base, T>::value, bool> = true>
|
||||
reference(T& value) noexcept : scalar(value.my_perl, nullptr) { m_sv = newRV_inc(value); }
|
||||
|
||||
// increments referent for rvalues of scalar objects (not raw SVs) since they dec on destruct
|
||||
template <typename T, std::enable_if_t<std::is_base_of<type_base, T>::value, bool> = true>
|
||||
reference(T&& value) noexcept : scalar(value.my_perl, nullptr) { m_sv = newRV_inc(value); }
|
||||
|
||||
template <typename T, std::enable_if_t<detail::is_any<T, SV*, AV*, HV*>::value, bool> = true>
|
||||
reference(T& value) noexcept { reset(newRV_inc(reinterpret_cast<SV*>(value))); }
|
||||
|
||||
template <typename T, std::enable_if_t<detail::is_any<T, SV*, AV*, HV*>::value, bool> = true>
|
||||
reference(T&& value) noexcept { reset(newRV_noinc(reinterpret_cast<SV*>(value))); }
|
||||
|
||||
SV* operator*() { return SvRV(m_sv); }
|
||||
};
|
||||
|
||||
// scalar proxy reference is used for array and hash index operator[] overloads
|
||||
struct scalar_proxy
|
||||
{
|
||||
scalar_proxy() = delete;
|
||||
scalar_proxy(PerlInterpreter* interp, scalar&& value) noexcept
|
||||
: my_perl(interp), m_value(std::move(value)) {}
|
||||
|
||||
SV* sv() const { return m_value; }
|
||||
const char* c_str() const { return static_cast<const char*>(m_value); }
|
||||
|
||||
template <typename T>
|
||||
T as() const { return m_value.as<T>(); }
|
||||
|
||||
operator std::string() const { return m_value; }
|
||||
|
||||
// copying value to supported conversion types (e.g. int val = arr[i])
|
||||
template <typename T, std::enable_if_t<!std::is_base_of<type_base, T>::value, bool> = true>
|
||||
operator T() const
|
||||
{
|
||||
return static_cast<T>(m_value);
|
||||
}
|
||||
|
||||
// taking a reference to the source SV (e.g. scalar val = arr[i])
|
||||
template <typename T, std::enable_if_t<std::is_same<T, scalar>::value, bool> = true>
|
||||
operator T() const
|
||||
{
|
||||
return SvREFCNT_inc(m_value);
|
||||
}
|
||||
|
||||
// assigning scalar to proxy, the source SV is modified (arr[i] = "new value")
|
||||
scalar_proxy& operator=(scalar value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scalar_proxy& operator=(const scalar_proxy& other)
|
||||
{
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// todo: nested proxy[]
|
||||
|
||||
private:
|
||||
PerlInterpreter* my_perl = nullptr;
|
||||
scalar m_value;
|
||||
};
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include "stack_push.h"
|
||||
#include "stack_read.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
// handles xsub call stack from perl, inherits stack::pusher to push return values
|
||||
class xsub_stack : public stack::pusher
|
||||
{
|
||||
public:
|
||||
xsub_stack() = delete;
|
||||
xsub_stack(PerlInterpreter* my_perl, CV* cv)
|
||||
: stack::pusher(my_perl)
|
||||
{
|
||||
GV* gv = CvGV(cv);
|
||||
m_sub_name = GvNAME(gv);
|
||||
m_pkg_name = HvNAME(GvSTASH(gv));
|
||||
|
||||
dXSARGS;
|
||||
this->sp = sp;
|
||||
this->ax = ax;
|
||||
this->mark = mark;
|
||||
this->items = items;
|
||||
}
|
||||
~xsub_stack() { XSRETURN(m_pushed); }
|
||||
|
||||
int size() const { return items; }
|
||||
std::string name() const { return std::string(pkg_name()) + "::" + sub_name(); }
|
||||
const char* pkg_name() const { return m_pkg_name; }
|
||||
const char* sub_name() const { return m_sub_name; }
|
||||
|
||||
template <typename T>
|
||||
void push_return(T&& value)
|
||||
{
|
||||
XSprePUSH;
|
||||
push(std::forward<T>(value));
|
||||
}
|
||||
|
||||
// returns true if all perl stack arguments are compatible with expected native arg types
|
||||
template <typename Tuple>
|
||||
bool check_types(Tuple&& types)
|
||||
{
|
||||
static constexpr int count = std::tuple_size<Tuple>::value;
|
||||
if (items != count)
|
||||
return false;
|
||||
else if (count == 0)
|
||||
return true;
|
||||
|
||||
using make_sequence = std::make_index_sequence<count>;
|
||||
return check_stack(std::forward<Tuple>(types), make_sequence());
|
||||
}
|
||||
|
||||
// returns tuple of converted perl stack arguments, throws on an incompatible type
|
||||
template <typename Tuple>
|
||||
auto convert_stack(Tuple&& types)
|
||||
{
|
||||
using make_sequence = std::make_index_sequence<std::tuple_size<Tuple>::value>;
|
||||
return get_stack(std::forward<Tuple>(types), make_sequence());
|
||||
}
|
||||
|
||||
std::string types()
|
||||
{
|
||||
std::string args;
|
||||
for (int i = 0; i < items; ++i)
|
||||
{
|
||||
args += get_type_name(ST(i));
|
||||
if (i < (items - 1))
|
||||
args += ", ";
|
||||
}
|
||||
return args.empty() ? "void" : args;
|
||||
}
|
||||
|
||||
protected:
|
||||
int ax = 0;
|
||||
int items = 0;
|
||||
SV** mark = nullptr;
|
||||
const char* m_pkg_name = nullptr;
|
||||
const char* m_sub_name = nullptr;
|
||||
|
||||
std::string get_type_name(SV* item)
|
||||
{
|
||||
switch (SvTYPE(item))
|
||||
{
|
||||
case SVt_NULL: return "<undefined>";
|
||||
case SVt_NV: return "double";
|
||||
case SVt_PV: return "string";
|
||||
case SVt_PVAV: return "array";
|
||||
case SVt_PVHV: return "hash";
|
||||
case SVt_IV:
|
||||
if (sv_isobject(item))
|
||||
return std::string(sv_reftype(SvRV(item), true)) + "*";
|
||||
else if (SvROK(item))
|
||||
return "ref";
|
||||
else
|
||||
return "int";
|
||||
default:
|
||||
return sv_reftype(item, true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
bool check_index(T t, size_t index)
|
||||
{
|
||||
return stack::read_as<T>::check(my_perl, static_cast<int>(index), ax, items);
|
||||
}
|
||||
|
||||
// return true if perl stack matches all expected argument types in tuple
|
||||
template <typename Tuple, size_t... I>
|
||||
bool check_stack(Tuple&& t, std::index_sequence<I...>)
|
||||
{
|
||||
// lists compatibility of each expected arg type (no short-circuit)
|
||||
std::initializer_list<bool> res = {
|
||||
check_index(std::get<I>(std::forward<Tuple>(t)), I)... };
|
||||
|
||||
return std::all_of(res.begin(), res.end(), [](bool same) { return same; });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get_stack_index(T t, size_t index)
|
||||
{
|
||||
return stack::read_as<T>::get(my_perl, static_cast<int>(index), ax, items);
|
||||
}
|
||||
|
||||
template <typename Tuple, size_t... I>
|
||||
auto get_stack(Tuple&& t, std::index_sequence<I...>)
|
||||
{
|
||||
return Tuple{ get_stack_index(std::get<I>(std::forward<Tuple>(t)), I)... };
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace perlbind { namespace stack {
|
||||
|
||||
// base class for pushing value types to perl stack
|
||||
// methods use macros that push new mortalized SVs but do not extend the stack
|
||||
// the stack is only extended when pushing an array, hash, or using push_args().
|
||||
// this is because for xsubs the "stack is always large enough to take one return value"
|
||||
struct pusher
|
||||
{
|
||||
virtual ~pusher() = default;
|
||||
|
||||
pusher() = delete;
|
||||
pusher(PerlInterpreter* interp) : my_perl(interp), sp(PL_stack_sp) {}
|
||||
|
||||
SV* pop() { return POPs; }
|
||||
|
||||
void push(bool value) { PUSHs(boolSV(value)); ++m_pushed; }
|
||||
void push(const char* value)
|
||||
{
|
||||
if (!value)
|
||||
PUSHs(&PL_sv_undef);
|
||||
else
|
||||
mPUSHp(value, strlen(value));
|
||||
|
||||
++m_pushed;
|
||||
}
|
||||
void push(const std::string& value) { mPUSHp(value.c_str(), value.size()); ++m_pushed; }
|
||||
void push(scalar value) { mPUSHs(value.release()); ++m_pushed; };
|
||||
void push(reference value) { mPUSHs(value.release()); ++m_pushed; };
|
||||
|
||||
void push(array value)
|
||||
{
|
||||
int count = static_cast<int>(value.size());
|
||||
EXTEND(sp, count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
// mortalizes one reference to array element to avoid copying
|
||||
PUSHs(sv_2mortal(SvREFCNT_inc(value[i].sv())));
|
||||
}
|
||||
m_pushed += count;
|
||||
}
|
||||
|
||||
void push(hash value)
|
||||
{
|
||||
// hashes are pushed to the perl stack as alternating keys and values
|
||||
// this is less efficient than pushing a reference to the hash
|
||||
auto count = hv_iterinit(value) * 2;
|
||||
EXTEND(sp, count);
|
||||
while (HE* entry = hv_iternext(value))
|
||||
{
|
||||
auto val = HeVAL(entry);
|
||||
PUSHs(hv_iterkeysv(entry)); // mortalizes new key sv (keys are not stored as sv)
|
||||
PUSHs(sv_2mortal(SvREFCNT_inc(val)));
|
||||
}
|
||||
m_pushed += count;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<detail::is_signed_integral_or_enum<T>::value, bool> = true>
|
||||
void push(T value) { mPUSHi(static_cast<IV>(value)); ++m_pushed; }
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
|
||||
void push(T value) { mPUSHu(value); ++m_pushed; }
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
void push(T value) { mPUSHn(value); ++m_pushed; }
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
|
||||
void push(T value)
|
||||
{
|
||||
const char* type_name = detail::typemap::get_name<T>(my_perl);
|
||||
if (!type_name)
|
||||
{
|
||||
throw std::runtime_error("cannot push unregistered pointer of type '" + util::type_name<T>::str() + "'");
|
||||
}
|
||||
|
||||
SV* sv = sv_newmortal();
|
||||
sv_setref_pv(sv, type_name, static_cast<void*>(value));
|
||||
PUSHs(sv);
|
||||
++m_pushed;
|
||||
};
|
||||
|
||||
void push(void* value)
|
||||
{
|
||||
SV* sv = sv_newmortal();
|
||||
sv_setref_pv(sv, nullptr, value); // unblessed
|
||||
PUSHs(sv);
|
||||
++m_pushed;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void push_args(Args&&... args)
|
||||
{
|
||||
EXTEND(sp, sizeof...(Args));
|
||||
push_args_impl(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
protected:
|
||||
PerlInterpreter* my_perl = nullptr;
|
||||
SV** sp = nullptr;
|
||||
int m_pushed = 0;
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
void push_args_impl(Args&&... args) {}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void push_args_impl(T&& value, Args&&... args)
|
||||
{
|
||||
push(std::forward<T>(value));
|
||||
push_args(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace stack
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,266 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace perlbind { namespace stack {
|
||||
|
||||
// perl stack reader to convert types, throws if perl stack value isn't type compatible
|
||||
template <typename T, typename = void>
|
||||
struct read_as;
|
||||
|
||||
template <typename T>
|
||||
struct read_as<T, std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
#ifdef PERLBIND_NO_STRICT_SCALAR_TYPES
|
||||
return SvTYPE(ST(i)) < SVt_PVAV;
|
||||
#elif !defined PERLBIND_STRICT_NUMERIC_TYPES
|
||||
return SvNIOK(ST(i));
|
||||
#else
|
||||
return SvIOK(ST(i));
|
||||
#endif
|
||||
}
|
||||
|
||||
static T get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be an integer");
|
||||
}
|
||||
return static_cast<T>(SvIV(ST(i))); // unsigned and bools casted
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct read_as<T, std::enable_if_t<std::is_floating_point<T>::value>>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
#ifdef PERLBIND_NO_STRICT_SCALAR_TYPES
|
||||
return SvTYPE(ST(i)) < SVt_PVAV;
|
||||
#elif !defined PERLBIND_STRICT_NUMERIC_TYPES
|
||||
return SvNIOK(ST(i));
|
||||
#else
|
||||
return SvNOK(ST(i));
|
||||
#endif
|
||||
}
|
||||
|
||||
static T get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a floating point");
|
||||
}
|
||||
return static_cast<T>(SvNV(ST(i)));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<const char*>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
#ifdef PERLBIND_NO_STRICT_SCALAR_TYPES
|
||||
return SvTYPE(ST(i)) < SVt_PVAV;
|
||||
#else
|
||||
return SvPOK(ST(i));
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char* get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a string");
|
||||
}
|
||||
return static_cast<const char*>(SvPV_nolen(ST(i)));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<std::string> : read_as<const char*>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<void*>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
return sv_isobject(ST(i));
|
||||
}
|
||||
|
||||
static void* get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a reference to an object");
|
||||
}
|
||||
|
||||
IV tmp = SvIV(SvRV(ST(i)));
|
||||
return INT2PTR(void*, tmp);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct read_as<T, std::enable_if_t<std::is_pointer<T>::value>>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
const char* type_name = detail::typemap::get_name<T>(my_perl);
|
||||
return type_name && sv_isobject(ST(i)) && sv_derived_from(ST(i), type_name);
|
||||
}
|
||||
|
||||
static T get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
// would prefer to check for unregistered types at compile time (not possible?)
|
||||
const char* type_name = detail::typemap::get_name<T>(my_perl);
|
||||
if (!type_name)
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a reference to an unregistered type (method unusable)");
|
||||
}
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a reference to an object of type '" + type_name + "'");
|
||||
}
|
||||
|
||||
IV tmp = SvIV(SvRV(ST(i)));
|
||||
return INT2PTR(T, tmp);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct read_as<nullable<T>>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static nullable<T> get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (sv_isobject(ST(i)))
|
||||
{
|
||||
const char* type_name = detail::typemap::get_name<T>(my_perl);
|
||||
if (type_name && sv_derived_from(ST(i), type_name))
|
||||
{
|
||||
IV tmp = SvIV(SvRV(ST(i)));
|
||||
return INT2PTR(T, tmp);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<SV*>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
return i < items;
|
||||
}
|
||||
|
||||
static SV* get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be valid scalar value");
|
||||
}
|
||||
return ST(i);
|
||||
}
|
||||
};
|
||||
|
||||
// scalar, array, and hash readers return reference to stack items (not copies)
|
||||
template <>
|
||||
struct read_as<scalar>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
return (SvROK(ST(i)) && SvTYPE(SvRV(ST(i))) < SVt_PVAV) || SvTYPE(ST(i)) < SVt_PVAV;
|
||||
}
|
||||
|
||||
static scalar get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a scalar or reference to a scalar");
|
||||
}
|
||||
return SvROK(ST(i)) ? SvREFCNT_inc(SvRV(ST(i))) : SvREFCNT_inc(ST(i));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<reference>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
return SvROK(ST(i));
|
||||
}
|
||||
|
||||
static reference get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be a reference");
|
||||
}
|
||||
// take ownership of a reference to the RV itself (avoid reference to a reference)
|
||||
reference result;
|
||||
result.reset(SvREFCNT_inc(ST(i)));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<array>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
return items > i;
|
||||
}
|
||||
|
||||
static array get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be start of a perl array");
|
||||
}
|
||||
|
||||
array result;
|
||||
result.reserve(items - i);
|
||||
for (int index = i; index < items; ++index)
|
||||
{
|
||||
result.push_back(SvREFCNT_inc(ST(index)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct read_as<hash>
|
||||
{
|
||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
int remaining = items - i;
|
||||
return remaining > 0 && remaining % 2 == 0 && SvTYPE(ST(i)) == SVt_PV;
|
||||
}
|
||||
|
||||
static hash get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||
{
|
||||
if (!check(my_perl, i, ax, items))
|
||||
{
|
||||
throw std::runtime_error("expected argument " + std::to_string(i+1) + " to be start of a perl hash");
|
||||
}
|
||||
|
||||
hash result;
|
||||
for (int index = i; index < items; index += 2)
|
||||
{
|
||||
const char* key = SvPV_nolen(ST(index));
|
||||
result[key] = SvREFCNT_inc(ST(index + 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace stack
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
// handles calls to perl, inherits stack::pusher to push args to perl sub
|
||||
class sub_caller : public stack::pusher
|
||||
{
|
||||
public:
|
||||
sub_caller() = delete;
|
||||
sub_caller(PerlInterpreter* my_perl) : stack::pusher(my_perl)
|
||||
{
|
||||
ENTER; // enter scope boundary for any mortals we create
|
||||
SAVETMPS;
|
||||
}
|
||||
~sub_caller()
|
||||
{
|
||||
PUTBACK; // set global sp back to local for any popped return values
|
||||
FREETMPS;
|
||||
LEAVE; // leave scope, decref mortals and values returned by perl
|
||||
}
|
||||
|
||||
template <typename T, typename... Args, std::enable_if_t<std::is_void<T>::value, bool> = true>
|
||||
auto call_sub(const char* subname, Args&&... args)
|
||||
{
|
||||
call_sub_impl(subname, G_EVAL|G_VOID, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args, std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
auto call_sub(const char* subname, Args&&... args)
|
||||
{
|
||||
T result = 0;
|
||||
|
||||
try
|
||||
{
|
||||
int count = call_sub_impl(subname, G_EVAL|G_SCALAR, std::forward<Args>(args)...);
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
SV* sv_result = pop();
|
||||
result = static_cast<T>(SvIV(sv_result));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pop(); // top of stack holds undef on error when called with these flags
|
||||
throw;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
int call_sub_impl(const char* subname, int flags, Args&&... args)
|
||||
{
|
||||
PUSHMARK(SP); // notify perl of local sp (required even if not pushing args)
|
||||
push_args(std::forward<Args>(args)...);
|
||||
PUTBACK; // set global sp back to local so call will know pushed arg count
|
||||
|
||||
int result_count = call_pv(subname, flags);
|
||||
|
||||
SPAGAIN; // refresh local sp since call may reallocate stack for scalar returns
|
||||
|
||||
// ERRSV doesn't work in perl 5.28+ here for unknown reasons
|
||||
SV* err = get_sv("@", 0);
|
||||
if (SvTRUE(err))
|
||||
{
|
||||
throw std::runtime_error("Perl error: " + std::string(SvPV_nolen(err)));
|
||||
}
|
||||
|
||||
return result_count;
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
template<typename T, typename... Rest>
|
||||
struct is_any : std::false_type {};
|
||||
template<typename T, typename Last>
|
||||
struct is_any<T, Last> : std::is_same<T, Last> {};
|
||||
template<typename T, typename First, typename... Rest>
|
||||
struct is_any<T, First, Rest...> : std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_signed_integral : std::integral_constant<bool, std::is_integral<T>::value && std::is_signed<T>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_signed_integral_or_enum : std::integral_constant<bool, is_signed_integral<T>::value || std::is_enum<T>::value> {};
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
struct count_of : std::integral_constant<size_t, 0> {};
|
||||
template <typename T, typename Last>
|
||||
struct count_of<T, Last> : std::integral_constant<size_t, std::is_same<T, Last>::value ? 1 : 0> {};
|
||||
template <typename T, typename Next, typename... Rest>
|
||||
struct count_of<T, Next, Rest...> : std::integral_constant<size_t, count_of<T, Next>::value + count_of<T, Rest...>::value> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_last : std::false_type {};
|
||||
template <typename T, typename Last>
|
||||
struct is_last<T, Last> : std::is_same<T, Last> {};
|
||||
template <typename T, typename Next, typename... Args>
|
||||
struct is_last<T, Next, Args...> : std::integral_constant<bool, is_last<T, Args...>::value> {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
struct usertype_counter
|
||||
{
|
||||
static std::size_t next_id()
|
||||
{
|
||||
static std::size_t counter = 0;
|
||||
return counter++;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct usertype
|
||||
{
|
||||
static std::string id()
|
||||
{
|
||||
static std::size_t id = usertype_counter::next_id();
|
||||
return std::to_string(id);
|
||||
}
|
||||
};
|
||||
|
||||
namespace typemap
|
||||
{
|
||||
// type names are stored in a hash on interpreter when registered with
|
||||
// unique id keys generated by usertype counter
|
||||
inline hash get(PerlInterpreter* my_perl)
|
||||
{
|
||||
HV* hv = get_hv("__perlbind::typemap", GV_ADD);
|
||||
return reinterpret_cast<HV*>(SvREFCNT_inc(hv));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char* get_name(PerlInterpreter* my_perl)
|
||||
{
|
||||
auto typemap = detail::typemap::get(my_perl);
|
||||
auto type_id = detail::template usertype<T>::id();
|
||||
|
||||
return typemap.exists(type_id) ? typemap[type_id].c_str() : nullptr;
|
||||
}
|
||||
} // namespace typemap
|
||||
|
||||
} // namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
struct type_base
|
||||
{
|
||||
type_base() : my_perl(PERL_GET_THX) {}
|
||||
type_base(PerlInterpreter* interp) : my_perl(interp) {}
|
||||
PerlInterpreter* my_perl = nullptr;
|
||||
};
|
||||
|
||||
// helper type to allow null object reference arguments in bindings
|
||||
template <typename T>
|
||||
struct nullable
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value, "nullable<T> 'T' must be pointer");
|
||||
|
||||
nullable() = default;
|
||||
nullable(T ptr) : m_ptr(ptr) {}
|
||||
T get() { return m_ptr; }
|
||||
private:
|
||||
T m_ptr = nullptr;
|
||||
};
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#ifndef _MSC_VER
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace perlbind { namespace util {
|
||||
|
||||
inline std::string demangle(const char* name)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
int status = 0;
|
||||
char* res = abi::__cxa_demangle(name, nullptr, nullptr, &status);
|
||||
if (res)
|
||||
{
|
||||
std::string demangled = res;
|
||||
free(res);
|
||||
return demangled;
|
||||
}
|
||||
return "<unknown>";
|
||||
#else
|
||||
return name;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
struct type_name;
|
||||
|
||||
template <>
|
||||
struct type_name<>
|
||||
{
|
||||
static std::string str() { return "void"; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct type_name<T>
|
||||
{
|
||||
static std::string str() { return demangle(typeid(T).name()); }
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct type_name<T, Args...>
|
||||
{
|
||||
static std::string str() { return type_name<T>::str() + "," + type_name<Args...>::str(); }
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
constexpr int perlbind_version_major = 1;
|
||||
constexpr int perlbind_version_minor = 0;
|
||||
constexpr int perlbind_version_patch = 0;
|
||||
|
||||
constexpr int perlbind_version()
|
||||
{
|
||||
return perlbind_version_major * 10000 + perlbind_version_minor * 100 + perlbind_version_patch;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <perlbind/perlbind.h>
|
||||
|
||||
namespace perlbind { namespace detail {
|
||||
|
||||
extern "C" int gc(pTHX_ SV* sv, MAGIC* mg)
|
||||
{
|
||||
auto pfunc = INT2PTR(perlbind::detail::function_base*, SvIV(sv));
|
||||
delete pfunc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const MGVTBL function_base::mgvtbl = { 0, 0, 0, 0, gc, 0, 0, 0 };
|
||||
|
||||
} // namespace detail
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <perlbind/perlbind.h>
|
||||
#include <perlbind/iterator.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
hash::hash(scalar ref)
|
||||
: type_base(ref.my_perl)
|
||||
{
|
||||
if (!ref.is_hash_ref())
|
||||
throw std::runtime_error("cannot construct hash from non-hash reference");
|
||||
|
||||
reset(reinterpret_cast<HV*>(SvREFCNT_inc(*ref)));
|
||||
}
|
||||
|
||||
hash::hash(scalar_proxy proxy)
|
||||
: hash(scalar(SvREFCNT_inc(proxy.sv())))
|
||||
{}
|
||||
|
||||
scalar hash::at(const char* key)
|
||||
{
|
||||
return at(key, strlen(key));
|
||||
}
|
||||
|
||||
scalar hash::at(const std::string& key)
|
||||
{
|
||||
return at(key.c_str(), key.size());
|
||||
}
|
||||
|
||||
scalar hash::at(const char* key, size_t size)
|
||||
{
|
||||
SV** sv = hv_fetch(m_hv, key, static_cast<I32>(size), 1);
|
||||
return SvREFCNT_inc(*sv);
|
||||
}
|
||||
|
||||
void hash::insert(const char* key, scalar value)
|
||||
{
|
||||
insert(key, strlen(key), value);
|
||||
}
|
||||
|
||||
void hash::insert(const std::string& key, scalar value)
|
||||
{
|
||||
insert(key.c_str(), key.size(), value);
|
||||
}
|
||||
|
||||
scalar_proxy hash::operator[](const std::string& key)
|
||||
{
|
||||
return scalar_proxy(my_perl, at(key.c_str(), key.size()));
|
||||
}
|
||||
|
||||
hash::iterator hash::begin() const noexcept
|
||||
{
|
||||
hv_iterinit(m_hv);
|
||||
return { my_perl, m_hv, hv_iternext(m_hv) };
|
||||
}
|
||||
|
||||
hash::iterator hash::end() const noexcept
|
||||
{
|
||||
return { my_perl, m_hv, nullptr };
|
||||
}
|
||||
|
||||
hash::iterator hash::find(const char* key)
|
||||
{
|
||||
return find(key, static_cast<I32>(strlen(key)));
|
||||
}
|
||||
|
||||
hash::iterator hash::find(const std::string& key)
|
||||
{
|
||||
return find(key.c_str(), static_cast<I32>(key.size()));
|
||||
}
|
||||
|
||||
hash::iterator hash::find(const char* key, size_t size)
|
||||
{
|
||||
// key sv made mortal with SVs_TEMP flag
|
||||
SV* keysv = newSVpvn_flags(key, static_cast<I32>(size), SVs_TEMP);
|
||||
HE* he = hv_fetch_ent(m_hv, keysv, 0, 0);
|
||||
return { my_perl, m_hv, he };
|
||||
}
|
||||
|
||||
void hash::insert(const char* key, size_t size, scalar value)
|
||||
{
|
||||
if (!hv_store(m_hv, key, static_cast<I32>(size), SvREFCNT_inc(value), 0))
|
||||
{
|
||||
SvREFCNT_dec(value);
|
||||
}
|
||||
}
|
||||
|
||||
HV* hash::copy_hash(HV* other) noexcept
|
||||
{
|
||||
HV* hv = newHV();
|
||||
|
||||
hv_iterinit(other);
|
||||
while (HE* entry = hv_iternext(other))
|
||||
{
|
||||
size_t key_size;
|
||||
auto key = HePV(entry, key_size);
|
||||
auto value = newSVsv(HeVAL(entry));
|
||||
if (!hv_store(hv, key, static_cast<I32>(key_size), value, HeHASH(entry)))
|
||||
{
|
||||
SvREFCNT_dec(value);
|
||||
}
|
||||
}
|
||||
|
||||
return hv;
|
||||
}
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,98 @@
|
||||
#include <perlbind/perlbind.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
EXTERN_C
|
||||
{
|
||||
void boot_DynaLoader(pTHX_ CV* cv);
|
||||
static void xs_init(pTHX)
|
||||
{
|
||||
newXS(const_cast<char*>("DynaLoader::boot_DynaLoader"), boot_DynaLoader, const_cast<char*>(__FILE__));
|
||||
}
|
||||
}
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
interpreter::interpreter()
|
||||
: m_is_owner(true)
|
||||
{
|
||||
const char* argv[] = { "", "-ew", "0", nullptr };
|
||||
constexpr int argc = (sizeof(argv) / sizeof(*argv)) - 1;
|
||||
init(argc, argv);
|
||||
}
|
||||
|
||||
interpreter::interpreter(int argc, const char** argv)
|
||||
: m_is_owner(true)
|
||||
{
|
||||
init(argc, argv);
|
||||
}
|
||||
|
||||
void interpreter::init(int argc, const char** argv)
|
||||
{
|
||||
char** argvs = const_cast<char**>(argv);
|
||||
char** env = { nullptr };
|
||||
|
||||
// PERL_SYS_INIT3 and PERL_SYS_TERM should only be called once per program
|
||||
PERL_SYS_INIT3(&argc, &argvs, &env);
|
||||
|
||||
my_perl = perl_alloc();
|
||||
PERL_SET_CONTEXT(my_perl);
|
||||
PL_perl_destruct_level = 1;
|
||||
perl_construct(my_perl);
|
||||
perl_parse(my_perl, xs_init, argc, argvs, nullptr);
|
||||
|
||||
perl_run(my_perl);
|
||||
}
|
||||
|
||||
interpreter::~interpreter()
|
||||
{
|
||||
if (m_is_owner)
|
||||
{
|
||||
PL_perl_destruct_level = 1;
|
||||
perl_destruct(my_perl);
|
||||
perl_free(my_perl);
|
||||
|
||||
PERL_SYS_TERM();
|
||||
}
|
||||
}
|
||||
|
||||
void interpreter::load_script(std::string packagename, std::string filename)
|
||||
{
|
||||
struct stat st{};
|
||||
if (stat(filename.c_str(), &st) != 0)
|
||||
{
|
||||
throw std::runtime_error("Unable to read perl file '" + filename + "'");
|
||||
}
|
||||
|
||||
std::ifstream ifs(filename);
|
||||
std::stringstream buffer;
|
||||
buffer << "package " << packagename << "; " << ifs.rdbuf();
|
||||
|
||||
try
|
||||
{
|
||||
eval(buffer.str().c_str());
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
throw std::runtime_error("Error loading script '" + filename + "':\n " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void interpreter::eval(const char* str)
|
||||
{
|
||||
SV* sv = eval_pv(str, 0);
|
||||
if (sv == &PL_sv_undef)
|
||||
{
|
||||
SV* err = get_sv("@", 0);
|
||||
if (err && err->sv_u.svu_pv[0])
|
||||
{
|
||||
throw std::runtime_error(err->sv_u.svu_pv);
|
||||
}
|
||||
|
||||
throw std::runtime_error("unknown error in eval()");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <perlbind/perlbind.h>
|
||||
|
||||
namespace perlbind {
|
||||
|
||||
namespace detail {
|
||||
extern "C" void xsub(PerlInterpreter* my_perl, CV* cv);
|
||||
} // namespace detail
|
||||
|
||||
void package::add_impl(const char* name, detail::function_base* function)
|
||||
{
|
||||
std::string export_name = m_name + "::" + name;
|
||||
|
||||
// the sv is assigned a magic metamethod table to delete the function
|
||||
// object when perl frees the sv
|
||||
SV* sv = newSViv(PTR2IV(function));
|
||||
sv_magicext(sv, nullptr, PERL_MAGIC_ext, &detail::function_base::mgvtbl, nullptr, 0);
|
||||
|
||||
CV* cv = get_cv(export_name.c_str(), 0);
|
||||
if (!cv)
|
||||
{
|
||||
cv = newXS(export_name.c_str(), &detail::xsub, __FILE__);
|
||||
CvXSUBANY(cv).any_ptr = function;
|
||||
}
|
||||
else // function exists, remove target to search overloads when called
|
||||
{
|
||||
CvXSUBANY(cv).any_ptr = nullptr;
|
||||
}
|
||||
|
||||
// create an array with same name to store overloads in the CV's GV
|
||||
AV* av = GvAV(CvGV(cv));
|
||||
if (!av)
|
||||
{
|
||||
av = get_av(export_name.c_str(), GV_ADD);
|
||||
}
|
||||
|
||||
array overloads = reinterpret_cast<AV*>(SvREFCNT_inc(av));
|
||||
overloads.push_back(sv); // giving only ref to GV array
|
||||
}
|
||||
|
||||
extern "C" void detail::xsub(PerlInterpreter* my_perl, CV* cv)
|
||||
{
|
||||
// croak does not unwind so inner calls throw exceptions to prevent leaks
|
||||
try
|
||||
{
|
||||
detail::xsub_stack stack(my_perl, cv);
|
||||
|
||||
auto target = static_cast<detail::function_base*>(CvXSUBANY(cv).any_ptr);
|
||||
if (target)
|
||||
{
|
||||
return target->call(stack);
|
||||
}
|
||||
|
||||
// find first compatible overload
|
||||
AV* av = GvAV(CvGV(cv));
|
||||
|
||||
array functions = reinterpret_cast<AV*>(SvREFCNT_inc(av));
|
||||
for (const auto& function : functions)
|
||||
{
|
||||
auto func = INT2PTR(detail::function_base*, SvIV(function.sv()));
|
||||
if (func->is_compatible(stack))
|
||||
{
|
||||
return func->call(stack);
|
||||
}
|
||||
}
|
||||
|
||||
SV* err = newSVpvf("no overload of '%s' matched the %d argument(s):\n (%s)\ncandidates:\n ",
|
||||
stack.name().c_str(), stack.size(), stack.types().c_str());
|
||||
|
||||
for (const auto& function : functions)
|
||||
{
|
||||
auto func = INT2PTR(detail::function_base*, SvIV(function.sv()));
|
||||
Perl_sv_catpvf(aTHX_ err, "%s\n ", func->get_signature().c_str());
|
||||
}
|
||||
|
||||
err = sv_2mortal(err);
|
||||
throw std::runtime_error(SvPV_nolen(err));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Perl_croak(aTHX_ "%s", e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Perl_croak(aTHX_ "unhandled exception");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace perlbind
|
||||
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="perlbind::scalar">
|
||||
<AlternativeType Name="perlbind::reference" />
|
||||
<DisplayString>{{ m_sv={(void*)m_sv} refcnt={m_sv->sv_refcnt,d} type={(svtype)(m_sv->sv_flags & 0xff),d} }}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>m_sv</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="perlbind::array">
|
||||
<DisplayString Condition="m_av != nullptr">{{ size={(m_av->sv_any)->xav_fill + 1,d} refcnt={m_av->sv_refcnt,d} }</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>m_av</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="perlbind::hash">
|
||||
<DisplayString Condition="m_hv != nullptr">{{ size={(m_hv->sv_any)->xhv_keys,d} refcnt={m_hv->sv_refcnt,d} }}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>m_hv</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="sv">
|
||||
<AlternativeType Name="cv" />
|
||||
<DisplayString>{{ refcnt={sv_refcnt,d} type={(svtype)(sv_flags & 0xff),d} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[refcnt]">sv_refcnt,d</Item>
|
||||
<Item Name="[type]">(svtype)(sv_flags & 0xff),d</Item>
|
||||
<Item Name="[reference]" Condition="(sv_flags & 0x00000800)">sv_u.svu_rv</Item>
|
||||
<!-- SVt_PVAV -->
|
||||
<Item Name="[array]" Condition="((svtype)(sv_flags & 0xff)) == 11">(av*)this</Item>
|
||||
<!-- SVt_PVHV -->
|
||||
<Item Name="[hash]" Condition="((svtype)(sv_flags & 0xff)) == 12">(hv*)this</Item>
|
||||
<!-- SVt_PVGV -->
|
||||
<Item Name="[glob]" Condition="((svtype)(sv_flags & 0xff)) == 9">(gv*)this</Item>
|
||||
<!-- SVt_PVMG -->
|
||||
<Item Name="[magic]" Condition="((svtype)(sv_flags & 0xff)) == 7">((XPVMG*)(sv_any))</Item>
|
||||
<!--<ExpandedItem>sv_u</ExpandedItem>-->
|
||||
<Item Name="svu_pv">sv_u.svu_pv,na</Item>
|
||||
<Item Name="svu_iv">sv_u.svu_iv,i</Item>
|
||||
<Item Name="svu_uv">sv_u.svu_uv</Item>
|
||||
<Item Name="svu_nv">sv_u.svu_nv,f</Item>
|
||||
<Item Name="svu_rv">sv_u.svu_rv</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="av">
|
||||
<!--
|
||||
These might be dependent on perl version
|
||||
#define AvARRAY(av) ((av)->sv_u.svu_array)
|
||||
#define AvALLOC(av) ((XPVAV*) SvANY(av))->xav_alloc
|
||||
#define AvMAX(av) ((XPVAV*) SvANY(av))->xav_max
|
||||
#define AvFILLp(av) ((XPVAV*) SvANY(av))->xav_fill
|
||||
-->
|
||||
<DisplayString>{{ size={(sv_any)->xav_fill + 1,d} refcnt={sv_refcnt,d} type={(svtype)(sv_flags & 0xff),d} }</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[refcnt]">sv_refcnt,d</Item>
|
||||
<Item Name="[size]">(sv_any)->xav_fill + 1</Item>
|
||||
<Item Name="[capacity]">(sv_any)->xav_max</Item>
|
||||
<ArrayItems>
|
||||
<Size>(sv_any)->xav_fill + 1</Size>
|
||||
<ValuePointer>(sv_u).svu_array</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="hv">
|
||||
<!--
|
||||
These might be dependent on perl version
|
||||
SvANY(hv): (m_hv->sv_any)
|
||||
HvMAX(hv): ((m_hv->sv_any)->xhv_max
|
||||
HvARRAY(hv): ((m_hv->sv_u).svu_hash
|
||||
HvAUX(hv): (xpvhv_aux*)&(((m_hv->sv_u)->svu_hash)[((m_hv->sv_any)->xhv_max + 1]
|
||||
-->
|
||||
<DisplayString>{{ size={(sv_any)->xhv_keys,d} refcnt={sv_refcnt,d} type={(svtype)(sv_flags & 0xff),d} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[refcnt]">sv_refcnt,d</Item>
|
||||
<Item Name="[size]">(sv_any)->xhv_keys</Item>
|
||||
<Item Name="[capacity]">(sv_any)->xhv_max</Item>
|
||||
<CustomListItems MaxItemsPerView="5000">
|
||||
<Variable Name="index" InitialValue="0"/>
|
||||
<Variable Name="bucket_inc" InitialValue="0"/>
|
||||
<Variable Name="max_index" InitialValue="(sv_any)->xhv_max"/>
|
||||
<Variable Name="bucket_array" InitialValue="(sv_u).svu_hash"/>
|
||||
<Variable Name="entry" InitialValue="(sv_u).svu_hash[0]"/>
|
||||
|
||||
<Loop>
|
||||
<If Condition="entry == nullptr">
|
||||
<Exec>index++</Exec>
|
||||
<Exec>bucket_inc = __findnonnull(bucket_array + index, max_index - index)</Exec>
|
||||
<Break Condition="bucket_inc == -1" />
|
||||
<Exec>index += bucket_inc</Exec>
|
||||
<Exec>entry = bucket_array[index]</Exec>
|
||||
</If>
|
||||
<Item Name="[{ (entry->hent_hek)->hek_key,na }]">(entry->he_valu).hent_val</Item>
|
||||
<Exec>entry = entry->hent_next</Exec>
|
||||
</Loop>
|
||||
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="gv">
|
||||
<DisplayString>{{ refcnt={sv_refcnt,d} type={(svtype)(sv_flags & 0xff),d} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[refcnt]">sv_refcnt,d</Item>
|
||||
<Item Name="[type]">(svtype)(sv_flags & 0xff),d</Item>
|
||||
<Item Name="[sv]" Condition="(sv_u.svu_gp)->gp_sv != nullptr">(sv_u.svu_gp)->gp_sv</Item>
|
||||
<Item Name="[cv]" Condition="(sv_u.svu_gp)->gp_cv != nullptr">(sv_u.svu_gp)->gp_cv</Item>
|
||||
<Item Name="[array]" Condition="(sv_u.svu_gp)->gp_av != nullptr">(sv_u.svu_gp)->gp_av</Item>
|
||||
<Item Name="[hash]" Condition="(sv_u.svu_gp)->gp_hv != nullptr">(sv_u.svu_gp)->gp_hv</Item>
|
||||
<Item Name="svu_gp">(sv_u.svu_gp)</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
@@ -1,18 +1,18 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||
|
||||
SET(qserv_sources
|
||||
database.cpp
|
||||
lfguild.cpp
|
||||
queryserv.cpp
|
||||
queryservconfig.cpp
|
||||
worldserver.cpp
|
||||
database.cpp
|
||||
lfguild.cpp
|
||||
queryserv.cpp
|
||||
queryservconfig.cpp
|
||||
worldserver.cpp
|
||||
)
|
||||
|
||||
SET(qserv_headers
|
||||
database.h
|
||||
lfguild.h
|
||||
queryservconfig.h
|
||||
worldserver.h
|
||||
database.h
|
||||
lfguild.h
|
||||
queryservconfig.h
|
||||
worldserver.h
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(queryserv ${qserv_sources} ${qserv_headers})
|
||||
|
||||
+15
-15
@@ -12,25 +12,25 @@ extern Database database;
|
||||
|
||||
PlayerLookingForGuild::PlayerLookingForGuild(char *Name, char *Comments, uint32 Level, uint32 Class, uint32 AACount, uint32 Timezone, uint32 TimePosted)
|
||||
{
|
||||
this->Name = Name;
|
||||
this->Comments = Comments;
|
||||
this->Level = Level;
|
||||
this->Class = Class;
|
||||
this->AACount = AACount;
|
||||
this->TimeZone = Timezone;
|
||||
this->TimePosted = TimePosted;
|
||||
Name = Name;
|
||||
Comments = Comments;
|
||||
Level = Level;
|
||||
Class = Class;
|
||||
AACount = AACount;
|
||||
TimeZone = Timezone;
|
||||
TimePosted = TimePosted;
|
||||
}
|
||||
|
||||
GuildLookingForPlayers::GuildLookingForPlayers(char *Name, char *Comments, uint32 FromLevel, uint32 ToLevel, uint32 Classes, uint32 AACount, uint32 Timezone, uint32 TimePosted)
|
||||
{
|
||||
this->Name = Name;
|
||||
this->Comments = Comments;
|
||||
this->FromLevel = FromLevel;
|
||||
this->ToLevel = ToLevel;
|
||||
this->Classes = Classes;
|
||||
this->AACount = AACount;
|
||||
this->TimeZone = Timezone;
|
||||
this->TimePosted = TimePosted;
|
||||
Name = Name;
|
||||
Comments = Comments;
|
||||
FromLevel = FromLevel;
|
||||
ToLevel = ToLevel;
|
||||
Classes = Classes;
|
||||
AACount = AACount;
|
||||
TimeZone = Timezone;
|
||||
TimePosted = TimePosted;
|
||||
}
|
||||
|
||||
bool LFGuildManager::LoadDatabase()
|
||||
|
||||
+21
-14
@@ -24,6 +24,7 @@
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/platform.h"
|
||||
#include "../common/crash.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/event/event_loop.h"
|
||||
#include "../common/timer.h"
|
||||
#include "database.h"
|
||||
@@ -32,21 +33,24 @@
|
||||
#include "worldserver.h"
|
||||
#include <list>
|
||||
#include <signal.h>
|
||||
#include <thread>
|
||||
|
||||
volatile bool RunLoops = true;
|
||||
|
||||
Database database;
|
||||
LFGuildManager lfguildmanager;
|
||||
std::string WorldShortName;
|
||||
Database database;
|
||||
LFGuildManager lfguildmanager;
|
||||
std::string WorldShortName;
|
||||
const queryservconfig *Config;
|
||||
WorldServer *worldserver = 0;
|
||||
EQEmuLogSys LogSys;
|
||||
WorldServer *worldserver = 0;
|
||||
EQEmuLogSys LogSys;
|
||||
|
||||
void CatchSignal(int sig_num) {
|
||||
void CatchSignal(int sig_num)
|
||||
{
|
||||
RunLoops = false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main()
|
||||
{
|
||||
RegisterExecutablePlatform(ExePlatformQueryServ);
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
@@ -58,7 +62,7 @@ int main() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Config = queryservconfig::get();
|
||||
Config = queryservconfig::get();
|
||||
WorldShortName = Config->ShortName;
|
||||
|
||||
LogInfo("Connecting to MySQL");
|
||||
@@ -69,7 +73,8 @@ int main() {
|
||||
Config->QSDatabaseUsername.c_str(),
|
||||
Config->QSDatabasePassword.c_str(),
|
||||
Config->QSDatabaseDB.c_str(),
|
||||
Config->QSDatabasePort)) {
|
||||
Config->QSDatabasePort
|
||||
)) {
|
||||
LogInfo("Cannot continue without a database connection");
|
||||
return 1;
|
||||
}
|
||||
@@ -78,11 +83,11 @@ int main() {
|
||||
->LoadLogDatabaseSettings()
|
||||
->StartFileLogs();
|
||||
|
||||
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
|
||||
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
|
||||
LogInfo("Could not set signal handler");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
|
||||
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
|
||||
LogInfo("Could not set signal handler");
|
||||
return 1;
|
||||
}
|
||||
@@ -94,10 +99,11 @@ int main() {
|
||||
/* Load Looking For Guild Manager */
|
||||
lfguildmanager.LoadDatabase();
|
||||
|
||||
while(RunLoops) {
|
||||
while (RunLoops) {
|
||||
Timer::SetCurrentTime();
|
||||
if(LFGuildExpireTimer.Check())
|
||||
if (LFGuildExpireTimer.Check()) {
|
||||
lfguildmanager.ExpireEntries();
|
||||
}
|
||||
|
||||
EQ::EventLoop::Get().Process();
|
||||
Sleep(5);
|
||||
@@ -105,7 +111,8 @@ int main() {
|
||||
LogSys.CloseFileLogs();
|
||||
}
|
||||
|
||||
void UpdateWindowTitle(char* iNewTitle) {
|
||||
void UpdateWindowTitle(char *iNewTitle)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
char tmp[500];
|
||||
if (iNewTitle) {
|
||||
|
||||
+104
-98
@@ -37,10 +37,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern WorldServer worldserver;
|
||||
extern const queryservconfig *Config;
|
||||
extern Database database;
|
||||
extern LFGuildManager lfguildmanager;
|
||||
extern Database database;
|
||||
extern LFGuildManager lfguildmanager;
|
||||
|
||||
WorldServer::WorldServer()
|
||||
{
|
||||
@@ -52,7 +52,13 @@ WorldServer::~WorldServer()
|
||||
|
||||
void WorldServer::Connect()
|
||||
{
|
||||
m_connection = std::make_unique<EQ::Net::ServertalkClient>(Config->WorldIP, Config->WorldTCPPort, false, "QueryServ", Config->SharedKey);
|
||||
m_connection = std::make_unique<EQ::Net::ServertalkClient>(
|
||||
Config->WorldIP,
|
||||
Config->WorldTCPPort,
|
||||
false,
|
||||
"QueryServ",
|
||||
Config->SharedKey
|
||||
);
|
||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
@@ -80,109 +86,109 @@ bool WorldServer::Connected() const
|
||||
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
{
|
||||
switch (opcode) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_KeepAlive: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_Speech: {
|
||||
Server_Speech_Struct *SSS = (Server_Speech_Struct*)p.Data();
|
||||
std::string tmp1 = SSS->from;
|
||||
std::string tmp2 = SSS->to;
|
||||
database.AddSpeech(tmp1.c_str(), tmp2.c_str(), SSS->message, SSS->minstatus, SSS->guilddbid, SSS->type);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogTrades: {
|
||||
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct*)p.Data();
|
||||
database.LogPlayerTrade(QS, QS->_detail_count);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerDropItem: {
|
||||
QSPlayerDropItem_Struct *QS = (QSPlayerDropItem_Struct *) p.Data();
|
||||
database.LogPlayerDropItem(QS);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogHandins: {
|
||||
QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)p.Data();
|
||||
database.LogPlayerHandin(QS, QS->_detail_count);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogNPCKills: {
|
||||
QSPlayerLogNPCKill_Struct *QS = (QSPlayerLogNPCKill_Struct*)p.Data();
|
||||
uint32 Members = (uint32)(p.Length() - sizeof(QSPlayerLogNPCKill_Struct));
|
||||
if (Members > 0) Members = Members / sizeof(QSPlayerLogNPCKillsPlayers_Struct);
|
||||
database.LogPlayerNPCKill(QS, Members);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogDeletes: {
|
||||
QSPlayerLogDelete_Struct *QS = (QSPlayerLogDelete_Struct*)p.Data();
|
||||
uint32 Items = QS->char_count;
|
||||
database.LogPlayerDelete(QS, Items);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogMoves: {
|
||||
QSPlayerLogMove_Struct *QS = (QSPlayerLogMove_Struct*)p.Data();
|
||||
uint32 Items = QS->char_count;
|
||||
database.LogPlayerMove(QS, Items);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogMerchantTransactions: {
|
||||
QSMerchantLogTransaction_Struct *QS = (QSMerchantLogTransaction_Struct*)p.Data();
|
||||
uint32 Items = QS->char_count + QS->merchant_count;
|
||||
database.LogMerchantTransaction(QS, Items);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QueryServGeneric: {
|
||||
/*
|
||||
The purpose of ServerOP_QueryServerGeneric is so that we don't have to add code to world just to relay packets
|
||||
each time we add functionality to queryserv.
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_KeepAlive: {
|
||||
break;
|
||||
}
|
||||
case ServerOP_Speech: {
|
||||
Server_Speech_Struct *SSS = (Server_Speech_Struct *) p.Data();
|
||||
std::string tmp1 = SSS->from;
|
||||
std::string tmp2 = SSS->to;
|
||||
database.AddSpeech(tmp1.c_str(), tmp2.c_str(), SSS->message, SSS->minstatus, SSS->guilddbid, SSS->type);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogTrades: {
|
||||
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct *) p.Data();
|
||||
database.LogPlayerTrade(QS, QS->_detail_count);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerDropItem: {
|
||||
QSPlayerDropItem_Struct *QS = (QSPlayerDropItem_Struct *) p.Data();
|
||||
database.LogPlayerDropItem(QS);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogHandins: {
|
||||
QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct *) p.Data();
|
||||
database.LogPlayerHandin(QS, QS->_detail_count);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogNPCKills: {
|
||||
QSPlayerLogNPCKill_Struct *QS = (QSPlayerLogNPCKill_Struct *) p.Data();
|
||||
uint32 Members = (uint32) (p.Length() - sizeof(QSPlayerLogNPCKill_Struct));
|
||||
if (Members > 0) { Members = Members / sizeof(QSPlayerLogNPCKillsPlayers_Struct); }
|
||||
database.LogPlayerNPCKill(QS, Members);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogDeletes: {
|
||||
QSPlayerLogDelete_Struct *QS = (QSPlayerLogDelete_Struct *) p.Data();
|
||||
uint32 Items = QS->char_count;
|
||||
database.LogPlayerDelete(QS, Items);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogMoves: {
|
||||
QSPlayerLogMove_Struct *QS = (QSPlayerLogMove_Struct *) p.Data();
|
||||
uint32 Items = QS->char_count;
|
||||
database.LogPlayerMove(QS, Items);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogMerchantTransactions: {
|
||||
QSMerchantLogTransaction_Struct *QS = (QSMerchantLogTransaction_Struct *) p.Data();
|
||||
uint32 Items = QS->char_count + QS->merchant_count;
|
||||
database.LogMerchantTransaction(QS, Items);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QueryServGeneric: {
|
||||
/*
|
||||
The purpose of ServerOP_QueryServerGeneric is so that we don't have to add code to world just to relay packets
|
||||
each time we add functionality to queryserv.
|
||||
|
||||
A ServerOP_QueryServGeneric packet has the following format:
|
||||
A ServerOP_QueryServGeneric packet has the following format:
|
||||
|
||||
uint32 SourceZoneID
|
||||
uint32 SourceInstanceID
|
||||
char OriginatingCharacterName[0]
|
||||
- Null terminated name of the character this packet came from. This could be just
|
||||
- an empty string if it has no meaning in the context of a particular packet.
|
||||
uint32 Type
|
||||
uint32 SourceZoneID
|
||||
uint32 SourceInstanceID
|
||||
char OriginatingCharacterName[0]
|
||||
- Null terminated name of the character this packet came from. This could be just
|
||||
- an empty string if it has no meaning in the context of a particular packet.
|
||||
uint32 Type
|
||||
|
||||
The 'Type' field is a 'sub-opcode'. A value of 0 is used for the LFGuild packets. The next feature to be added
|
||||
to queryserv would use 1, etc.
|
||||
The 'Type' field is a 'sub-opcode'. A value of 0 is used for the LFGuild packets. The next feature to be added
|
||||
to queryserv would use 1, etc.
|
||||
|
||||
Obviously, any fields in the packet following the 'Type' will be unique to the particular type of packet. The
|
||||
'Generic' in the name of this ServerOP code relates to the four header fields.
|
||||
*/
|
||||
Obviously, any fields in the packet following the 'Type' will be unique to the particular type of packet. The
|
||||
'Generic' in the name of this ServerOP code relates to the four header fields.
|
||||
*/
|
||||
|
||||
auto from = p.GetCString(8);
|
||||
uint32 Type = p.GetUInt32(8 + from.length() + 1);
|
||||
auto from = p.GetCString(8);
|
||||
uint32 Type = p.GetUInt32(8 + from.length() + 1);
|
||||
|
||||
switch (Type) {
|
||||
case QSG_LFGuild: {
|
||||
switch (Type) {
|
||||
case QSG_LFGuild: {
|
||||
ServerPacket pack;
|
||||
pack.pBuffer = (uchar *) p.Data();
|
||||
pack.opcode = opcode;
|
||||
pack.size = (uint32) p.Length();
|
||||
lfguildmanager.HandlePacket(&pack);
|
||||
pack.pBuffer = nullptr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogInfo("Received unhandled ServerOP_QueryServGeneric", Type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSSendQuery: {
|
||||
/* Process all packets here */
|
||||
ServerPacket pack;
|
||||
pack.pBuffer = (uchar*)p.Data();
|
||||
pack.opcode = opcode;
|
||||
pack.size = (uint32)p.Length();
|
||||
lfguildmanager.HandlePacket(&pack);
|
||||
pack.pBuffer = (uchar *) p.Data();
|
||||
pack.opcode = opcode;
|
||||
pack.size = (uint32) p.Length();
|
||||
|
||||
database.GeneralQueryReceive(&pack);
|
||||
pack.pBuffer = nullptr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogInfo("Received unhandled ServerOP_QueryServGeneric", Type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSSendQuery: {
|
||||
/* Process all packets here */
|
||||
ServerPacket pack;
|
||||
pack.pBuffer = (uchar*)p.Data();
|
||||
pack.opcode = opcode;
|
||||
pack.size = (uint32)p.Length();
|
||||
|
||||
database.GeneralQueryReceive(&pack);
|
||||
pack.pBuffer = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-13
@@ -18,24 +18,25 @@
|
||||
#ifndef WORLDSERVER_H
|
||||
#define WORLDSERVER_H
|
||||
|
||||
#include <mutex>
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
|
||||
class WorldServer
|
||||
{
|
||||
public:
|
||||
WorldServer();
|
||||
~WorldServer();
|
||||
class WorldServer {
|
||||
public:
|
||||
WorldServer();
|
||||
~WorldServer();
|
||||
|
||||
void Connect();
|
||||
bool SendPacket(ServerPacket* pack);
|
||||
std::string GetIP() const;
|
||||
uint16 GetPort() const;
|
||||
bool Connected() const;
|
||||
void Connect();
|
||||
bool SendPacket(ServerPacket *pack);
|
||||
std::string GetIP() const;
|
||||
uint16 GetPort() const;
|
||||
bool Connected() const;
|
||||
|
||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
private:
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
|
||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||
private:
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
+52
-21
@@ -32,15 +32,19 @@
|
||||
#include "worldserver.h"
|
||||
#include <list>
|
||||
#include <signal.h>
|
||||
#include <csignal>
|
||||
#include <thread>
|
||||
|
||||
#include "../common/net/tcp_server.h"
|
||||
#include "../common/net/servertalk_client_connection.h"
|
||||
#include "../common/discord_manager.h"
|
||||
|
||||
ChatChannelList *ChannelList;
|
||||
Clientlist *g_Clientlist;
|
||||
EQEmuLogSys LogSys;
|
||||
Database database;
|
||||
WorldServer *worldserver = nullptr;
|
||||
DiscordManager discord_manager;
|
||||
|
||||
const ucsconfig *Config;
|
||||
|
||||
@@ -49,19 +53,49 @@ std::string WorldShortName;
|
||||
uint32 ChatMessagesSent = 0;
|
||||
uint32 MailMessagesSent = 0;
|
||||
|
||||
volatile bool RunLoops = true;
|
||||
|
||||
void CatchSignal(int sig_num) {
|
||||
|
||||
RunLoops = false;
|
||||
}
|
||||
|
||||
std::string GetMailPrefix() {
|
||||
|
||||
return "SOE.EQ." + WorldShortName + ".";
|
||||
|
||||
}
|
||||
|
||||
void crash_func() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
|
||||
int* p=0;
|
||||
*p=0;
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
LogInfo("Shutting down...");
|
||||
ChannelList->RemoveAllChannels();
|
||||
g_Clientlist->CloseAllConnections();
|
||||
LogSys.CloseFileLogs();
|
||||
}
|
||||
|
||||
int caught_loop = 0;
|
||||
void CatchSignal(int sig_num) {
|
||||
LogInfo("Caught signal [{}]", sig_num);
|
||||
|
||||
EQ::EventLoop::Get().Shutdown();
|
||||
|
||||
caught_loop++;
|
||||
// when signal handler is incapable of exiting properly
|
||||
if (caught_loop > 1) {
|
||||
LogInfo("In a signal handler loop and process is incapable of exiting properly, forcefully cleaning up");
|
||||
ChannelList->RemoveAllChannels();
|
||||
g_Clientlist->CloseAllConnections();
|
||||
LogSys.CloseFileLogs();
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void DiscordQueueListener() {
|
||||
while (caught_loop == 0) {
|
||||
discord_manager.ProcessMessageQueue();
|
||||
Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
RegisterExecutablePlatform(ExePlatformUCS);
|
||||
LogSys.LoadLogSettingsDefaults();
|
||||
@@ -134,17 +168,19 @@ int main() {
|
||||
|
||||
database.LoadChatChannels();
|
||||
|
||||
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
|
||||
LogInfo("Could not set signal handler");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
|
||||
LogInfo("Could not set signal handler");
|
||||
return 1;
|
||||
}
|
||||
std::signal(SIGINT, CatchSignal);
|
||||
std::signal(SIGTERM, CatchSignal);
|
||||
std::signal(SIGKILL, CatchSignal);
|
||||
std::signal(SIGSEGV, CatchSignal);
|
||||
|
||||
std::thread(DiscordQueueListener).detach();
|
||||
|
||||
worldserver = new WorldServer;
|
||||
|
||||
// uncomment to simulate timed crash for catching SIGSEV
|
||||
// std::thread crash_test(crash_func);
|
||||
// crash_test.detach();
|
||||
|
||||
auto loop_fn = [&](EQ::Timer* t) {
|
||||
|
||||
Timer::SetCurrentTime();
|
||||
@@ -166,12 +202,7 @@ int main() {
|
||||
|
||||
EQ::EventLoop::Get().Run();
|
||||
|
||||
ChannelList->RemoveAllChannels();
|
||||
|
||||
g_Clientlist->CloseAllConnections();
|
||||
|
||||
LogSys.CloseFileLogs();
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void UpdateWindowTitle(char* iNewTitle) {
|
||||
|
||||
+15
-3
@@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "clientlist.h"
|
||||
#include "ucsconfig.h"
|
||||
#include "database.h"
|
||||
#include "../common/discord_manager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
@@ -35,10 +36,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern Clientlist *g_Clientlist;
|
||||
extern WorldServer worldserver;
|
||||
extern Clientlist *g_Clientlist;
|
||||
extern const ucsconfig *Config;
|
||||
extern Database database;
|
||||
extern Database database;
|
||||
extern DiscordManager discord_manager;
|
||||
|
||||
void ProcessMailTo(Client *c, std::string from, std::string subject, std::string message);
|
||||
|
||||
@@ -72,6 +74,16 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ServerOP_DiscordWebhookMessage: {
|
||||
auto *q = (DiscordWebhookMessage_Struct *) p.Data();
|
||||
|
||||
discord_manager.QueueWebhookMessage(
|
||||
q->webhook_id,
|
||||
q->message
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSMessage:
|
||||
{
|
||||
char *Buffer = (char *)pack->pBuffer;
|
||||
|
||||
@@ -8,40 +8,6 @@
|
||||
*
|
||||
]]
|
||||
|
||||
MonkACBonusWeight = RuleI.Get(Rule.MonkACBonusWeight);
|
||||
NPCACFactor = RuleR.Get(Rule.NPCACFactor);
|
||||
OldACSoftcapRules = RuleB.Get(Rule.OldACSoftcapRules);
|
||||
ClothACSoftcap = RuleI.Get(Rule.ClothACSoftcap);
|
||||
LeatherACSoftcap = RuleI.Get(Rule.LeatherACSoftcap);
|
||||
MonkACSoftcap = RuleI.Get(Rule.MonkACSoftcap);
|
||||
ChainACSoftcap = RuleI.Get(Rule.ChainACSoftcap);
|
||||
PlateACSoftcap = RuleI.Get(Rule.PlateACSoftcap);
|
||||
AAMitigationACFactor = RuleR.Get(Rule.AAMitigationACFactor);
|
||||
WarriorACSoftcapReturn = RuleR.Get(Rule.WarriorACSoftcapReturn);
|
||||
KnightACSoftcapReturn = RuleR.Get(Rule.KnightACSoftcapReturn);
|
||||
LowPlateChainACSoftcapReturn = RuleR.Get(Rule.LowPlateChainACSoftcapReturn);
|
||||
LowChainLeatherACSoftcapReturn = RuleR.Get(Rule.LowChainLeatherACSoftcapReturn);
|
||||
CasterACSoftcapReturn = RuleR.Get(Rule.CasterACSoftcapReturn);
|
||||
MiscACSoftcapReturn = RuleR.Get(Rule.MiscACSoftcapReturn);
|
||||
WarACSoftcapReturn = RuleR.Get(Rule.WarACSoftcapReturn);
|
||||
ClrRngMnkBrdACSoftcapReturn = RuleR.Get(Rule.ClrRngMnkBrdACSoftcapReturn);
|
||||
PalShdACSoftcapReturn = RuleR.Get(Rule.PalShdACSoftcapReturn);
|
||||
DruNecWizEncMagACSoftcapReturn = RuleR.Get(Rule.DruNecWizEncMagACSoftcapReturn);
|
||||
RogShmBstBerACSoftcapReturn = RuleR.Get(Rule.RogShmBstBerACSoftcapReturn);
|
||||
SoftcapFactor = RuleR.Get(Rule.SoftcapFactor);
|
||||
ACthac0Factor = RuleR.Get(Rule.ACthac0Factor);
|
||||
ACthac20Factor = RuleR.Get(Rule.ACthac20Factor);
|
||||
BaseHitChance = RuleR.Get(Rule.BaseHitChance);
|
||||
NPCBonusHitChance = RuleR.Get(Rule.NPCBonusHitChance);
|
||||
HitFalloffMinor = RuleR.Get(Rule.HitFalloffMinor);
|
||||
HitFalloffModerate = RuleR.Get(Rule.HitFalloffModerate);
|
||||
HitFalloffMajor = RuleR.Get(Rule.HitFalloffMajor);
|
||||
HitBonusPerLevel = RuleR.Get(Rule.HitBonusPerLevel);
|
||||
AgiHitFactor = RuleR.Get(Rule.AgiHitFactor);
|
||||
WeaponSkillFalloff = RuleR.Get(Rule.WeaponSkillFalloff);
|
||||
ArcheryHitPenalty = RuleR.Get(Rule.ArcheryHitPenalty);
|
||||
UseOldDamageIntervalRules = RuleB.Get(Rule.UseOldDamageIntervalRules);
|
||||
CriticalMessageRange = RuleI.Get(Rule.CriticalDamage);
|
||||
|
||||
--[[
|
||||
*
|
||||
@@ -51,6 +17,41 @@ CriticalMessageRange = RuleI.Get(Rule.CriticalDamage);
|
||||
*
|
||||
]]
|
||||
|
||||
MonkACBonusWeight = 15;
|
||||
NPCACFactor = 2.25;
|
||||
OldACSoftcapRules = false;
|
||||
ClothACSoftcap = 75;
|
||||
LeatherACSoftcap = 100;
|
||||
MonkACSoftcap = 120;
|
||||
ChainACSoftcap = 200;
|
||||
PlateACSoftcap = 300;
|
||||
AAMitigationACFactor = 3.0;
|
||||
WarriorACSoftcapReturn = 0.45;
|
||||
KnightACSoftcapReturn = 0.33;
|
||||
LowPlateChainACSoftcapReturn = 0.23;
|
||||
LowChainLeatherACSoftcapReturn = 0.17;
|
||||
CasterACSoftcapReturn = 0.06;
|
||||
MiscACSoftcapReturn = 0.3;
|
||||
WarACSoftcapReturn = 0.3448;
|
||||
ClrRngMnkBrdACSoftcapReturn = 0.3030;
|
||||
PalShdACSoftcapReturn = 0.3226;
|
||||
DruNecWizEncMagACSoftcapReturn = 0.2;
|
||||
RogShmBstBerACSoftcapReturn = 0.25;
|
||||
SoftcapFactor = 1.88;
|
||||
ACthac0Factor = 0.55;
|
||||
ACthac20Factor = 0.55;
|
||||
BaseHitChance = 69.0;
|
||||
NPCBonusHitChance = 26.0;
|
||||
HitFalloffMinor = 5.0;
|
||||
HitFalloffModerate = 7.0;
|
||||
HitFalloffMajor = 50.0;
|
||||
HitBonusPerLevel = 1.2;
|
||||
AgiHitFactor = 0.01;
|
||||
WeaponSkillFalloff = 0.33;
|
||||
ArcheryHitPenalty = 0.25;
|
||||
UseOldDamageIntervalRules = false;
|
||||
CriticalMessageRange = RuleI.Get(Rule.CriticalDamage);
|
||||
|
||||
MeleeBaseCritChance = 0.0;
|
||||
ClientBaseCritChance = 0.0;
|
||||
BerserkBaseCritChance = 6.0;
|
||||
@@ -851,7 +852,12 @@ function MobGetMeleeMitDmg(defender, attacker, damage, min_damage, mitigation_ra
|
||||
);
|
||||
|
||||
-- Changed from positive to negative per original
|
||||
damage = damage - (damage * (defender:GetSpellBonuses():MeleeMitigationEffect() + defender:GetItemBonuses():MeleeMitigationEffect() + defender:GetAABonuses():MeleeMitigationEffect()) / 100);
|
||||
local spell_based_mitigation = defender:GetSpellBonuses():MeleeMitigationEffect() * -1;
|
||||
local item_based_mitigation = defender:GetItemBonuses():MeleeMitigationEffect() * -1;
|
||||
local aa_based_mitigation = defender:GetAABonuses():MeleeMitigationEffect() * -1;
|
||||
|
||||
-- Changed from positive to negative per original
|
||||
damage = damage - (damage * (spell_based_mitigation + item_based_mitigation + aa_based_mitigation) / 100);
|
||||
|
||||
eq.log_combat(
|
||||
string.format("[%s] [Mob::GetMeleeMitDmg] Damage [%02f] SpellMit [%i] ItemMit [%i] AAMit [%i] Post All Mit Bonuses",
|
||||
|
||||
@@ -203,6 +203,7 @@ OP_DeleteSpell=0x3358
|
||||
OP_Surname=0x0423
|
||||
OP_ClearSurname=0x3fb0
|
||||
OP_FaceChange=0x5578
|
||||
OP_SetFace=0x1af3
|
||||
OP_SenseHeading=0x260a
|
||||
OP_Action=0x744c
|
||||
OP_ConsiderCorpse=0x5204
|
||||
|
||||
@@ -201,6 +201,7 @@ OP_DeleteSpell=0x0736 # C
|
||||
OP_Surname=0x7547 # C
|
||||
OP_ClearSurname=0x2edd # C
|
||||
OP_FaceChange=0x5658 # C
|
||||
OP_SetFace=0x210a
|
||||
OP_SenseHeading=0x3887 # C
|
||||
OP_Action=0x2c27 # C
|
||||
OP_ConsiderCorpse=0x37a7 # C
|
||||
|
||||
@@ -198,6 +198,7 @@ OP_DeleteSpell=0x6D7E #Xinu 02/20/09
|
||||
OP_Surname=0x683E #Xinu 02/21/09
|
||||
OP_ClearSurname=0x2613
|
||||
OP_FaceChange=0x482D #Trevius 01/16/09
|
||||
OP_SetFace=0x49dc
|
||||
OP_SenseHeading=0x1237 #Trevius 01/16/09
|
||||
OP_Action=0x5285 #Trevius 01/16/09
|
||||
OP_ConsiderCorpse=0x4CBB #Xinu 02/20/09
|
||||
|
||||
@@ -205,6 +205,7 @@ OP_DeleteSpell=0x0698 # C
|
||||
OP_Surname=0x44ae # C
|
||||
OP_ClearSurname=0x6705 # C
|
||||
OP_FaceChange=0x37a7 # C
|
||||
OP_SetFace=0x6cfa
|
||||
OP_SenseHeading=0x1b8a # C
|
||||
OP_Action=0x0f14 # C
|
||||
OP_ConsiderCorpse=0x0a18 # C
|
||||
|
||||
@@ -64,11 +64,10 @@ if [ ! -f ./install_variables.txt ]; then
|
||||
echo ""
|
||||
echo ""
|
||||
groupadd eqemu
|
||||
useradd -g eqemu -d $eqemu_server_directory eqemu
|
||||
useradd -g eqemu -m -d $eqemu_server_directory eqemu
|
||||
passwd eqemu
|
||||
|
||||
#::: Make server directory and go to it
|
||||
mkdir $eqemu_server_directory
|
||||
#::: Go to server directory
|
||||
cd $eqemu_server_directory
|
||||
|
||||
#::: Setup MySQL root user PW
|
||||
|
||||
@@ -432,6 +432,13 @@
|
||||
9176|2022_01_10_checksum_verification.sql|SHOW COLUMNS FROM `account` LIKE 'crc_eqgame'|empty|
|
||||
9177|2022_03_06_table_structure_changes.sql|SHOW COLUMNS FROM `pets` LIKE 'id'|empty|
|
||||
9178|2022_03_07_saylink_collation.sql|SELECT * FROM db_version WHERE version >= 9178|empty|
|
||||
9179|2022_04_30_hp_regen_per_second.sql|SHOW COLUMNS FROM `npc_types` LIKE 'hp_regen_per_second'|empty|
|
||||
9180|2022_05_01_character_peqzone_flags.sql|SHOW TABLES LIKE 'character_peqzone_flags'|empty|
|
||||
9181|2022_05_03_task_activity_goal_match_list.sql|SHOW COLUMNS FROM `task_activities` LIKE 'goal_match_list'|empty|
|
||||
9182|2022_05_02_npc_types_int64.sql|SHOW COLUMNS FROM `npc_types` LIKE 'hp'|missing|bigint
|
||||
9183|2022_05_07_merchant_data_buckets.sql|SHOW COLUMNS FROM `merchantlist` LIKE 'bucket_comparison'|empty
|
||||
9184|2022_05_21_schema_consistency.sql|SELECT * FROM db_version WHERE version >= 9184|empty|
|
||||
9185|2022_05_07_discord_webhooks.sql|SHOW TABLES LIKE 'discord_webhooks'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE npc_types ADD COLUMN hp_regen_per_second bigint DEFAULT 0 AFTER hp_regen_rate;
|
||||
@@ -0,0 +1,14 @@
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for character_peqzone_flags
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `character_peqzone_flags`;
|
||||
CREATE TABLE `character_peqzone_flags` (
|
||||
`id` int NOT NULL DEFAULT 0,
|
||||
`zone_id` int NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`, `zone_id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE npc_types MODIFY COLUMN hp BIGINT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE npc_types MODIFY COLUMN mana BIGINT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE npc_types MODIFY COLUMN hp_regen_rate BIGINT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE npc_types MODIFY COLUMN mana_regen_rate BIGINT NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE task_activities ADD goal_match_list text AFTER goalid;
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE discord_webhooks
|
||||
(
|
||||
id INT auto_increment primary key NULL,
|
||||
webhook_name varchar(100) NULL,
|
||||
webhook_url varchar(255) NULL,
|
||||
created_at DATETIME NULL,
|
||||
deleted_at DATETIME NULL
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE logsys_categories
|
||||
ADD log_to_discord smallint(11) default 0 AFTER log_to_gmsay;
|
||||
ALTER TABLE logsys_categories
|
||||
ADD discord_webhook_id int(11) default 0 AFTER log_to_discord;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user