mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[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:
parent
31ab1d4287
commit
94c1a50cc8
@ -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
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -269,6 +269,8 @@ public:
|
||||
int CountInvSnapshots();
|
||||
void ClearInvSnapshots(bool from_now = false);
|
||||
|
||||
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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
common/http/uri.h
Normal file
633
common/http/uri.h
Normal 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;
|
||||
};
|
||||
346
common/repositories/base/base_tool_game_objects_repository.h
Normal file
346
common/repositories/base/base_tool_game_objects_repository.h
Normal file
@ -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
|
||||
70
common/repositories/tool_game_objects_repository.h
Normal file
70
common/repositories/tool_game_objects_repository.h
Normal file
@ -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
|
||||
@ -157,7 +157,7 @@ foreach my $table_to_generate (@tables) {
|
||||
$table_found_in_schema = 0;
|
||||
}
|
||||
|
||||
if ($table_found_in_schema == 0) {
|
||||
if ($table_found_in_schema == 0 && ($requested_table_to_generate eq "" || $requested_table_to_generate eq "all")) {
|
||||
print "Table [$table_to_generate] not found in schema, skipping\n";
|
||||
next;
|
||||
}
|
||||
|
||||
@ -80,6 +80,7 @@ SET(zone_sources
|
||||
fearpath.cpp
|
||||
forage.cpp
|
||||
global_loot_manager.cpp
|
||||
gm_commands/door_manipulation.cpp
|
||||
groups.cpp
|
||||
guild.cpp
|
||||
guild_mgr.cpp
|
||||
@ -198,6 +199,7 @@ SET(zone_headers
|
||||
fastmath.h
|
||||
forage.h
|
||||
global_loot_manager.h
|
||||
gm_commands/door_manipulation.h
|
||||
groups.h
|
||||
guild_mgr.h
|
||||
hate_list.h
|
||||
|
||||
@ -10515,3 +10515,13 @@ void Client::ApplyWeaponsStance()
|
||||
weaponstance.spellbonus_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Client::GetDoorToolEntityId() const
|
||||
{
|
||||
return m_door_tool_entity_id;
|
||||
}
|
||||
|
||||
void Client::SetDoorToolEntityId(uint16 door_tool_entity_id)
|
||||
{
|
||||
Client::m_door_tool_entity_id = door_tool_entity_id;
|
||||
}
|
||||
|
||||
@ -1764,9 +1764,17 @@ private:
|
||||
int Haste; //precalced value
|
||||
uint32 tmSitting; // time stamp started sitting, used for HP regen bonus added on MAY 5, 2004
|
||||
|
||||
|
||||
// dev tools
|
||||
bool display_mob_info_window;
|
||||
bool dev_tools_enabled;
|
||||
|
||||
uint16 m_door_tool_entity_id;
|
||||
public:
|
||||
uint16 GetDoorToolEntityId() const;
|
||||
void SetDoorToolEntityId(uint16 door_tool_entity_id);
|
||||
private:
|
||||
|
||||
int32 max_end;
|
||||
int32 current_endurance;
|
||||
|
||||
|
||||
@ -66,6 +66,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/repositories/character_instance_safereturns_repository.h"
|
||||
#include "../common/repositories/criteria/content_filter_criteria.h"
|
||||
#include "../common/shared_tasks.h"
|
||||
#include "gm_commands/door_manipulation.h"
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
@ -4356,6 +4357,20 @@ void Client::Handle_OP_ClickDoor(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
// set door selected
|
||||
if (IsDevToolsEnabled()) {
|
||||
SetDoorToolEntityId(currentdoor->GetEntityID());
|
||||
DoorManipulation::CommandHeader(this);
|
||||
Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Door ({}) [{}]",
|
||||
currentdoor->GetEntityID(),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door edit", false, "#door edit")
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
char buf[20];
|
||||
snprintf(buf, 19, "%u", cd->doorid);
|
||||
buf[19] = '\0';
|
||||
|
||||
@ -78,6 +78,7 @@
|
||||
#include "../common/content/world_content_service.h"
|
||||
#include "../common/http/httplib.h"
|
||||
#include "../common/shared_tasks.h"
|
||||
#include "gm_commands/door_manipulation.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern WorldServer worldserver;
|
||||
@ -202,6 +203,7 @@ int command_init(void)
|
||||
command_add("disablerecipe", "[recipe_id] - Disables a recipe using the recipe id.", 80, command_disablerecipe) ||
|
||||
command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) ||
|
||||
command_add("distance", "- Reports the distance between you and your target.", 80, command_distance) ||
|
||||
command_add("door", "Door editing command", 80, command_door) ||
|
||||
command_add("doanim", "[animnum] [type] - Send an EmoteAnim for you or your target", 50, command_doanim) ||
|
||||
command_add("dz", "Manage expeditions and dynamic zone instances", 80, command_dz) ||
|
||||
command_add("dzkickplayers", "Removes all players from current expedition. (/kickplayers alternative for pre-RoF clients)", 0, command_dzkickplayers) ||
|
||||
@ -12940,6 +12942,10 @@ void command_distance(Client *c, const Seperator *sep) {
|
||||
}
|
||||
}
|
||||
|
||||
void command_door(Client *c, const Seperator *sep) {
|
||||
DoorManipulation::CommandHandler(c, sep);
|
||||
}
|
||||
|
||||
void command_cvs(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(c)
|
||||
|
||||
@ -90,6 +90,7 @@ void command_devtools(Client *c, const Seperator *sep);
|
||||
void command_details(Client *c, const Seperator *sep);
|
||||
void command_disablerecipe(Client *c, const Seperator *sep);
|
||||
void command_disarmtrap(Client *c, const Seperator *sep);
|
||||
void command_door(Client *c, const Seperator *sep);
|
||||
void command_distance(Client *c, const Seperator *sep);
|
||||
void command_doanim(Client *c, const Seperator *sep);
|
||||
void command_dz(Client *c, const Seperator *sep);
|
||||
|
||||
@ -801,6 +801,12 @@ void Doors::SetIncline(int in) {
|
||||
entity_list.RespawnAllDoors();
|
||||
}
|
||||
|
||||
void Doors::SetInvertState(int in) {
|
||||
entity_list.DespawnAllDoors();
|
||||
invert_state = in;
|
||||
entity_list.RespawnAllDoors();
|
||||
}
|
||||
|
||||
void Doors::SetOpenType(uint8 in) {
|
||||
entity_list.DespawnAllDoors();
|
||||
open_type = in;
|
||||
|
||||
@ -54,6 +54,7 @@ public:
|
||||
void SetDoorName(const char *name);
|
||||
void SetEntityID(uint32 entity) { entity_id = entity; }
|
||||
void SetIncline(int in);
|
||||
void SetInvertState(int in);
|
||||
void SetKeyItem(uint32 in) { key_item_id = in; }
|
||||
void SetLocation(float x, float y, float z);
|
||||
void SetLockpick(uint16 in) { lockpick = in; }
|
||||
|
||||
779
zone/gm_commands/door_manipulation.cpp
Normal file
779
zone/gm_commands/door_manipulation.cpp
Normal file
@ -0,0 +1,779 @@
|
||||
#include "door_manipulation.h"
|
||||
#include "../doors.h"
|
||||
#include "../../common/misc_functions.h"
|
||||
|
||||
#define MAX_CLIENT_MESSAGE_LENGTH 2000
|
||||
|
||||
void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
|
||||
{
|
||||
// this should never happen
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
// args
|
||||
std::string arg1(sep->arg[1]);
|
||||
std::string arg2(sep->arg[2]);
|
||||
std::string arg3(sep->arg[3]);
|
||||
|
||||
// table check
|
||||
std::string table_name = "tool_game_objects";
|
||||
std::string url = "https://raw.githubusercontent.com/EQEmu/database-tool-sqls/main/tool_game_objects.sql";
|
||||
if (!database.DoesTableExist(table_name)) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Table [{}] does not exist. Downloading from [{}] and installing locally",
|
||||
table_name,
|
||||
url
|
||||
).c_str()
|
||||
);
|
||||
database.SourceDatabaseTableFromUrl(
|
||||
table_name,
|
||||
url
|
||||
);
|
||||
}
|
||||
|
||||
// option
|
||||
if (arg1.empty()) {
|
||||
DoorManipulation::CommandHeader(c);
|
||||
c->Message(Chat::White, "#door create <modelname> | Creates a door from a model. (Example IT78 creates a campfire)");
|
||||
c->Message(Chat::White, "#door setinvertstate [0|1] | Sets selected door invert state");
|
||||
c->Message(Chat::White, "#door setincline <incline> | Sets selected door incline");
|
||||
c->Message(Chat::White, "#door opentype <opentype> | Sets selected door opentype");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"#door model <modelname> | Changes door model for selected door or select from [{}] or [{}]",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door showmodelszone", false, "local zone"),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door showmodelsglobal", false, "global")
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"#door showmodelsfromfile <file.eqg|file.s3d> | Shows models from s3d or eqg file. Example tssequip.eqg or wallet01.eqg"
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} | Shows available models in the current zone that you are in",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door showmodelszone", false, "#door showmodelszone")
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} | Shows available models globally by first listing all global model files",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door showmodelsglobal", false, "#door showmodelsglobal")
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(Chat::White, "#door save | Creates database entry for selected door");
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} - Brings up editing interface for selected door",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door edit", false, "#door edit")
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} - lists doors in zone",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#list doors", false, "#list doors")
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// edit menu
|
||||
if (arg1 == "edit") {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
if (door) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Door Selected ID [{}] Name [{}] OpenType [{}] Invertstate [{} | {}/{}] ",
|
||||
c->GetDoorToolEntityId(),
|
||||
door->GetDoorName(),
|
||||
door->GetOpenType(),
|
||||
door->GetInvertState(),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door setinvertstate 0", false, "0"),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door setinvertstate 1", false, "1")
|
||||
).c_str()
|
||||
);
|
||||
|
||||
const std::string move_x_action = "move_x";
|
||||
const std::string move_y_action = "move_y";
|
||||
const std::string move_z_action = "move_z";
|
||||
const std::string move_h_action = "move_h";
|
||||
const std::string set_size_action = "set_size";
|
||||
|
||||
std::vector<std::string> move_options = {
|
||||
move_x_action,
|
||||
move_y_action,
|
||||
move_z_action,
|
||||
move_h_action,
|
||||
set_size_action
|
||||
};
|
||||
std::vector<std::string> move_x_options_positive;
|
||||
std::vector<std::string> move_x_options_negative;
|
||||
std::vector<std::string> move_y_options_positive;
|
||||
std::vector<std::string> move_y_options_negative;
|
||||
std::vector<std::string> move_z_options_positive;
|
||||
std::vector<std::string> move_z_options_negative;
|
||||
std::vector<std::string> move_h_options_positive;
|
||||
std::vector<std::string> move_h_options_negative;
|
||||
std::vector<std::string> set_size_options_positive;
|
||||
std::vector<std::string> set_size_options_negative;
|
||||
for (const auto &move_option : move_options) {
|
||||
if (move_option == move_x_action) {
|
||||
move_x_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} .25", move_option),
|
||||
false,
|
||||
".25"
|
||||
)
|
||||
);
|
||||
|
||||
for (int move_index = 0; move_index <= 15; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_x_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int move_index = -15; move_index <= 0; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_x_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
move_x_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} -.25", move_option),
|
||||
false,
|
||||
"-.25"
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (move_option == move_y_action) {
|
||||
move_y_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} .25", move_option),
|
||||
false,
|
||||
".25"
|
||||
)
|
||||
);
|
||||
|
||||
for (int move_index = 0; move_index <= 15; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_y_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int move_index = -15; move_index <= 0; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_y_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
move_y_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} -.25", move_option),
|
||||
false,
|
||||
"-.25"
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (move_option == move_z_action) {
|
||||
move_z_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} .25", move_option),
|
||||
false,
|
||||
".25"
|
||||
)
|
||||
);
|
||||
|
||||
for (int move_index = 0; move_index <= 15; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_z_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int move_index = -15; move_index <= 0; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_z_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
move_z_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} -.25", move_option),
|
||||
false,
|
||||
"-.25"
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (move_option == move_h_action) {
|
||||
for (int move_index = 0; move_index <= 50; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_h_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int move_index = -50; move_index <= 0; move_index += 5) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
move_h_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (move_option == set_size_action) {
|
||||
for (int move_index = 0; move_index <= 100; move_index += 10) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
set_size_options_positive.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int move_index = -100; move_index <= 0; move_index += 10) {
|
||||
int value = (move_index == 0 ? 1 : move_index);
|
||||
set_size_options_negative.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door edit {} {}", move_option, value),
|
||||
false,
|
||||
fmt::format("{}", std::abs(value))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we're passing a move action here
|
||||
if (!arg3.empty() && StringIsNumber(arg3)) {
|
||||
int x_move = 0;
|
||||
int y_move = 0;
|
||||
int z_move = 0;
|
||||
int h_move = 0;
|
||||
int set_size = 0;
|
||||
|
||||
if (arg2 == move_x_action) {
|
||||
x_move = std::atoi(arg3.c_str());
|
||||
}
|
||||
if (arg2 == move_y_action) {
|
||||
y_move = std::atoi(arg3.c_str());
|
||||
}
|
||||
if (arg2 == move_z_action) {
|
||||
z_move = std::atoi(arg3.c_str());
|
||||
}
|
||||
if (arg2 == move_h_action) {
|
||||
h_move = std::atoi(arg3.c_str());
|
||||
}
|
||||
if (arg2 == set_size_action) {
|
||||
set_size = std::atoi(arg3.c_str());
|
||||
}
|
||||
|
||||
door->SetLocation(
|
||||
door->GetX() + x_move,
|
||||
door->GetY() + y_move,
|
||||
door->GetZ() + z_move
|
||||
);
|
||||
|
||||
glm::vec4 door_position = door->GetPosition();
|
||||
door_position.w = door_position.w + h_move;
|
||||
door->SetPosition(door_position);
|
||||
door->SetSize(door->GetSize() + set_size);
|
||||
}
|
||||
|
||||
// spawn and move helpers
|
||||
uint16 helper_mob_x_negative = 0;
|
||||
uint16 helper_mob_x_positive = 0;
|
||||
uint16 helper_mob_y_positive = 0;
|
||||
uint16 helper_mob_y_negative = 0;
|
||||
|
||||
for (auto &n: entity_list.GetNPCList()) {
|
||||
NPC *npc = n.second;
|
||||
std::string npc_name = npc->GetName();
|
||||
if (npc_name.find("-X") != std::string::npos) {
|
||||
helper_mob_x_negative = npc->GetID();
|
||||
}
|
||||
if (npc_name.find("-Y") != std::string::npos) {
|
||||
helper_mob_y_negative = npc->GetID();
|
||||
}
|
||||
if (npc_name.find("+X") != std::string::npos) {
|
||||
helper_mob_x_positive = npc->GetID();
|
||||
}
|
||||
if (npc_name.find("+Y") != std::string::npos) {
|
||||
helper_mob_y_positive = npc->GetID();
|
||||
}
|
||||
}
|
||||
|
||||
// -X
|
||||
glm::vec4 door_position = door->GetPosition();
|
||||
if (helper_mob_x_negative == 0) {
|
||||
door_position.x = door_position.x - 15;
|
||||
helper_mob_x_negative = NPC::SpawnNodeNPC("-X", "", door_position)->GetID();
|
||||
}
|
||||
else {
|
||||
auto n = entity_list.GetNPCByID(helper_mob_x_negative);
|
||||
n->GMMove(door->GetX() - 15, door->GetY(), door->GetZ(), n->GetHeading());
|
||||
}
|
||||
|
||||
// +X
|
||||
door_position = door->GetPosition();
|
||||
if (helper_mob_x_positive == 0) {
|
||||
door_position.x = door_position.x + 15;
|
||||
helper_mob_x_positive = NPC::SpawnNodeNPC("+X", "", door_position)->GetID();
|
||||
}
|
||||
else {
|
||||
auto n = entity_list.GetNPCByID(helper_mob_x_positive);
|
||||
n->GMMove(door->GetX() + 15, door->GetY(), door->GetZ(), n->GetHeading());
|
||||
}
|
||||
|
||||
// -Y
|
||||
door_position = door->GetPosition();
|
||||
if (helper_mob_y_negative == 0) {
|
||||
door_position.y = door_position.y - 15;
|
||||
helper_mob_y_negative = NPC::SpawnNodeNPC("-Y", "", door_position)->GetID();
|
||||
}
|
||||
else {
|
||||
auto n = entity_list.GetNPCByID(helper_mob_y_negative);
|
||||
n->GMMove(door->GetX(), door->GetY() - 15, door->GetZ(), n->GetHeading());
|
||||
}
|
||||
|
||||
// +Y
|
||||
door_position = door->GetPosition();
|
||||
if (helper_mob_y_positive == 0) {
|
||||
door_position.y = door_position.y + 15;
|
||||
helper_mob_y_positive = NPC::SpawnNodeNPC("+Y", "", door_position)->GetID();
|
||||
}
|
||||
else {
|
||||
auto n = entity_list.GetNPCByID(helper_mob_y_positive);
|
||||
n->GMMove(door->GetX(), door->GetY() + 15, door->GetZ(), n->GetHeading());
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Name [{}] [{}] [{}] [{}]",
|
||||
door->GetDoorName(),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
"#door save",
|
||||
false,
|
||||
"Save"
|
||||
),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
"#door changemodelqueue",
|
||||
false,
|
||||
"Change Model"
|
||||
),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
"#door setinclineinc",
|
||||
false,
|
||||
"Incline"
|
||||
)
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[{}] - [X] + [{}]",
|
||||
implode(" | ", move_x_options_negative),
|
||||
implode(" | ", move_x_options_positive)
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[{}] - [Y] + [{}]",
|
||||
implode(" | ", move_y_options_negative),
|
||||
implode(" | ", move_y_options_positive)
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[{}] - [Z] + [{}]",
|
||||
implode(" | ", move_z_options_negative),
|
||||
implode(" | ", move_z_options_positive)
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[{}] - [H] + [{}]",
|
||||
implode(" | ", move_h_options_negative),
|
||||
implode(" | ", move_h_options_positive)
|
||||
).c_str()
|
||||
);
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[{}] - [Size] + [{}]",
|
||||
implode(" | ", set_size_options_negative),
|
||||
implode(" | ", set_size_options_positive)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(Chat::Red, "Door selection invalid...");
|
||||
}
|
||||
|
||||
// create
|
||||
if (arg1 == "create") {
|
||||
std::string model = str_toupper(arg2);
|
||||
uint16 entity_id = entity_list.CreateDoor(
|
||||
model.c_str(),
|
||||
c->GetPosition(),
|
||||
58,
|
||||
100
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format("Creating door entity_id [{}] with model [{}]", entity_id, model).c_str());
|
||||
c->SetDoorToolEntityId(entity_id);
|
||||
}
|
||||
|
||||
// set model
|
||||
if (arg1 == "model") {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
std::string model = str_toupper(arg2);
|
||||
if (door) {
|
||||
door->SetDoorName(model.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// change model queue
|
||||
if (arg1 == "changemodelqueue") {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"#door model <modelname> | Changes door model for selected door or select from [{}] or [{}]",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door showmodelszone", false, "local zone"),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#door showmodelsglobal", false, "global")
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
// open type
|
||||
if (arg1 == "opentype" && !arg2.empty() && StringIsNumber(arg2)) {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
if (door) {
|
||||
door->SetOpenType(std::atoi(arg2.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// incline
|
||||
if (arg1 == "setincline" && !arg2.empty() && StringIsNumber(arg2)) {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
if (door) {
|
||||
door->SetIncline(std::atoi(arg2.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// incline
|
||||
if (arg1 == "setinvertstate" && !arg2.empty() && StringIsNumber(arg2)) {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
if (door) {
|
||||
door->SetInvertState(std::atoi(arg2.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// save
|
||||
if (arg1 == "save") {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
if (door) {
|
||||
door->CreateDatabaseEntry();
|
||||
c->Message(Chat::White, "Door saved");
|
||||
}
|
||||
}
|
||||
|
||||
// incline incremental
|
||||
if (arg1 == "setinclineinc" && !arg2.empty() && StringIsNumber(arg2)) {
|
||||
Doors *door = entity_list.GetDoorsByID(c->GetDoorToolEntityId());
|
||||
if (door) {
|
||||
door->SetIncline(door->GetIncline() + std::atoi(arg2.c_str()));
|
||||
}
|
||||
}
|
||||
if (arg1 == "setinclineinc") {
|
||||
std::map<float, std::string> incline_values = {
|
||||
{.01, "Upright"},
|
||||
{63.75, "45 Degrees",},
|
||||
{130, "90 Degrees"},
|
||||
{192.5, "135 Degrees"},
|
||||
{255, "180 Degrees"},
|
||||
{321.25, "225 Degrees"},
|
||||
{385, "270 Degrees"},
|
||||
{448.75, "315 Degrees"},
|
||||
{512.5, "360 Degrees"}
|
||||
};
|
||||
|
||||
std::vector<std::string> incline_normal_options;
|
||||
std::vector<std::string> incline_positive_options;
|
||||
std::vector<std::string> incline_negative_options;
|
||||
for (auto incline_value : incline_values) {
|
||||
incline_normal_options.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format(
|
||||
"#door setincline {}",
|
||||
incline_value.first
|
||||
),
|
||||
false,
|
||||
incline_value.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int incline_index = 0; incline_index <= 100; incline_index += 10) {
|
||||
int incline_value = (incline_index == 0 ? 1 : incline_index);
|
||||
incline_positive_options.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format(
|
||||
"#door setinclineinc {}",
|
||||
incline_value
|
||||
),
|
||||
false,
|
||||
itoa(std::abs(incline_value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (int incline_index = -100; incline_index <= 1; incline_index += 10) {
|
||||
int incline_value = (incline_index == 0 ? -1 : incline_index);
|
||||
incline_negative_options.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format(
|
||||
"#door setinclineinc {}",
|
||||
incline_value
|
||||
),
|
||||
false,
|
||||
itoa(std::abs(incline_value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[Incline] [{}]",
|
||||
implode(" | ", incline_normal_options)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"[Incline Increments] [{}] - | + [{}]",
|
||||
implode(" | ", incline_negative_options),
|
||||
implode(" | ", incline_positive_options)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
// show models in zone
|
||||
if (arg1 == "showmodelsglobal") {
|
||||
auto game_objects = ToolGameObjectsRepository::GetWhere(
|
||||
database,
|
||||
"object_name LIKE '%IT%' AND zoneid = 0 AND object_name NOT LIKE '%OBJ%' GROUP by file_from"
|
||||
);
|
||||
|
||||
if (game_objects.empty()) {
|
||||
c->Message(Chat::White, "There are no models to display...");
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
c->Message(Chat::White, "# Models (Global)");
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
|
||||
DisplayModelsFromFileResults(c, game_objects);
|
||||
}
|
||||
|
||||
// show models in zone
|
||||
if (arg1 == "showmodelszone") {
|
||||
auto game_objects = ToolGameObjectsRepository::GetWhere(
|
||||
database,
|
||||
fmt::format("zoneid = {}", zone->GetZoneID())
|
||||
);
|
||||
|
||||
if (game_objects.empty()) {
|
||||
c->Message(Chat::White, "There are no models for this zone...");
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
c->Message(Chat::White, "# Models from zone");
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
|
||||
DisplayObjectResultToClient(c, game_objects);
|
||||
}
|
||||
|
||||
// show models from file name
|
||||
if (arg1 == "showmodelsfromfile" && !arg2.empty()) {
|
||||
const std::string &file_name = arg2;
|
||||
auto game_objects = ToolGameObjectsRepository::GetWhere(
|
||||
database,
|
||||
fmt::format("file_from = '{}'", file_name)
|
||||
);
|
||||
|
||||
if (game_objects.empty()) {
|
||||
c->Message(Chat::White, "There are no models for this zone...");
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
c->Message(Chat::White, fmt::format("# Models from file name [{}]", file_name).c_str());
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
|
||||
DisplayObjectResultToClient(c, game_objects);
|
||||
}
|
||||
}
|
||||
|
||||
void DoorManipulation::CommandHeader(Client *c)
|
||||
{
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
c->Message(Chat::White, "# Door Commands");
|
||||
c->Message(Chat::White, "------------------------------------------------");
|
||||
}
|
||||
|
||||
void DoorManipulation::DisplayObjectResultToClient(
|
||||
Client *c,
|
||||
std::vector<ToolGameObjectsRepository::ToolGameObjects> game_objects
|
||||
)
|
||||
{
|
||||
std::vector<std::string> say_links;
|
||||
|
||||
for (auto &g: game_objects) {
|
||||
say_links.emplace_back(
|
||||
fmt::format(
|
||||
"[{}] ",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door model {}", g.object_name),
|
||||
false,
|
||||
g.object_name
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
int character_length = 0;
|
||||
std::vector<std::string> buffered_links;
|
||||
|
||||
for (auto &links: say_links) {
|
||||
buffered_links.emplace_back(links);
|
||||
character_length += links.length();
|
||||
|
||||
// empty buffer
|
||||
if (character_length > MAX_CLIENT_MESSAGE_LENGTH) {
|
||||
std::string message_buffer;
|
||||
|
||||
for (auto &buffered_link: buffered_links) {
|
||||
message_buffer += buffered_link;
|
||||
}
|
||||
|
||||
c->Message(Chat::White, message_buffer.c_str());
|
||||
|
||||
// reset
|
||||
character_length = 0;
|
||||
buffered_links = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffered_links.empty()) {
|
||||
c->Message(Chat::White, implode(" ", buffered_links).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void DoorManipulation::DisplayModelsFromFileResults(
|
||||
Client *c,
|
||||
std::vector<ToolGameObjectsRepository::ToolGameObjects> game_objects
|
||||
)
|
||||
{
|
||||
std::vector<std::string> say_links;
|
||||
|
||||
for (auto &g: game_objects) {
|
||||
say_links.emplace_back(
|
||||
fmt::format(
|
||||
"[{}] ",
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#door showmodelsfromfile {}", g.file_from),
|
||||
false,
|
||||
g.file_from
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
int character_length = 0;
|
||||
std::vector<std::string> buffered_links;
|
||||
|
||||
for (auto &links: say_links) {
|
||||
buffered_links.emplace_back(links);
|
||||
character_length += links.length();
|
||||
|
||||
// empty buffer
|
||||
if (character_length > MAX_CLIENT_MESSAGE_LENGTH) {
|
||||
std::string message_buffer;
|
||||
|
||||
for (auto &buffered_link: buffered_links) {
|
||||
message_buffer += buffered_link;
|
||||
}
|
||||
|
||||
c->Message(Chat::White, message_buffer.c_str());
|
||||
|
||||
// reset
|
||||
character_length = 0;
|
||||
buffered_links = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffered_links.empty()) {
|
||||
c->Message(Chat::White, implode(" ", buffered_links).c_str());
|
||||
}
|
||||
}
|
||||
23
zone/gm_commands/door_manipulation.h
Normal file
23
zone/gm_commands/door_manipulation.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef EQEMU_DOOR_MANIPULATION_H
|
||||
#define EQEMU_DOOR_MANIPULATION_H
|
||||
|
||||
#include "../client.h"
|
||||
#include "../../common/repositories/tool_game_objects_repository.h"
|
||||
|
||||
class DoorManipulation {
|
||||
|
||||
public:
|
||||
static void CommandHandler(Client *c, const Seperator *sep);
|
||||
static void CommandHeader(Client *c);
|
||||
static void DisplayObjectResultToClient(
|
||||
Client *c,
|
||||
std::vector<ToolGameObjectsRepository::ToolGameObjects> game_objects
|
||||
);
|
||||
static void DisplayModelsFromFileResults(
|
||||
Client *c,
|
||||
std::vector<ToolGameObjectsRepository::ToolGameObjects> game_objects
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_DOOR_MANIPULATION_H
|
||||
19
zone/npc.cpp
19
zone/npc.cpp
@ -284,7 +284,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
|
||||
entity_list.MakeNameUnique(name);
|
||||
|
||||
npc_aggro = npc_type_data->npc_aggro;
|
||||
|
||||
|
||||
AISpellVar.fail_recast = static_cast<uint32>(RuleI(Spells, AI_SpellCastFinishedFailRecast));
|
||||
AISpellVar.engaged_no_sp_recast_min = static_cast<uint32>(RuleI(Spells, AI_EngagedNoSpellMinRecast));
|
||||
AISpellVar.engaged_no_sp_recast_max = static_cast<uint32>(RuleI(Spells, AI_EngagedNoSpellMaxRecast));
|
||||
@ -694,7 +694,7 @@ bool NPC::HasItem(uint32 item_id) {
|
||||
if (loot_item->item_id == item_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1124,7 +1124,7 @@ bool NPC::SpawnZoneController()
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
|
||||
strncpy(npc_type->name, "zone_controller", 60);
|
||||
npc_type->current_hp = 2000000000;
|
||||
npc_type->current_hp = 2000000000;
|
||||
npc_type->max_hp = 2000000000;
|
||||
npc_type->hp_regen = 100000000;
|
||||
npc_type->race = 240;
|
||||
@ -1207,7 +1207,7 @@ void NPC::SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_id, int32 grid_
|
||||
entity_list.AddNPC(npc);
|
||||
}
|
||||
|
||||
void NPC::SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position)
|
||||
NPC * NPC::SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position)
|
||||
{
|
||||
auto npc_type = new NPCType;
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
@ -1235,6 +1235,8 @@ void NPC::SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position)
|
||||
npc_type->show_name = true;
|
||||
npc_type->findable = true;
|
||||
|
||||
strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1");
|
||||
|
||||
auto node_position = glm::vec4(position.x, position.y, position.z, position.w);
|
||||
auto npc = new NPC(npc_type, nullptr, node_position, GravityBehavior::Flying);
|
||||
|
||||
@ -1243,14 +1245,15 @@ void NPC::SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position)
|
||||
npc->GiveNPCTypeData(npc_type);
|
||||
|
||||
entity_list.AddNPC(npc);
|
||||
|
||||
return npc;
|
||||
}
|
||||
|
||||
NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position) {
|
||||
auto npc_type = new NPCType;
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
|
||||
sprintf(npc_type->name, "%s", name.c_str());
|
||||
sprintf(npc_type->lastname, "%s", last_name.c_str());
|
||||
strncpy(npc_type->name, name.c_str(), 60);
|
||||
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
@ -1272,9 +1275,13 @@ NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4
|
||||
npc_type->findable = true;
|
||||
npc_type->runspeed = 1.25;
|
||||
|
||||
strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1");
|
||||
|
||||
auto node_position = glm::vec4(position.x, position.y, position.z, position.w);
|
||||
auto npc = new NPC(npc_type, nullptr, node_position, GravityBehavior::Flying);
|
||||
|
||||
npc->name[strlen(npc->name) - 3] = (char) NULL;
|
||||
|
||||
npc->GiveNPCTypeData(npc_type);
|
||||
|
||||
entity_list.AddNPC(npc, true, true);
|
||||
|
||||
@ -115,7 +115,7 @@ public:
|
||||
|
||||
static NPC *SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position);
|
||||
static void SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_id, int32 grid_number, int32 zoffset);
|
||||
static void SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position);
|
||||
static NPC * SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position);
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQ::skills::SkillType attack_skill);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user