diff --git a/changelog.txt b/changelog.txt index 716325c2d..324974969 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 9/04/2019 == +Uleat: Added code to restore rule notes to their original values + - The code is inactive by default + - Change rule 'World:RestoreRuleNotes' to 'true' to enable this feature + - Rule will not exist until the server is run for the first time after updating + == 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 diff --git a/common/rulesys.cpp b/common/rulesys.cpp index ecf8cf6cd..413755df8 100644 --- a/common/rulesys.cpp +++ b/common/rulesys.cpp @@ -215,15 +215,17 @@ bool RuleManager::_FindRule(const char *rule_name, RuleType &type_into, uint16 & //assumes index is valid! const char *RuleManager::_GetRuleName(RuleType type, uint16 index) { switch (type) { - case IntRule: - return(s_RuleInfo[index].name); - case RealRule: - return(s_RuleInfo[index + _IntRuleCount].name); - case BoolRule: - return(s_RuleInfo[index + _IntRuleCount + _RealRuleCount].name); + case IntRule: + return(s_RuleInfo[index].name); + case RealRule: + return(s_RuleInfo[index+_IntRuleCount].name); + case BoolRule: + return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].name); + default: + break; } //should never happen - return("InvalidRule??"); + return(s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount].name); // no need to create a string when one already exists... } //assumes index is valid! @@ -232,12 +234,14 @@ const std::string &RuleManager::_GetRuleNotes(RuleType type, uint16 index) { case IntRule: return(s_RuleInfo[index].notes); case RealRule: - return(s_RuleInfo[index + _IntRuleCount].notes); + return(s_RuleInfo[index+_IntRuleCount].notes); case BoolRule: - return(s_RuleInfo[index + _IntRuleCount + _RealRuleCount].notes); + return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].notes); + default: + break; } //should never happen - return(std::string()); + return(s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount].notes); } bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool reload) { @@ -304,12 +308,8 @@ bool RuleManager::LoadRules(Database *database, const char *ruleset_name, bool r 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 if (m_activeName != ruleset_name) { @@ -328,10 +328,6 @@ 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); @@ -377,11 +373,6 @@ void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) { 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 database_data; @@ -472,11 +463,33 @@ bool RuleManager::UpdateInjectedRules(Database *db, const char *ruleset_name, bo } if (injected_rule_entries.size()) { - return _UpdateRules(db, ruleset_name, ruleset_id, injected_rule_entries, std::vector()); - } - else { - return true; + + std::string query( + fmt::format( + "REPLACE INTO `rule_values`(`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}", + implode( + ",", + std::pair('(', ')'), + join_tuple(",", std::pair('\'', '\''), injected_rule_entries) + ) + ) + ); + + if (!db->QueryDatabase(query).Success()) { + return false; + } + + Log(Logs::General, + Logs::Status, + "%u New Rule%s Added to ruleset '%s' (%i)", + injected_rule_entries.size(), + (injected_rule_entries.size() == 1 ? "" : "s"), + ruleset_name, + ruleset_id + ); } + + return true; } bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update) @@ -524,113 +537,83 @@ bool RuleManager::UpdateOrphanedRules(Database *db, bool quiet_update) } if (orphaned_rule_entries.size()) { - return _UpdateRules( - db, - "All Rulesets", - -1, - std::vector>(), - orphaned_rule_entries + + std::string query ( + fmt::format( + "DELETE FROM `rule_values` WHERE `rule_name` IN ({})", + implode(",", std::pair('\'', '\''), orphaned_rule_entries) + ) + ); + + if (!db->QueryDatabase(query).Success()) { + return false; + } + + Log(Logs::General, + Logs::Status, + "%u Orphaned Rule%s Deleted from 'All Rulesets' (-1)", + orphaned_rule_entries.size(), + (orphaned_rule_entries.size() == 1 ? "" : "s") ); } - else { - return true; - } + + return true; } -bool RuleManager::_UpdateRules( - Database *db, - const char *ruleset_name, - const int ruleset_id, - const std::vector> &injected, - const std::vector &orphaned -) +bool RuleManager::RestoreRuleNotes(Database *db) { - bool return_value = true; - if (!db) { return false; } - if (ruleset_name == nullptr) { + std::string query("SELECT `ruleset_id`, `rule_name`, IFNULL(`notes`, '\\0')`notes` FROM `rule_values`"); + + auto results = db->QueryDatabase(query); + if (!results.Success()) { return false; } - if (injected.size()) { + int update_count = 0; + for (auto row = results.begin(); row != results.end(); ++row) { - if (ruleset_id >= 0 && strcasecmp(ruleset_name, "All Rulesets") != 0) { + const auto &rule = [&row]() { - std::string query( - fmt::format( - "REPLACE INTO `rule_values`(`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}", - implode( - ",", - std::pair('(', ')'), - join_tuple(",", std::pair('\'', '\''), 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 - ); + for (const auto &rule_iter : s_RuleInfo) { + if (strcasecmp(rule_iter.name, row[1]) == 0) { + return rule_iter; + } } + + return s_RuleInfo[_IntRuleCount+_RealRuleCount+_BoolRuleCount]; + }(); + + if (strcasecmp(rule.name, row[1]) != 0) { + continue; } - else { - return_value = false; + + if (rule.notes.compare(row[2]) == 0) { + continue; } - } - if (orphaned.size()) { + std::string query( + StringFormat( + "UPDATE `rule_values` SET `notes` = '%s' WHERE `ruleset_id` = '%i' AND `rule_name` = '%s'", + rule.notes.c_str(), + atoi(row[0]), + row[1] + ) + ); - 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('\'', '\''), 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('\'', '\''), orphaned) - ); + if (!db->QueryDatabase(query).Success()) { + continue; } - 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; - } + ++update_count; } - return return_value; + if (update_count > 0) { + Log(Logs::General, Logs::Status, "%u Rule Note%s Restored", update_count, (update_count == 1 ? "" : "s")); + } } int RuleManager::GetRulesetID(Database *database, const char *ruleset_name) { diff --git a/common/rulesys.h b/common/rulesys.h index 4ade97983..e9d3365fe 100644 --- a/common/rulesys.h +++ b/common/rulesys.h @@ -97,6 +97,9 @@ public: static const char *GetRuleName(IntType t) { return(s_RuleInfo[t].name); } static const char *GetRuleName(RealType t) { return(s_RuleInfo[t+_IntRuleCount].name); } static const char *GetRuleName(BoolType t) { return(s_RuleInfo[t+_IntRuleCount+_RealRuleCount].name); } + static const std::string &GetRuleNotes(IntType t) { return(s_RuleInfo[t].notes); } + static const std::string &GetRuleNotes(RealType t) { return(s_RuleInfo[t+_IntRuleCount].notes); } + static const std::string &GetRuleNotes(BoolType t) { return(s_RuleInfo[t+_IntRuleCount+_RealRuleCount].notes); } static uint32 CountRules() { return(_RulesCount); } static CategoryType FindCategory(const char *catname); bool ListRules(const char *catname, std::vector &into); @@ -113,9 +116,9 @@ public: void ResetRules(bool reload = false); bool LoadRules(Database *db, const char *ruleset = nullptr, bool reload = false); void SaveRules(Database *db, const char *ruleset = nullptr); - bool 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); + bool RestoreRuleNotes(Database *db); private: RuleManager(); @@ -143,21 +146,14 @@ private: 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> &injected, - const std::vector &orphaned - ); - + static const char *s_categoryNames[]; typedef struct { const char *name; CategoryType category; RuleType type; uint16 rule_index; //index into its 'type' array - std::string notes; + const std::string notes; } RuleInfo; static const RuleInfo s_RuleInfo[]; diff --git a/common/ruletypes.h b/common/ruletypes.h index b8581e9f4..0e3f3cdc5 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -241,6 +241,7 @@ RULE_BOOL(World, MaxClientsSimplifiedLogic, false, "New logic that only uses Exe RULE_INT (World, TellQueueSize, 20, "") RULE_BOOL(World, StartZoneSameAsBindOnCreation, true, "Should the start zone ALWAYS be the same location as your bind?") RULE_BOOL(World, EnforceCharacterLimitAtLogin, false, "") +RULE_BOOL(World, RestoreRuleNotes, false, "Restores all database rule entry notes to their original text") RULE_CATEGORY_END() RULE_CATEGORY(Zone) diff --git a/world/net.cpp b/world/net.cpp index f85c1b387..2a2a25d05 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -335,13 +335,13 @@ int main(int argc, char** argv) { //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."); } + + if (!RuleManager::Instance()->UpdateInjectedRules(&database, "default")) { + Log(Logs::General, Logs::World_Server, "Failed to process 'Injected Rules' for ruleset 'default' update operation."); + } std::string tmp; if (database.GetVariable("RuleSet", tmp)) { @@ -361,6 +361,10 @@ int main(int argc, char** argv) { Log(Logs::General, Logs::World_Server, "Loaded default rule set 'default'", tmp.c_str()); } } + + if (RuleB(World, RestoreRuleNotes) && !RuleManager::Instance()->RestoreRuleNotes(&database)) { + Log(Logs::General, Logs::World_Server, "Failed to process 'Restore Rule Notes' update operation."); + } } EQEmu::InitializeDynamicLookups();