mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Updated the rule system to automatically add new rules and remove orphaned entries from the rule values tables
This commit is contained in:
parent
a534ab83ec
commit
f9536f9621
@ -1,5 +1,16 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 9/02/2019 ==
|
||||
Uleat: Added code to inject new rules into the 'default' ruleset and remove orphaned rules from all rulesets
|
||||
- New rules are only added using the 'default' ruleset - Other rulesets will need to be added manually or through in-game updates
|
||||
-- Rule notes are now loaded into the system's hard-coded entries and will now propagate properly into database updates
|
||||
- Defunct rules will have their orhpaned entries removed from the `rule_values` table for the all rulesets
|
||||
|
||||
Note: If you would like to add these rules before starting your server so that you can modify them, start world.exe
|
||||
manually and wait for the console messages to finish. It should take 5-10 seconds, or so. The world log should contain
|
||||
a list of the added and removed entries, IF the `file` field of the 'Status' logging category is set to 1 or higher.
|
||||
(Don't forget to manually stop the process after the update is complete.)
|
||||
|
||||
== 8/30/2019 ==
|
||||
Uleat: Added code to inject new commands and remove orphaned commands from both command systems
|
||||
- New commands are added with their status (`access`) set to the server default value - no aliases are defined
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "string_util.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
|
||||
/*
|
||||
Commands:
|
||||
@ -45,14 +46,14 @@ const char *RuleManager::s_categoryNames[_CatCount+1] = {
|
||||
|
||||
const RuleManager::RuleInfo RuleManager::s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount+1] = {
|
||||
/* this is done in three steps so we can reliably get to them by index*/
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, IntRule, Int__##rule },
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, IntRule, Int__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, RealRule, Real__##rule },
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, RealRule, Real__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
{ #cat ":" #rule, Category__##cat, BoolRule, Bool__##rule },
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
{ #cat ":" #rule, Category__##cat, BoolRule, Bool__##rule, notes },
|
||||
#include "ruletypes.h"
|
||||
{ "Invalid Rule", _CatCount, IntRule }
|
||||
};
|
||||
@ -178,11 +179,11 @@ void RuleManager::ResetRules(bool reload) {
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Resetting running rules to default values");
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
m_RuleIntValues[ Int__##rule ] = default_value;
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
m_RuleRealValues[ Real__##rule ] = default_value;
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
m_RuleBoolValues[ Bool__##rule ] = default_value;
|
||||
#include "ruletypes.h"
|
||||
|
||||
@ -225,7 +226,89 @@ const char *RuleManager::_GetRuleName(RuleType type, uint16 index) {
|
||||
return("InvalidRule??");
|
||||
}
|
||||
|
||||
//assumes index is valid!
|
||||
const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) {
|
||||
switch (type) {
|
||||
case IntRule:
|
||||
return(s_RuleInfo[index].notes);
|
||||
case RealRule:
|
||||
return(s_RuleInfo[index + _IntRuleCount].notes);
|
||||
case BoolRule:
|
||||
return(s_RuleInfo[index + _IntRuleCount + _RealRuleCount].notes);
|
||||
}
|
||||
//should never happen
|
||||
return(std::string());
|
||||
}
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
|
||||
return (false);
|
||||
}
|
||||
|
||||
m_activeRuleset = ruleset_id;
|
||||
m_activeName = ruleset_name;
|
||||
|
||||
/* Load default ruleset values first if we're loading something other than default */
|
||||
if (strcasecmp(ruleset_name, "default") != 0) {
|
||||
|
||||
std::string default_ruleset_name = "default";
|
||||
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
|
||||
|
||||
if (default_ruleset_id < 0) {
|
||||
Log(Logs::Detail,
|
||||
Logs::Rules,
|
||||
"Failed to find default ruleset '%s' for load operation. Canceling.",
|
||||
default_ruleset_name.c_str()
|
||||
);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Processing rule set '%s' (%d) load...", default_ruleset_name.c_str(), default_ruleset_id);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT `rule_name`, `rule_value` FROM `rule_values` WHERE `ruleset_id` = '%d'",
|
||||
default_ruleset_id
|
||||
);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload)) {
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for '%s'", row[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Processing rule set '%s' (%d) load...", ruleset_name, ruleset_id);
|
||||
|
||||
std::string query = StringFormat("SELECT `rule_name`, `rule_value` FROM `rule_values` WHERE `ruleset_id` = '%d'", ruleset_id);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload)) {
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for '%s'", row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// convert this to a single REPLACE query (it can handle it - currently at 608 rules)
|
||||
void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
// tbh, UpdateRules() can probably be called since it will handle deletions of
|
||||
// orphaned entries of existing rulesets as well as adding the new ones
|
||||
// (it already does it as a single REPLACE query)
|
||||
|
||||
if (ruleset_name != nullptr) {
|
||||
//saving to a specific name
|
||||
@ -245,6 +328,10 @@ void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
Log(Logs::Detail, Logs::Rules, "Saving running rules into running rule set %s", m_activeName.c_str(), m_activeRuleset);
|
||||
}
|
||||
|
||||
// this should be all that is needed..with the exception of handling expansion-based rules...
|
||||
// (those really need to be put somewhere else - probably variables)
|
||||
//UpdateRules(database, m_activeName.c_str(), m_activeRuleset, true);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < _IntRuleCount; i++) {
|
||||
_SaveRule(database, IntRule, i);
|
||||
@ -257,56 +344,6 @@ void RuleManager::SaveRules(Database *database, const char *ruleset_name) {
|
||||
}
|
||||
}
|
||||
|
||||
bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) {
|
||||
|
||||
int ruleset_id = this->GetRulesetID(database, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name);
|
||||
return (false);
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", ruleset_name, ruleset_id);
|
||||
|
||||
m_activeRuleset = ruleset_id;
|
||||
m_activeName = ruleset_name;
|
||||
|
||||
/* Load default ruleset values first if we're loading something other than default */
|
||||
if (strcasecmp(ruleset_name, "default") != 0) {
|
||||
std::string default_ruleset_name = "default";
|
||||
int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str());
|
||||
if (default_ruleset_id < 0) {
|
||||
Log(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.",
|
||||
default_ruleset_name.c_str());
|
||||
return (false);
|
||||
}
|
||||
Log(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name.c_str(), default_ruleset_id);
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d",
|
||||
default_ruleset_id
|
||||
);
|
||||
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload))
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
|
||||
}
|
||||
|
||||
std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id);
|
||||
auto results = database->QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (!SetRule(row[0], row[1], nullptr, false, reload))
|
||||
Log(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
char value_string[100];
|
||||
|
||||
@ -328,17 +365,273 @@ void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) {
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO rule_values "
|
||||
"(ruleset_id, rule_name, rule_value) "
|
||||
" VALUES(%d, '%s', '%s')",
|
||||
"REPLACE INTO `rule_values`"
|
||||
"(`ruleset_id`, `rule_name`, `rule_value`, `notes`)"
|
||||
" VALUES('%d', '%s', '%s', '%s')",
|
||||
m_activeRuleset,
|
||||
_GetRuleName(type, index),
|
||||
value_string
|
||||
value_string,
|
||||
EscapeString(_GetRuleNotes(type, index)).c_str()
|
||||
);
|
||||
|
||||
database->QueryDatabase(query);
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateChangedRules(Database *db, const char *ruleset_name, bool quiet_update)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bool quiet_update)
|
||||
{
|
||||
std::vector<std::string> database_data;
|
||||
std::map<std::string, std::pair<std::string, const std::string *>> rule_data;
|
||||
std::vector<std::tuple<int, std::string, std::string, std::string>> injected_rule_entries;
|
||||
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ruleset_name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ruleset_id = GetRulesetID(db, ruleset_name);
|
||||
if (ruleset_id < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load database rule names
|
||||
std::string query(StringFormat("SELECT `rule_name` FROM `rule_values` WHERE `ruleset_id` = '%i'", ruleset_id));
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build database data entries
|
||||
for (auto &row : results) {
|
||||
database_data.push_back(std::string(row[0]));
|
||||
}
|
||||
|
||||
// build rule data entries
|
||||
for (const auto &ri_iter : s_RuleInfo) {
|
||||
if (strcasecmp(ri_iter.name, "Invalid Rule") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char buffer[100];
|
||||
|
||||
switch (ri_iter.type) {
|
||||
case IntRule:
|
||||
sprintf(buffer, "%d", m_RuleIntValues[ri_iter.rule_index]);
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
case RealRule:
|
||||
sprintf(buffer, "%.13f", m_RuleRealValues[ri_iter.rule_index]);
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
case BoolRule:
|
||||
sprintf(buffer, "%s", (m_RuleBoolValues[ri_iter.rule_index] ? "true" : "false"));
|
||||
rule_data[ri_iter.name].first = buffer;
|
||||
rule_data[ri_iter.name].second = &ri_iter.notes;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// build injected entries
|
||||
for (const auto &rd_iter : rule_data) {
|
||||
|
||||
const auto &dd_iter = std::find(database_data.begin(), database_data.end(), rd_iter.first);
|
||||
if (dd_iter == database_data.end()) {
|
||||
|
||||
injected_rule_entries.push_back(
|
||||
std::tuple<int, std::string, std::string, std::string>(
|
||||
ruleset_id, // `ruleset_id`
|
||||
rd_iter.first, // `rule_name`
|
||||
rd_iter.second.first, // `rule_value`
|
||||
EscapeString(*rd_iter.second.second) // `notes`
|
||||
)
|
||||
);
|
||||
|
||||
if (!quiet_update) {
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"New Rule '%s' found... Adding to `rule_values` table with ruleset '%s' (%i) and rule value '%s'...",
|
||||
rd_iter.first.c_str(),
|
||||
ruleset_name,
|
||||
ruleset_id,
|
||||
rd_iter.second.first.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (injected_rule_entries.size()) {
|
||||
return _UpdateRules(db, ruleset_name, ruleset_id, injected_rule_entries, std::vector<std::string>());
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update)
|
||||
{
|
||||
std::vector<std::string> rule_data;
|
||||
std::vector<std::string> orphaned_rule_entries;
|
||||
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load database rule names
|
||||
std::string query("SELECT `rule_name` FROM `rule_values` GROUP BY `rule_name`");
|
||||
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build rule data entries
|
||||
for (const auto &ri_iter : s_RuleInfo) {
|
||||
if (strcasecmp(ri_iter.name, "Invalid Rule") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rule_data.push_back(ri_iter.name);
|
||||
}
|
||||
|
||||
// build orphaned entries
|
||||
for (auto &row : results) {
|
||||
|
||||
const auto &rd_iter = std::find(rule_data.begin(), rule_data.end(), row[0]);
|
||||
if (rd_iter == rule_data.end()) {
|
||||
|
||||
orphaned_rule_entries.push_back(std::string(row[0]));
|
||||
|
||||
if (!quiet_update) {
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"Rule '%s' no longer exists... Deleting orphaned entry from `rule_values` table...",
|
||||
row[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (orphaned_rule_entries.size()) {
|
||||
return _UpdateRules(
|
||||
db,
|
||||
"All Rulesets",
|
||||
-1,
|
||||
std::vector<std::tuple<int, std::string, std::string, std::string>>(),
|
||||
orphaned_rule_entries
|
||||
);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool RuleManager::_UpdateRules(
|
||||
Database *db,
|
||||
const char *ruleset_name,
|
||||
const int ruleset_id,
|
||||
const std::vector<std::tuple<int, std::string, std::string, std::string>> &injected,
|
||||
const std::vector<std::string> &orphaned
|
||||
)
|
||||
{
|
||||
bool return_value = true;
|
||||
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ruleset_name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (injected.size()) {
|
||||
|
||||
if (ruleset_id >= 0 && strcasecmp(ruleset_name, "All Rulesets") != 0) {
|
||||
|
||||
std::string query(
|
||||
fmt::format(
|
||||
"REPLACE INTO `rule_values`(`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}",
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_tuple(",", std::pair<char, char>('\'', '\''), injected)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
return_value = false;
|
||||
}
|
||||
else {
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"%u New Command%s Added to ruleset '%s' (%i)",
|
||||
injected.size(),
|
||||
(injected.size() == 1 ? "" : "s"),
|
||||
ruleset_name,
|
||||
ruleset_id
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (orphaned.size()) {
|
||||
|
||||
std::string query;
|
||||
|
||||
if (ruleset_id < 0 && strcasecmp(ruleset_name, "All Rulesets") == 0) {
|
||||
|
||||
query = fmt::format(
|
||||
"DELETE FROM `rule_values` WHERE `rule_name` IN ({})",
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned)
|
||||
);
|
||||
}
|
||||
else if (ruleset_id >= 0 && strcasecmp(ruleset_name, "All Rulesets") != 0) {
|
||||
|
||||
query = fmt::format(
|
||||
"DELETE FROM `rule_values` WHERE `ruleset_id` = '%i' AND `rule_name` IN ({})",
|
||||
ruleset_id,
|
||||
implode(",", std::pair<char, char>('\'', '\''), orphaned)
|
||||
);
|
||||
}
|
||||
|
||||
if (query.size() > 0) {
|
||||
|
||||
if (!db->QueryDatabase(query).Success()) {
|
||||
return_value = false;
|
||||
}
|
||||
else {
|
||||
Log(Logs::General,
|
||||
Logs::Status,
|
||||
"%u Orphaned Command%s Deleted from ruleset '%s' (%i)",
|
||||
orphaned.size(),
|
||||
(orphaned.size() == 1 ? "" : "s"),
|
||||
ruleset_name,
|
||||
ruleset_id
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
int RuleManager::GetRulesetID(Database *database, const char *ruleset_name) {
|
||||
|
||||
|
||||
@ -49,21 +49,21 @@ class RuleManager {
|
||||
public:
|
||||
//generate our rule enums:
|
||||
typedef enum {
|
||||
#define RULE_INT(cat, rule, default_value) \
|
||||
#define RULE_INT(cat, rule, default_value, notes) \
|
||||
Int__##rule,
|
||||
#include "ruletypes.h"
|
||||
_IntRuleCount
|
||||
} IntType;
|
||||
|
||||
typedef enum {
|
||||
#define RULE_REAL(cat, rule, default_value) \
|
||||
#define RULE_REAL(cat, rule, default_value, notes) \
|
||||
Real__##rule,
|
||||
#include "ruletypes.h"
|
||||
_RealRuleCount
|
||||
} RealType;
|
||||
|
||||
typedef enum {
|
||||
#define RULE_BOOL(cat, rule, default_value) \
|
||||
#define RULE_BOOL(cat, rule, default_value, notes) \
|
||||
Bool__##rule,
|
||||
#include "ruletypes.h"
|
||||
_BoolRuleCount
|
||||
@ -113,6 +113,9 @@ public:
|
||||
void ResetRules(bool reload = false);
|
||||
bool LoadRules(Database *db, const char *ruleset = nullptr, bool reload = false);
|
||||
void SaveRules(Database *db, const char *ruleset = nullptr);
|
||||
bool UpdateChangedRules(Database *db, const char *ruleset_name, bool quiet_update = false);
|
||||
bool UpdateInjectedRules(Database *db, const char *ruleset_name, bool quiet_update = false);
|
||||
bool UpdateOrphanedRules(Database *db, bool quiet_update = false);
|
||||
|
||||
private:
|
||||
RuleManager();
|
||||
@ -137,8 +140,16 @@ private:
|
||||
|
||||
static bool _FindRule(const char *rule_name, RuleType &type_into, uint16 &index_into);
|
||||
static const char *_GetRuleName(RuleType type, uint16 index);
|
||||
static const std::string &_GetRuleNotes(RuleType type, uint16 index);
|
||||
static int _FindOrCreateRuleset(Database *db, const char *ruleset);
|
||||
void _SaveRule(Database *db, RuleType type, uint16 index);
|
||||
bool _UpdateRules(
|
||||
Database *db,
|
||||
const char *ruleset_name,
|
||||
const int ruleset_id,
|
||||
const std::vector<std::tuple<int, std::string, std::string, std::string>> &injected,
|
||||
const std::vector<std::string> &orphaned
|
||||
);
|
||||
|
||||
static const char *s_categoryNames[];
|
||||
typedef struct {
|
||||
@ -146,6 +157,7 @@ private:
|
||||
CategoryType category;
|
||||
RuleType type;
|
||||
uint16 rule_index; //index into its 'type' array
|
||||
std::string notes;
|
||||
} RuleInfo;
|
||||
static const RuleInfo s_RuleInfo[];
|
||||
|
||||
|
||||
1222
common/ruletypes.h
1222
common/ruletypes.h
File diff suppressed because it is too large
Load Diff
@ -1481,12 +1481,7 @@ bool SharedDatabase::UpdateCommandSettings(const std::vector<std::pair<std::stri
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_pair(
|
||||
",",
|
||||
std::pair<char, char>('\'', '\''),
|
||||
std::pair<char, char>('\'', '\''),
|
||||
injected
|
||||
)
|
||||
join_pair(",", std::pair<char, char>('\'', '\''), injected)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
#include <tuple>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
@ -33,27 +34,27 @@ const std::string vStringFormat(const char* format, va_list args);
|
||||
std::string implode(std::string glue, std::vector<std::string> src);
|
||||
|
||||
template <typename T>
|
||||
std::string implode(std::string glue, std::pair<char, char> encapsulation, std::vector<T> src)
|
||||
std::string implode(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ostringstream output;
|
||||
std::ostringstream oss;
|
||||
|
||||
for (const T &src_iter : src) {
|
||||
output << encapsulation.first << src_iter << encapsulation.second << glue;
|
||||
oss << encapsulation.first << src_iter << encapsulation.second << glue;
|
||||
}
|
||||
|
||||
std::string final_output = output.str();
|
||||
final_output.resize(output.str().size() - glue.size());
|
||||
|
||||
return final_output;
|
||||
std::string output(oss.str());
|
||||
output.resize(output.size() - glue.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// this requires that #include<fmt/format.h> be included in whatever file the invocation is made from
|
||||
// this requires that #include<fmt/format.h> be included in whatever code file the invocation is made from
|
||||
template <typename T1, typename T2>
|
||||
std::vector<std::string> join_pair(std::string glue, std::pair<char, char> first_encap, std::pair<char, char> second_encap, std::vector<std::pair<T1, T2>> src)
|
||||
std::vector<std::string> join_pair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::pair<T1, T2>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
@ -65,17 +66,55 @@ std::vector<std::string> join_pair(std::string glue, std::pair<char, char> first
|
||||
output.push_back(
|
||||
// There are issues with including <fmt/format.h> in a header file that result in compile
|
||||
// failure. I'm not sure if this applies only within the same project or across projects.
|
||||
// Since templates act similar to macros in regards to initialization, this call should be
|
||||
// safe so long as the '#include<fmt/format.h>' rule above is observed.
|
||||
// Since templates act similar to macros in regards to initialization, this definition
|
||||
// should be safe so long as the '#include<fmt/format.h>' rule above is observed.
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}",
|
||||
first_encap.first,
|
||||
encapsulation.first,
|
||||
src_iter.first,
|
||||
first_encap.second,
|
||||
encapsulation.second,
|
||||
glue,
|
||||
second_encap.first,
|
||||
encapsulation.first,
|
||||
src_iter.second,
|
||||
second_encap.second
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// this requires that #include<fmt/format.h> be included in whatever code file the invocation is made from
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
std::vector<std::string> join_tuple(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::tuple<T1, T2, T3, T4>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::tuple<T1, T2, T3, T4> &src_iter : src) {
|
||||
|
||||
output.push_back(
|
||||
// note: see join_pair(...)
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
std::get<0>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<1>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<2>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<3>(src_iter),
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -332,16 +332,28 @@ int main(int argc, char** argv) {
|
||||
Log(Logs::General, Logs::World_Server, "Error: Could not load skill cap data. But ignoring");
|
||||
Log(Logs::General, Logs::World_Server, "Loading guilds..");
|
||||
guild_mgr.LoadGuilds();
|
||||
|
||||
//rules:
|
||||
{
|
||||
if (!RuleManager::Instance()->UpdateInjectedRules(&database, "default")) {
|
||||
Log(Logs::General, Logs::World_Server, "Failed to process 'Injected Rules' for ruleset 'default' update operation.");
|
||||
}
|
||||
|
||||
if (!RuleManager::Instance()->UpdateOrphanedRules(&database)) {
|
||||
Log(Logs::General, Logs::World_Server, "Failed to process 'Orphaned Rules' update operation.");
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
if (database.GetVariable("RuleSet", tmp)) {
|
||||
|
||||
Log(Logs::General, Logs::World_Server, "Loading rule set '%s'", tmp.c_str());
|
||||
|
||||
if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) {
|
||||
Log(Logs::General, Logs::World_Server, "Failed to load ruleset '%s', falling back to defaults.", tmp.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
|
||||
Log(Logs::General, Logs::World_Server, "No rule set configured, using default rules");
|
||||
}
|
||||
@ -349,18 +361,16 @@ int main(int argc, char** argv) {
|
||||
Log(Logs::General, Logs::World_Server, "Loaded default rule set 'default'", tmp.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
EQEmu::InitializeDynamicLookups();
|
||||
Log(Logs::General, Logs::World_Server, "Initialized dynamic dictionary entries");
|
||||
}
|
||||
|
||||
EQEmu::InitializeDynamicLookups();
|
||||
Log(Logs::General, Logs::World_Server, "Initialized dynamic dictionary entries");
|
||||
|
||||
if (RuleB(World, ClearTempMerchantlist)) {
|
||||
Log(Logs::General, Logs::World_Server, "Clearing temporary merchant lists..");
|
||||
database.ClearMerchantTemp();
|
||||
}
|
||||
|
||||
RuleManager::Instance()->SaveRules(&database);
|
||||
|
||||
Log(Logs::General, Logs::World_Server, "Loading EQ time of day..");
|
||||
TimeOfDay_Struct eqTime;
|
||||
time_t realtime;
|
||||
|
||||
@ -65,12 +65,7 @@ bool BotDatabase::UpdateBotCommandSettings(const std::vector<std::pair<std::stri
|
||||
implode(
|
||||
",",
|
||||
std::pair<char, char>('(', ')'),
|
||||
join_pair(
|
||||
",",
|
||||
std::pair<char, char>('\'', '\''),
|
||||
std::pair<char, char>('\'', '\''),
|
||||
injected
|
||||
)
|
||||
join_pair(",", std::pair<char, char>('\'', '\''), injected)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user