eqemu-server/common/content/world_content_service_rulesets.cpp
2025-07-26 20:04:50 -05:00

982 lines
25 KiB
C++

#include "world_content_service.h"
#include "../repositories/rule_sets_repository.h"
#include "../repositories/rule_values_repository.h"
// RuleSet is a struct that contains a ruleset and its associated rules.
struct RuleSet {
RuleSetsRepository::RuleSets rule_set;
std::vector<RuleValuesRepository::RuleValues> rules;
};
inline RuleSet GetClassicRuleset()
{
return {
.rule_set = {
.ruleset_id = 100,
.name = "Original (Classic)",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::Classic,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "Classic client-based ruleset",
},
.rules = {
{
.rule_name = "Character:EnableXTargetting",
.rule_value = "false",
.notes = "Added in Call of the Forsaken"
},
{
.rule_name = "Character:LeaveCorpses",
.rule_value = "true",
.notes = "Leave corpses behind"
},
{
.rule_name = "Character:LeaveNakedCorpses",
.rule_value = "false",
.notes = "Gear left on corpses until SoD"
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "50",
.notes = "Level 50 cap until Kunark"
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "50",
.notes = "Level 50 cap until Kunark"
},
{
.rule_name = "Character:RestRegenEnabled",
.rule_value = "false",
.notes = "OoC regen not added until TSS"
},
{
.rule_name = "Character:SharedBankPlat",
.rule_value = "false",
.notes = "No shared bank until LoY"
},
{
.rule_name = "Character:StatCap",
.rule_value = "255",
.notes = "Classic stat cap is 255"
},
{
.rule_name = "Character:UseOldBindWound",
.rule_value = "true",
.notes = ""
},
{
.rule_name = "Character:UseOldClassExpPenalties",
.rule_value = "true",
.notes = "Exp penalties removed in SoF"
},
{
.rule_name = "Character:UseOldConSystem",
.rule_value = "true",
.notes = "Con system changed in SoF"
},
{
.rule_name = "Character:UseOldRaceExpPenalties",
.rule_value = "true",
.notes = "Exp penalties removed in SoF"
},
{
.rule_name = "Character:UseOldRaceRezEffects",
.rule_value = "true",
.notes = "May need testing to ensure it can't be dispelled"
},
{
.rule_name = "Character:UseRaceClassExpBonuses",
.rule_value = "true",
.notes = ""
},
{
.rule_name = "Chat:EnableVoiceMacros",
.rule_value = "false",
.notes = "Introduced in GoD"
},
{
.rule_name = "Chat:ServerWideAuction",
.rule_value = "false",
.notes = "Disable Server-Wide Auction Chat"
},
{
.rule_name = "Chat:ServerWideOOC",
.rule_value = "false",
.notes = "Disable Server-Wide OOC Chat"
},
{
.rule_name = "Combat:ClassicNPCBackstab",
.rule_value = "true",
.notes = "Disables front backstab"
},
{
.rule_name = "Mail:EnableMailSystem",
.rule_value = "false",
.notes = "Mail system added in DoN"
},
{
.rule_name = "Spells:PreNerfBardAEDoT",
.rule_value = "true",
.notes = "Bard AE nerf not added until OoW"
},
{
.rule_name = "Spells:WizCritLevel",
.rule_value = "65",
.notes = "Wiz non-AA crits not until Luclin"
},
{
.rule_name = "TaskSystem:EnableTaskSystem",
.rule_value = "false",
.notes = "Task system added in OoW"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "0",
.notes = "Classic Client-Based Expansion Setting"
},
{
.rule_name = "World:EnableReturnHomeButton",
.rule_value = "false",
.notes = "Return Home added in DoN"
},
{
.rule_name = "World:EnableTutorialButton",
.rule_value = "false",
.notes = "Tutorial added in DoN"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "0",
.notes = "Classic Client-Based Expansion Setting"
},
}
};
}
inline RuleSet GetKunarkRuleset()
{
return {
.rule_set = {
.ruleset_id = 101,
.name = "Ruins of Kunark",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::TheRuinsOfKunark,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "Kunark client-based ruleset. Level 60 cap until PoP.",
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "1",
.notes = "Current Expansion"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "1",
.notes = "Kunark Client-Based Expansion Setting"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "1",
.notes = "Kunark Client-Based Expansion Setting"
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "60",
.notes = "Level 60 cap until PoP"
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "60",
.notes = "Level 60 cap until PoP"
},
}
};
}
inline RuleSet GetVeliousRuleset()
{
return {
.rule_set = {
.ruleset_id = 102,
.name = "Scars of Velious",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::TheScarsOfVelious,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "Velious client-based ruleset. Level 60 cap until PoP."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "2",
.notes = "Current Expansion"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "3",
.notes = "Velious Client-Based Expansion Setting"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "3",
.notes = "Velious Client-Based Expansion Setting"
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "60",
.notes = "Level 60 cap until PoP"
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "60",
.notes = "Level 60 cap until PoP"
},
}
};
}
inline RuleSet GetLuclinRuleset()
{
return {
.rule_set = {
.ruleset_id = 103,
.name = "Shadows of Luclin",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::TheShadowsOfLuclin,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "Luclin client-based ruleset. Level 60 cap. Added Wiz crits."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "3",
.notes = "Current Expansion"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "7",
.notes = "Luclin Client-Based Expansion Setting"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "7",
.notes = "Luclin Client-Based Expansion Setting"
},
{
.rule_name = "Spells:WizCritLevel",
.rule_value = "12",
.notes = "Wizard non-AA Criticals Not added until Luclin"
},
}
};
}
inline RuleSet GetPlanesRuleset()
{
return {
.rule_set = {
.ruleset_id = 104,
.name = "Planes of Power",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::ThePlanesOfPower,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "PoP client-based ruleset. Level 65 cap. Stat cap increased. Bind Wound changed."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "4",
.notes = "Current Expansion"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "15",
.notes = "Planes of Power Client-Based Expansion Setting"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "15",
.notes = "Planes of Power Client-Based Expansion Setting"
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "65",
.notes = "Level 65 cap until Omens of War"
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "65",
.notes = "Level 65 cap until Omens of War"
},
{
.rule_name = "Character:StatCap",
.rule_value = "305",
.notes = "Stat cap raised from 255 to 305 with PoP"
},
{
.rule_name = "Character:UseOldBindWound",
.rule_value = "false",
.notes = "PoP introduced a more effective bind wound system"
},
}
};
}
// Returns a RuleSet for the Legacy of Ykesha ruleset.
inline RuleSet GetLegacyOfYkeshaRuleset()
{
return {
.rule_set = {
.ruleset_id = 105,
.name = "Legacy of Ykesha",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::TheLegacyOfYkesha,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "LoY client-based ruleset. Shared bank introduced. Stat cap raised to 350."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "5",
.notes = "Current Expansion"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "31",
.notes = "Legacy of Ykesha Client-Based Expansion Setting"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "31",
.notes = "Legacy of Ykesha Client-Based Expansion Setting"
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "65",
.notes = "Level 65 cap until Omens of War"
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "65",
.notes = "Level 65 cap until Omens of War"
},
{
.rule_name = "Character:SharedBankPlat",
.rule_value = "true",
.notes = "Shared bank enabled in Legacy of Ykesha"
},
{
.rule_name = "Character:StatCap",
.rule_value = "350",
.notes = "Stat cap increased to 350 with LoY (was 305 in PoP)"
},
}
};
}
inline RuleSet GetLDoNRuleset()
{
return {
.rule_set = {
.ruleset_id = 106,
.name = "Lost Dungeons of Norrath",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::LostDungeonsOfNorrath,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "LDoN client-based ruleset. Stat cap raised to 400."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "6",
.notes = "Current Expansion"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "63",
.notes = "Lost Dungeons of Norrath Client-Based Expansion Setting"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "63",
.notes = "Lost Dungeons of Norrath Client-Based Expansion Setting"
},
{
.rule_name = "Character:StatCap",
.rule_value = "400",
.notes = "Stat cap increased to 400 with LDoN (was 350 in LoY)"
},
}
};
}
inline RuleSet GetGatesOfDiscordRuleset()
{
return {
.rule_set = {
.ruleset_id = 107,
.name = "Gates of Discord",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::GatesOfDiscord,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "GoD client-based ruleset. Voice macros introduced."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "7",
.notes = "Current Expansion"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "127",
.notes = "Gates of Discord Client-Based Expansion Setting"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "127",
.notes = "Gates of Discord Client-Based Expansion Setting"
},
{
.rule_name = "Chat:EnableVoiceMacros",
.rule_value = "true",
.notes = "Enable Voice Macros - Introduced in Gates of Discord"
},
}
};
}
inline RuleSet GetOmensOfWarRuleset()
{
return {
.rule_set = {
.ruleset_id = 108,
.name = "Omens of War",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::OmensOfWar,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "OoW client-based ruleset. Level cap raised to 70. Bard AE nerfed. Task system enabled."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "8",
.notes = "Current Expansion"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "255",
.notes = "Omens of War Client-Based Expansion Setting"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "255",
.notes = "Omens of War Client-Based Expansion Setting"
},
{
.rule_name = "Spells:PreNerfBardAEDoT",
.rule_value = "false",
.notes = "Bard AE Nerf"
},
{
.rule_name = "TaskSystem:EnableTaskSystem",
.rule_value = "true",
.notes = "Task system was introduced in Omens of War"
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "70",
.notes = "Level 70 cap until The Serpent's Spine"
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "70",
.notes = "Level 70 cap until The Serpent's Spine"
},
}
};
}
inline RuleSet GetDragonsOfNorrathRuleset()
{
return {
.rule_set = {
.ruleset_id = 109,
.name = "Dragons of Norrath",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::DragonsOfNorrath,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "DoN client-based ruleset. Mail system introduced. Accursed Nest unlockable."
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "9",
.notes = "Current Expansion"
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "511",
.notes = "Dragons of Norrath Client-Based Expansion Setting"
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "511",
.notes = "Dragons of Norrath Client-Based Expansion Setting"
},
{
.rule_name = "Mail:EnableMailSystem",
.rule_value = "true",
.notes = "Mail System not added until Dragons of Norrath"
},
}
};
}
inline RuleSet GetEraOverridesRuleset()
{
return {
.rule_set = {
.ruleset_id = 200,
.name = "Era Overrides",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::EXPANSION_ALL,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "If you want to override any rules for era specific rulesets, use this ruleset. It will not be used by default.",
},
.rules = {
// users will add their own dynamically
}
};
}
inline RuleSet GetDepthsOfDarkhollowRuleset()
{
return {
.rule_set = {
.ruleset_id = 110,
.name = "Depths of Darkhollow",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::DepthsOfDarkhollow,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "DoD client-based ruleset. Introduced Shroud system.",
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "10",
.notes = "Current Expansion",
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "1023",
.notes = "Depths of Darkhollow Client-Based Expansion Setting",
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "1023",
.notes = "Depths of Darkhollow Client-Based Expansion Setting",
},
{
.rule_name = "Character:EnableShroudSystem",
.rule_value = "true",
.notes = "Shroud system was introduced in Depths of Darkhollow",
},
}
};
}
inline RuleSet GetProphecyOfRoRuleset()
{
return {
.rule_set = {
.ruleset_id = 111,
.name = "Prophecy of Ro",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::ProphecyOfRo,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "PoR client-based ruleset. Introduced aura system.",
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "11",
.notes = "Current Expansion",
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "2047",
.notes = "Prophecy of Ro Client-Based Expansion Setting",
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "2047",
.notes = "Prophecy of Ro Client-Based Expansion Setting",
},
{
.rule_name = "Character:EnableAuraSystem",
.rule_value = "true",
.notes = "Aura system introduced in Prophecy of Ro",
},
}
};
}
inline RuleSet GetTheSerpentsSpineRuleset()
{
return {
.rule_set = {
.ruleset_id = 112,
.name = "The Serpent's Spine",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::TheSerpentsSpine,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "TSS client-based ruleset. Level cap raised to 75. Out-of-combat regen enabled.",
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "12",
.notes = "Current Expansion",
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "4095",
.notes = "The Serpent's Spine Client-Based Expansion Setting",
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "4095",
.notes = "The Serpent's Spine Client-Based Expansion Setting",
},
{
.rule_name = "Character:MaxExpLevel",
.rule_value = "75",
.notes = "Level 75 cap until The Buried Sea",
},
{
.rule_name = "Character:MaxLevel",
.rule_value = "75",
.notes = "Level 75 cap until The Buried Sea",
},
{
.rule_name = "Character:RestRegenEnabled",
.rule_value = "true",
.notes = "Out of combat regeneration enabled in The Serpent's Spine",
},
}
};
}
inline RuleSet GetTheBuriedSeaRuleset()
{
return {
.rule_set = {
.ruleset_id = 113,
.name = "The Buried Sea",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::TheBuriedSea,
.max_expansion = Expansion::EXPANSION_MAX,
.notes = "TBS client-based ruleset. Fellowship and item aug system added.",
},
.rules = {
{
.rule_name = "Expansion:CurrentExpansion",
.rule_value = "13",
.notes = "Current Expansion",
},
{
.rule_name = "World:CharacterSelectExpansionSettings",
.rule_value = "8191",
.notes = "The Buried Sea Client-Based Expansion Setting",
},
{
.rule_name = "World:ExpansionSettings",
.rule_value = "8191",
.notes = "The Buried Sea Client-Based Expansion Setting",
},
{
.rule_name = "Fellowship:Enabled",
.rule_value = "true",
.notes = "Fellowships were introduced in The Buried Sea",
},
{
.rule_name = "Items:AllowItemAugmenting",
.rule_value = "true",
.notes = "Item augmenting system introduced in The Buried Sea",
},
}
};
}
inline std::vector<RuleSet> GetCustomRulesets()
{
return {
{
.rule_set = {
.ruleset_id = 300,
.name = "Double Experience",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::EXPANSION_ZERO_VALUE,
.max_expansion = Expansion::EXPANSION_ZERO_VALUE,
.notes = "Doubles EXP globally",
},
.rules = {
{
.rule_name = "Character:FinalExpMultiplier",
.rule_value = "2"
}
}
},
{
.rule_set = {
.ruleset_id = 1000,
.name = "Custom Boundary (Put your custom rulesets after here)",
.zone_ids = "",
.instance_versions = "",
.content_flags = "",
.content_flags_disabled = "",
.min_expansion = Expansion::EXPANSION_ZERO_VALUE,
.max_expansion = Expansion::EXPANSION_ZERO_VALUE,
.notes = "You may add your own rulesets above 1000+"
},
},
};
}
inline std::vector<RuleSet> GetDefaultRulesets()
{
std::vector<RuleSet> sets = {
GetClassicRuleset(),
GetKunarkRuleset(),
GetVeliousRuleset(),
GetLuclinRuleset(),
GetPlanesRuleset(),
GetLegacyOfYkeshaRuleset(),
GetLDoNRuleset(),
GetGatesOfDiscordRuleset(),
GetOmensOfWarRuleset(),
GetDragonsOfNorrathRuleset(),
GetDepthsOfDarkhollowRuleset(),
GetProphecyOfRoRuleset(),
GetTheSerpentsSpineRuleset(),
GetTheBuriedSeaRuleset(),
GetEraOverridesRuleset()
};
// Append custom rulesets
const auto custom = GetCustomRulesets();
sets.insert(sets.end(), custom.begin(), custom.end());
return sets;
}
void WorldContentService::SeedDefaultRulesets() const
{
LogInfo("Seeding default rulesets");
// Load existing rule_sets into a map
std::unordered_map<uint32_t, RuleSetsRepository::RuleSets> existing_rulesets;
for (const auto& r : RuleSetsRepository::All(*m_database)) {
existing_rulesets[r.ruleset_id] = r;
}
// Load existing rule_values into a map<ruleset_id, map<rule_name, RuleValues>>
std::unordered_map<uint32_t, std::unordered_map<std::string, RuleValuesRepository::RuleValues>> existing_rule_values;
for (const auto& r : RuleValuesRepository::All(*m_database)) {
existing_rule_values[r.ruleset_id][r.rule_name] = r;
}
std::vector<RuleSetsRepository::RuleSets> rule_sets_to_insert;
std::vector<RuleSetsRepository::RuleSets> rule_sets_to_update;
std::vector<RuleValuesRepository::RuleValues> rule_values_to_insert;
std::unordered_map<uint32_t, std::vector<std::string>> rule_values_to_delete;
for (const auto& entry : GetDefaultRulesets()) {
const auto& rs = entry.rule_set;
const auto existing_it = existing_rulesets.find(rs.ruleset_id);
if (existing_it == existing_rulesets.end()) {
rule_sets_to_insert.push_back(rs);
}
else {
const auto& existing = existing_it->second;
if (rs.name != existing.name ||
rs.zone_ids != existing.zone_ids ||
rs.instance_versions != existing.instance_versions ||
rs.content_flags != existing.content_flags ||
rs.content_flags_disabled != existing.content_flags_disabled ||
rs.min_expansion != existing.min_expansion ||
rs.max_expansion != existing.max_expansion ||
rs.notes != existing.notes) {
rule_sets_to_update.push_back(rs);
}
}
std::unordered_set<std::string> defined_rule_names;
for (auto rule : entry.rules) {
rule.ruleset_id = rs.ruleset_id;
if (rule.notes.empty()) {
rule.notes = m_rule_manager->GetRuleNotesByName(rule.rule_name);
}
defined_rule_names.insert(rule.rule_name);
auto& existing_rules = existing_rule_values[rs.ruleset_id];
if (existing_rules.find(rule.rule_name) == existing_rules.end()) {
rule_values_to_insert.push_back(rule);
}
}
for (const auto& [rule_name, _] : existing_rule_values[rs.ruleset_id]) {
if (!defined_rule_names.count(rule_name)) {
rule_values_to_delete[rs.ruleset_id].push_back(rule_name);
}
}
}
// Insert new rule sets
for (const auto& rs : rule_sets_to_insert) {
RuleSetsRepository::InsertOne(*m_database, rs);
LogInfo("Inserted ruleset [{}] {}", rs.ruleset_id, rs.name);
}
// Update modified rule sets
for (const auto& rs : rule_sets_to_update) {
RuleSetsRepository::UpdateOne(*m_database, rs);
LogInfo("Updated ruleset metadata [{}] {}", rs.ruleset_id, rs.name);
}
// Insert new rule values
if (!rule_values_to_insert.empty()) {
RuleValuesRepository::InsertMany(*m_database, rule_values_to_insert);
LogInfo("Inserted [{}] new rule(s)]", rule_values_to_insert.size());
}
// Delete obsolete rule values in batches
for (const auto& [ruleset_id, rule_names] : rule_values_to_delete) {
if (rule_names.empty()) continue;
std::string in_clause = "'" + Strings::Join(rule_names, "','") + "'";
std::string where = fmt::format("ruleset_id = {} AND rule_name IN ({})", ruleset_id, in_clause);
int removed = RuleValuesRepository::DeleteWhere(*m_database, where);
LogInfo("Deleted [{}] obsolete rule(s) from ruleset [{}]: [{}]", removed, ruleset_id, Strings::Join(rule_names, ", "));
}
}
void WorldContentService::LoadTargetedRulesets()
{
if (!m_zone_id) {
LogError("Zone ID is not set. Cannot load targeted rulesets.");
return;
}
SeedDefaultRulesets();
LogInfo("Zone ID [{}] Instance Version [{}] - Loading targeted rulesets", m_zone_id, m_instance_version);
auto rules = RuleValuesRepository::GetWhere(*m_database, "TRUE ORDER BY ruleset_id, rule_name");
auto sets = RuleSetsRepository::GetWhere(*m_database, "TRUE ORDER BY ruleset_id");
for (auto& e : sets) {
bool has_filters =
!e.zone_ids.empty() ||
!e.instance_versions.empty() ||
!e.content_flags.empty() ||
!e.content_flags_disabled.empty() ||
e.min_expansion != Expansion::EXPANSION_ZERO_VALUE ||
e.max_expansion != Expansion::EXPANSION_ZERO_VALUE;
if (!has_filters) {
continue; // not a targeted ruleset
}
auto zone_id = std::to_string(m_zone_id);
if (!e.zone_ids.empty() && !Strings::Contains(e.zone_ids, zone_id)) {
continue;
}
auto instance_id = std::to_string(m_instance_version);
if (!e.instance_versions.empty() && !Strings::Contains(e.instance_versions, instance_id)) {
continue;
}
if (!DoesPassContentFiltering(
ContentFlags{
.min_expansion = e.min_expansion,
.max_expansion = e.max_expansion,
.content_flags = e.content_flags,
.content_flags_disabled = e.content_flags_disabled
}
)) {
continue;
}
for (auto& r : rules) {
if (r.ruleset_id != e.ruleset_id) {
continue;
}
m_rule_manager->SetRule(r.rule_name, r.rule_value);
LogInfo(
"Loaded [{}] ruleset [{}] name [{}] value [{}]",
e.ruleset_id,
e.name,
r.rule_name,
r.rule_value
);
}
}
}