[GM Command] Door Manipulation Command Port (#1524)

* Initial commit

* Push latest

* Update door_manipulation.cpp

* More door work

* More doors work

* Upload notes

* Finalize changes

* Remove comment

* Add missing chat line

* Swapped URI parser with something not using deprecated C++ functions
This commit is contained in:
Chris Miles
2021-09-12 22:08:04 -05:00
committed by GitHub
parent 31ab1d4287
commit 94c1a50cc8
22 changed files with 2007 additions and 9 deletions
+3 -1
View File
@@ -526,6 +526,7 @@ SET(common_headers
guild_base.h
guilds.h
http/httplib.h
http/uri.h
inventory_profile.h
inventory_slot.h
ipc_mutex.h
@@ -638,7 +639,8 @@ SET(common_headers
StackWalker/StackWalker.h
util/memory_stream.h
util/directory.h
util/uuid.h)
util/uuid.h
)
SOURCE_GROUP(Event FILES
event/event_loop.h
+67
View File
@@ -39,6 +39,7 @@
#include "unix.h"
#include <netinet/in.h>
#include <sys/time.h>
#endif
#include "database.h"
@@ -46,6 +47,8 @@
#include "extprofile.h"
#include "string_util.h"
#include "database_schema.h"
#include "http/httplib.h"
#include "http/uri.h"
extern Client client;
@@ -2418,3 +2421,67 @@ bool Database::CopyCharacter(
return true;
}
void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string url)
{
try {
uri request_uri(url);
LogHTTP(
"[SourceDatabaseTableFromUrl] parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
url,
request_uri.get_path(),
request_uri.get_host(),
request_uri.get_query(),
request_uri.get_scheme(),
request_uri.get_port()
);
if (!DoesTableExist(table_name)) {
LogMySQLQuery("Table [{}] does not exist. Downloading from Github and installing...", table_name);
// http get request
httplib::Client cli(
fmt::format(
"{}://{}",
request_uri.get_scheme(),
request_uri.get_host()
).c_str()
);
cli.set_connection_timeout(0, 60000000); // 60 sec
cli.set_read_timeout(60, 0); // 60 seconds
cli.set_write_timeout(60, 0); // 60 seconds
int sourced_queries = 0;
if (auto res = cli.Get(request_uri.get_path().c_str())) {
if (res->status == 200) {
for (auto &s: SplitString(res->body, ';')) {
if (!trim(s).empty()) {
auto results = QueryDatabase(s);
if (!results.ErrorMessage().empty()) {
LogError("Error sourcing SQL [{}]", results.ErrorMessage());
return;
}
sourced_queries++;
}
}
}
}
else {
LogError("Error retrieving URL [{}]", url);
}
LogMySQLQuery(
"Table [{}] installed. Sourced [{}] queries",
table_name,
sourced_queries
);
}
}
catch (std::invalid_argument iae) {
LogError("[SourceDatabaseTableFromUrl] URI parser error [{}]", iae.what());
}
}
+2
View File
@@ -269,6 +269,8 @@ public:
int CountInvSnapshots();
void ClearInvSnapshots(bool from_now = false);
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
private:
+2
View File
@@ -130,6 +130,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HTTP].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
/**
* RFC 5424
+2
View File
@@ -125,6 +125,7 @@ namespace Logs {
Cheat,
ClientList,
DiaWind,
HTTP,
MaxCategoryID /* Don't Remove this */
};
@@ -208,6 +209,7 @@ namespace Logs {
"Cheat",
"ClientList",
"DialogueWindow",
"HTTP",
};
}
+16
View File
@@ -676,6 +676,16 @@
OutF(LogSys, Logs::Detail, Logs::DiaWind, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHTTP(message, ...) do {\
if (LogSys.log_settings[Logs::HTTP].is_category_enabled == 1)\
OutF(LogSys, Logs::General, Logs::HTTP, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHTTPDetail(message, ...) do {\
if (LogSys.log_settings[Logs::HTTP].is_category_enabled == 1)\
OutF(LogSys, Logs::Detail, Logs::HTTP, __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__);\
@@ -1066,6 +1076,12 @@
#define LogDiaWindDetail(message, ...) do {\
} while (0)
#define LogHTTP(message, ...) do {\
} while (0)
#define LogHTTPDetail(message, ...) do {\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
} while (0)
+633
View File
@@ -0,0 +1,633 @@
// Copyright (C) 2015 Ben Lewis <benjf5+github@gmail.com>
// Licensed under the MIT license.
// https://github.com/ben-zen/uri-library
#pragma once
#include <cctype>
#include <map>
#include <string>
#include <stdexcept>
#include <utility>
class uri {
/* URIs are broadly divided into two categories: hierarchical and
* non-hierarchical. Both hierarchical URIs and non-hierarchical URIs have a
* few elements in common; all URIs have a scheme of one or more alphanumeric
* characters followed by a colon, and they all may optionally have a query
* component preceded by a question mark, and a fragment component preceded by
* an octothorpe (hash mark: '#'). The query consists of stanzas separated by
* either ampersands ('&') or semicolons (';') (but only one or the other),
* and each stanza consists of a key and an optional value; if the value
* exists, the key and value must be divided by an equals sign.
*
* The following is an example from Wikipedia of a hierarchical URI:
* scheme:[//[user:password@]domain[:port]][/]path[?query][#fragment]
*/
public:
enum class scheme_category {
Hierarchical,
NonHierarchical
};
enum class component {
Scheme,
Content,
Username,
Password,
Host,
Port,
Path,
Query,
Fragment
};
enum class query_argument_separator {
ampersand,
semicolon
};
uri(
char const *uri_text, scheme_category category = scheme_category::Hierarchical,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(false),
m_port(0),
m_separator(separator)
{
setup(std::string(uri_text), category);
};
uri(
std::string const &uri_text, scheme_category category = scheme_category::Hierarchical,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(false),
m_port(0),
m_separator(separator)
{
setup(uri_text, category);
};
uri(
std::map<component, std::string> const &components,
scheme_category category,
bool rooted_path,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(rooted_path),
m_separator(separator)
{
if (components.count(component::Scheme)) {
if (components.at(component::Scheme).length() == 0) {
throw std::invalid_argument("Scheme cannot be empty.");
}
m_scheme = components.at(component::Scheme);
}
else {
throw std::invalid_argument("A URI must have a scheme.");
}
if (category == scheme_category::Hierarchical) {
if (components.count(component::Content)) {
throw std::invalid_argument("The content component is only for use in non-hierarchical URIs.");
}
bool has_username = components.count(component::Username);
bool has_password = components.count(component::Password);
if (has_username && has_password) {
m_username = components.at(component::Username);
m_password = components.at(component::Password);
}
else if ((has_username && !has_password) || (!has_username && has_password)) {
throw std::invalid_argument("If a username or password is supplied, both must be provided.");
}
if (components.count(component::Host)) {
m_host = components.at(component::Host);
}
if (components.count(component::Port)) {
m_port = std::stoul(components.at(component::Port));
}
if (components.count(component::Path)) {
m_path = components.at(component::Path);
}
else {
throw std::invalid_argument("A path is required on a hierarchical URI, even an empty path.");
}
}
else {
if (components.count(component::Username)
|| components.count(component::Password)
|| components.count(component::Host)
|| components.count(component::Port)
|| components.count(component::Path)) {
throw std::invalid_argument("None of the hierarchical components are allowed in a non-hierarchical URI.");
}
if (components.count(component::Content)) {
m_content = components.at(component::Content);
}
else {
throw std::invalid_argument(
"Content is a required component for a non-hierarchical URI, even an empty string."
);
}
}
if (components.count(component::Query)) {
m_query = components.at(component::Query);
}
if (components.count(component::Fragment)) {
m_fragment = components.at(component::Fragment);
}
}
uri(uri const &other, std::map<component, std::string> const &replacements) :
m_category(other.m_category),
m_path_is_rooted(other.m_path_is_rooted),
m_separator(other.m_separator)
{
m_scheme = (replacements.count(component::Scheme))
? replacements.at(component::Scheme) : other.m_scheme;
if (m_category == scheme_category::Hierarchical) {
m_username = (replacements.count(component::Username))
? replacements.at(component::Username) : other.m_username;
m_password = (replacements.count(component::Password))
? replacements.at(component::Password) : other.m_password;
m_host = (replacements.count(component::Host))
? replacements.at(component::Host) : other.m_host;
m_port = (replacements.count(component::Port))
? std::stoul(replacements.at(component::Port)) : other.m_port;
m_path = (replacements.count(component::Path))
? replacements.at(component::Path) : other.m_path;
}
else {
m_content = (replacements.count(component::Content))
? replacements.at(component::Content) : other.m_content;
}
m_query = (replacements.count(component::Query))
? replacements.at(component::Query) : other.m_query;
m_fragment = (replacements.count(component::Fragment))
? replacements.at(component::Fragment) : other.m_fragment;
}
// Copy constructor; just use the copy assignment operator internally.
uri(uri const &other)
{
*this = other;
};
// Copy assignment operator
uri &operator=(uri const &other)
{
if (this != &other) {
m_scheme = other.m_scheme;
m_content = other.m_content;
m_username = other.m_username;
m_password = other.m_password;
m_host = other.m_host;
m_path = other.m_path;
m_query = other.m_query;
m_fragment = other.m_fragment;
m_query_dict = other.m_query_dict;
m_category = other.m_category;
m_port = other.m_port;
m_path_is_rooted = other.m_path_is_rooted;
m_separator = other.m_separator;
}
return *this;
}
~uri() {};
std::string const &get_scheme() const
{
return m_scheme;
};
scheme_category get_scheme_category() const
{
return m_category;
};
std::string const &get_content() const
{
if (m_category != scheme_category::NonHierarchical) {
throw std::domain_error("The content component is only valid for non-hierarchical URIs.");
}
return m_content;
};
std::string const &get_username() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The username component is only valid for hierarchical URIs.");
}
return m_username;
};
std::string const &get_password() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The password component is only valid for hierarchical URIs.");
}
return m_password;
};
std::string const &get_host() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The host component is only valid for hierarchical URIs.");
}
return m_host;
};
unsigned long get_port() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The port component is only valid for hierarchical URIs.");
}
return m_port;
};
std::string const &get_path() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The path component is only valid for hierarchical URIs.");
}
return m_path;
};
std::string const &get_query() const
{
return m_query;
};
std::map<std::string, std::string> const &get_query_dictionary() const
{
return m_query_dict;
};
std::string const &get_fragment() const
{
return m_fragment;
};
std::string to_string() const
{
std::string full_uri;
full_uri.append(m_scheme);
full_uri.append(":");
if (m_content.length() > m_path.length()) {
full_uri.append("//");
if (!(m_username.empty() || m_password.empty())) {
full_uri.append(m_username);
full_uri.append(":");
full_uri.append(m_password);
full_uri.append("@");
}
full_uri.append(m_host);
if (m_port != 0) {
full_uri.append(":");
full_uri.append(std::to_string(m_port));
}
}
if (m_path_is_rooted) {
full_uri.append("/");
}
full_uri.append(m_path);
if (!m_query.empty()) {
full_uri.append("?");
full_uri.append(m_query);
}
if (!m_fragment.empty()) {
full_uri.append("#");
full_uri.append(m_fragment);
}
return full_uri;
};
private:
void setup(std::string const &uri_text, scheme_category category)
{
size_t const uri_length = uri_text.length();
if (uri_length == 0) {
throw std::invalid_argument("URIs cannot be of zero length.");
}
std::string::const_iterator cursor = parse_scheme(
uri_text,
uri_text.begin());
// After calling parse_scheme, *cursor == ':'; none of the following parsers
// expect a separator character, so we advance the cursor upon calling them.
cursor = parse_content(uri_text, (cursor + 1));
if ((cursor != uri_text.end()) && (*cursor == '?')) {
cursor = parse_query(uri_text, (cursor + 1));
}
if ((cursor != uri_text.end()) && (*cursor == '#')) {
cursor = parse_fragment(uri_text, (cursor + 1));
}
init_query_dictionary(); // If the query string is empty, this will be empty too.
};
std::string::const_iterator parse_scheme(
std::string const &uri_text,
std::string::const_iterator scheme_start
)
{
std::string::const_iterator scheme_end = scheme_start;
while ((scheme_end != uri_text.end()) && (*scheme_end != ':')) {
if (!(std::isalnum(*scheme_end) || (*scheme_end == '-')
|| (*scheme_end == '+') || (*scheme_end == '.'))) {
throw std::invalid_argument(
"Invalid character found in the scheme component. Supplied URI was: \""
+ uri_text + "\"."
);
}
++scheme_end;
}
if (scheme_end == uri_text.end()) {
throw std::invalid_argument(
"End of URI found while parsing the scheme. Supplied URI was: \""
+ uri_text + "\"."
);
}
if (scheme_start == scheme_end) {
throw std::invalid_argument(
"Scheme component cannot be zero-length. Supplied URI was: \""
+ uri_text + "\"."
);
}
m_scheme = std::move(std::string(scheme_start, scheme_end));
return scheme_end;
};
std::string::const_iterator parse_content(
std::string const &uri_text,
std::string::const_iterator content_start
)
{
std::string::const_iterator content_end = content_start;
while ((content_end != uri_text.end()) && (*content_end != '?') && (*content_end != '#')) {
++content_end;
}
m_content = std::move(std::string(content_start, content_end));
if ((m_category == scheme_category::Hierarchical) && (m_content.length() > 0)) {
// If it's a hierarchical URI, the content should be parsed for the hierarchical components.
std::string::const_iterator path_start = m_content.begin();
std::string::const_iterator path_end = m_content.end();
if (!m_content.compare(0, 2, "//")) {
// In this case an authority component is present.
std::string::const_iterator authority_cursor = (m_content.begin() + 2);
if (m_content.find_first_of('@') != std::string::npos) {
std::string::const_iterator userpass_divider = parse_username(
uri_text,
m_content,
authority_cursor
);
authority_cursor = parse_password(uri_text, m_content, (userpass_divider + 1));
// After this call, *authority_cursor == '@', so we skip over it.
++authority_cursor;
}
authority_cursor = parse_host(uri_text, m_content, authority_cursor);
if ((authority_cursor != m_content.end()) && (*authority_cursor == ':')) {
authority_cursor = parse_port(uri_text, m_content, (authority_cursor + 1));
}
if ((authority_cursor != m_content.end()) && (*authority_cursor == '/')) {
// Then the path is rooted, and we should note this.
m_path_is_rooted = true;
path_start = authority_cursor + 1;
}
// If we've reached the end and no path is present then set path_start
// to the end.
if (authority_cursor == m_content.end()) {
path_start = m_content.end();
}
}
else if (!m_content.compare(0, 1, "/")) {
m_path_is_rooted = true;
++path_start;
}
// We can now build the path based on what remains in the content string,
// since that's all that exists after the host and optional port component.
m_path = std::move(std::string(path_start, path_end));
}
return content_end;
};
std::string::const_iterator parse_username(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator username_start
)
{
std::string::const_iterator username_end = username_start;
// Since this is only reachable when '@' was in the content string, we can
// ignore the end-of-string case.
while (*username_end != ':') {
if (*username_end == '@') {
throw std::invalid_argument(
"Username must be followed by a password. Supplied URI was: \""
+ uri_text + "\"."
);
}
++username_end;
}
m_username = std::move(std::string(username_start, username_end));
return username_end;
};
std::string::const_iterator parse_password(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator password_start
)
{
std::string::const_iterator password_end = password_start;
while (*password_end != '@') {
++password_end;
}
m_password = std::move(std::string(password_start, password_end));
return password_end;
};
std::string::const_iterator parse_host(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator host_start
)
{
std::string::const_iterator host_end = host_start;
// So, the host can contain a few things. It can be a domain, it can be an
// IPv4 address, it can be an IPv6 address, or an IPvFuture literal. In the
// case of those last two, it's of the form [...] where what's between the
// brackets is a matter of which IPv?? version it is.
while (host_end != content.end()) {
if (*host_end == '[') {
// We're parsing an IPv6 or IPvFuture address, so we should handle that
// instead of the normal procedure.
while ((host_end != content.end()) && (*host_end != ']')) {
++host_end;
}
if (host_end == content.end()) {
throw std::invalid_argument(
"End of content component encountered "
"while parsing the host component. "
"Supplied URI was: \""
+ uri_text + "\"."
);
}
++host_end;
break;
// We can stop looping, we found the end of the IP literal, which is the
// whole of the host component when one's in use.
}
else if ((*host_end == ':') || (*host_end == '/')) {
break;
}
else {
++host_end;
}
}
m_host = std::move(std::string(host_start, host_end));
return host_end;
};
std::string::const_iterator parse_port(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator port_start
)
{
std::string::const_iterator port_end = port_start;
while ((port_end != content.end()) && (*port_end != '/')) {
if (!std::isdigit(*port_end)) {
throw std::invalid_argument(
"Invalid character while parsing the port. "
"Supplied URI was: \"" + uri_text + "\"."
);
}
++port_end;
}
m_port = std::stoul(std::string(port_start, port_end));
return port_end;
};
std::string::const_iterator parse_query(
std::string const &uri_text,
std::string::const_iterator query_start
)
{
std::string::const_iterator query_end = query_start;
while ((query_end != uri_text.end()) && (*query_end != '#')) {
// Queries can contain almost any character except hash, which is reserved
// for the start of the fragment.
++query_end;
}
m_query = std::move(std::string(query_start, query_end));
return query_end;
};
std::string::const_iterator parse_fragment(
std::string const &uri_text,
std::string::const_iterator fragment_start
)
{
m_fragment = std::move(std::string(fragment_start, uri_text.end()));
return uri_text.end();
};
void init_query_dictionary()
{
if (!m_query.empty()) {
// Loop over the query string looking for '&'s, then check each one for
// an '=' to find keys and values; if there's not an '=' then the key
// will have an empty value in the map.
char separator = (m_separator == query_argument_separator::ampersand) ? '&' : ';';
size_t carat = 0;
size_t stanza_end = m_query.find_first_of(separator);
do {
std::string stanza = m_query.substr(
carat,
((stanza_end != std::string::npos) ? (stanza_end - carat) : std::string::npos));
size_t key_value_divider = stanza.find_first_of('=');
std::string key = stanza.substr(0, key_value_divider);
std::string value;
if (key_value_divider != std::string::npos) {
value = stanza.substr((key_value_divider + 1));
}
if (m_query_dict.count(key) != 0) {
throw std::invalid_argument("Bad key in the query string!");
}
m_query_dict.emplace(key, value);
carat = ((stanza_end != std::string::npos) ? (stanza_end + 1)
: std::string::npos);
stanza_end = m_query.find_first_of(separator, carat);
} while ((stanza_end != std::string::npos)
|| (carat != std::string::npos));
}
}
std::string m_scheme;
std::string m_content;
std::string m_username;
std::string m_password;
std::string m_host;
std::string m_path;
std::string m_query;
std::string m_fragment;
std::map<std::string, std::string> m_query_dict;
scheme_category m_category;
unsigned long m_port;
bool m_path_is_rooted;
query_argument_separator m_separator;
};
@@ -0,0 +1,346 @@
/**
* 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_TOOL_GAME_OBJECTS_REPOSITORY_H
#define EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
#include "../../database.h"
#include "../../string_util.h"
#include <ctime>
class BaseToolGameObjectsRepository {
public:
struct ToolGameObjects {
int id;
int zoneid;
std::string zonesn;
std::string object_name;
std::string file_from;
int is_global;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"zoneid",
"zonesn",
"object_name",
"file_from",
"is_global",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"zoneid",
"zonesn",
"object_name",
"file_from",
"is_global",
};
}
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("tool_game_objects");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static ToolGameObjects NewEntity()
{
ToolGameObjects entry{};
entry.id = 0;
entry.zoneid = 0;
entry.zonesn = "";
entry.object_name = "";
entry.file_from = "";
entry.is_global = 0;
return entry;
}
static ToolGameObjects GetToolGameObjectsEntry(
const std::vector<ToolGameObjects> &tool_game_objectss,
int tool_game_objects_id
)
{
for (auto &tool_game_objects : tool_game_objectss) {
if (tool_game_objects.id == tool_game_objects_id) {
return tool_game_objects;
}
}
return NewEntity();
}
static ToolGameObjects FindOne(
Database& db,
int tool_game_objects_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
tool_game_objects_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
return entry;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int tool_game_objects_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
tool_game_objects_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
ToolGameObjects tool_game_objects_entry
)
{
std::vector<std::string> update_values;
auto columns = Columns();
update_values.push_back(columns[1] + " = " + std::to_string(tool_game_objects_entry.zoneid));
update_values.push_back(columns[2] + " = '" + EscapeString(tool_game_objects_entry.zonesn) + "'");
update_values.push_back(columns[3] + " = '" + EscapeString(tool_game_objects_entry.object_name) + "'");
update_values.push_back(columns[4] + " = '" + EscapeString(tool_game_objects_entry.file_from) + "'");
update_values.push_back(columns[5] + " = " + std::to_string(tool_game_objects_entry.is_global));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
implode(", ", update_values),
PrimaryKey(),
tool_game_objects_entry.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static ToolGameObjects InsertOne(
Database& db,
ToolGameObjects tool_game_objects_entry
)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(tool_game_objects_entry.id));
insert_values.push_back(std::to_string(tool_game_objects_entry.zoneid));
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.zonesn) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.object_name) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.file_from) + "'");
insert_values.push_back(std::to_string(tool_game_objects_entry.is_global));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
implode(",", insert_values)
)
);
if (results.Success()) {
tool_game_objects_entry.id = results.LastInsertedID();
return tool_game_objects_entry;
}
tool_game_objects_entry = NewEntity();
return tool_game_objects_entry;
}
static int InsertMany(
Database& db,
std::vector<ToolGameObjects> tool_game_objects_entries
)
{
std::vector<std::string> insert_chunks;
for (auto &tool_game_objects_entry: tool_game_objects_entries) {
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(tool_game_objects_entry.id));
insert_values.push_back(std::to_string(tool_game_objects_entry.zoneid));
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.zonesn) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.object_name) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.file_from) + "'");
insert_values.push_back(std::to_string(tool_game_objects_entry.is_global));
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<ToolGameObjects> All(Database& db)
{
std::vector<ToolGameObjects> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
all_entries.push_back(entry);
}
return all_entries;
}
static std::vector<ToolGameObjects> GetWhere(Database& db, std::string where_filter)
{
std::vector<ToolGameObjects> 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) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
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_TOOL_GAME_OBJECTS_REPOSITORY_H
@@ -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_TOOL_GAME_OBJECTS_REPOSITORY_H
#define EQEMU_TOOL_GAME_OBJECTS_REPOSITORY_H
#include "../database.h"
#include "../string_util.h"
#include "base/base_tool_game_objects_repository.h"
class ToolGameObjectsRepository: public BaseToolGameObjectsRepository {
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
*
* ToolGameObjectsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ToolGameObjectsRepository::GetWhereNeverExpires()
* ToolGameObjectsRepository::GetWhereXAndY()
* ToolGameObjectsRepository::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_TOOL_GAME_OBJECTS_REPOSITORY_H