From 651635b535c16ead93afd5e6bced94f373f60008 Mon Sep 17 00:00:00 2001 From: Helpless Date: Sun, 22 Jun 2025 13:07:13 +0300 Subject: [PATCH 1/3] Add setting to ignore volatile cores in minimap icons --- MapIconsSettings.cs | 3 ++- MinimapIcons.cs | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/MapIconsSettings.cs b/MapIconsSettings.cs index 2348037..56e3151 100644 --- a/MapIconsSettings.cs +++ b/MapIconsSettings.cs @@ -14,6 +14,7 @@ public class MapIconsSettings : ISettings public ToggleNode DrawReplacementsForGameIconsWhenOutOfRange { get; set; } = new ToggleNode(true); public ToggleNode IgnoreFullscreenPanels { get; set; } = new ToggleNode(false); public ToggleNode IgnoreLargePanels { get; set; } = new ToggleNode(false); + public ToggleNode IgnoreVolatileCores { get; set; } = new ToggleNode(true); [Menu("Cache breach entities", "Breaches spawn lots of entities, to avoid cluttering your minimap you can turn off this setting")] public ToggleNode CacheBreachEntities { get; set; } = new ToggleNode(true); @@ -27,7 +28,7 @@ public class MapIconsSettings : ISettings Content = [ ], - EnableControls = true, + EnableControls = true, ItemFactory = () => new TextNode(""), UseFlatItems = true, }; diff --git a/MinimapIcons.cs b/MinimapIcons.cs index 220b29f..0681bf6 100644 --- a/MinimapIcons.cs +++ b/MinimapIcons.cs @@ -229,9 +229,9 @@ public override Job Tick() public override void Render() { - if (_largeMap == null || + if (_largeMap == null || !GameController.InGame || - Settings.DrawOnlyOnLargeMap && _largeMap != true) + Settings.DrawOnlyOnLargeMap && _largeMap != true) return; if (!Settings.IgnoreFullscreenPanels && @@ -257,6 +257,9 @@ public override void Render() if (!Settings.DrawMonsters && icon.Entity.Type == EntityType.Monster) continue; + if (Settings.IgnoreVolatileCores && icon.Entity.RenderName.Contains("Volatile Core")) + continue; + if (IgnoreCache.GetOrAdd(icon.Entity.Path, () => Ignored.Any(x => icon.Entity.Path.StartsWith(x)))) continue; @@ -284,7 +287,7 @@ icon is not CustomIcon && var halfSize = size / 2f; icon.DrawRect = new RectangleF(position.X - halfSize, position.Y - halfSize, size, size); var drawRect = icon.DrawRect; - if (_largeMap == false && !_ingameUi.Map.SmallMiniMap.GetClientRectCache.Contains(drawRect)) + if (_largeMap == false && !_ingameUi.Map.SmallMiniMap.GetClientRectCache.Contains(drawRect)) continue; Graphics.DrawImage(iconValueMainTexture.FileName, drawRect, iconValueMainTexture.UV, iconValueMainTexture.Color.ToSharpDx()); From c6ab272483bbb7cb59806e1c589c265d6b826f3f Mon Sep 17 00:00:00 2001 From: Helpless Date: Thu, 23 Oct 2025 19:17:41 +0300 Subject: [PATCH 2/3] Add custom ignore rules for minimap icons --- IgnoreRules/CustomIgnoreSettings.cs | 39 ++++ IgnoreRules/IgnoreRule.cs | 60 ++++++ IgnoreRules/IgnoreRulesManager.cs | 318 ++++++++++++++++++++++++++++ MapIconsSettings.cs | 5 +- MinimapIcons.cs | 64 +++++- config/custom_ignore_rules.txt | 25 +++ 6 files changed, 504 insertions(+), 7 deletions(-) create mode 100644 IgnoreRules/CustomIgnoreSettings.cs create mode 100644 IgnoreRules/IgnoreRule.cs create mode 100644 IgnoreRules/IgnoreRulesManager.cs create mode 100644 config/custom_ignore_rules.txt diff --git a/IgnoreRules/CustomIgnoreSettings.cs b/IgnoreRules/CustomIgnoreSettings.cs new file mode 100644 index 0000000..3baf5b7 --- /dev/null +++ b/IgnoreRules/CustomIgnoreSettings.cs @@ -0,0 +1,39 @@ +using ExileCore.Shared.Attributes; +using ExileCore.Shared.Interfaces; +using ExileCore.Shared.Nodes; + +namespace MinimapIcons.IgnoreRules; + +public class CustomIgnoreSettings : ISettings +{ + [Menu("Enable Custom Ignore Rules")] + public ToggleNode EnableCustomIgnoreRules { get; set; } = new ToggleNode(true); + + [Menu("New Rule Type")] + public ListNode NewRuleType { get; set; } = new ListNode + { + Values = new System.Collections.Generic.List + { + "Metadata Exact", + "Metadata Starts With", + "Metadata Contains", + "Name Exact", + "Name Contains" + }, + Value = "Metadata Starts With" + }; + + [Menu("New Rule Pattern")] + public TextNode NewRulePattern { get; set; } = new TextNode(""); + + [Menu("Add Rule")] + public ButtonNode AddRule { get; set; } = new ButtonNode(); + + [Menu("Reload Rules from File")] + public ButtonNode ReloadRules { get; set; } = new ButtonNode(); + + [Menu("Open Config Folder")] + public ButtonNode OpenConfigFolder { get; set; } = new ButtonNode(); + + public ToggleNode Enable { get; set; } = new ToggleNode(true); +} diff --git a/IgnoreRules/IgnoreRule.cs b/IgnoreRules/IgnoreRule.cs new file mode 100644 index 0000000..ea6ebfa --- /dev/null +++ b/IgnoreRules/IgnoreRule.cs @@ -0,0 +1,60 @@ +using System; + +namespace MinimapIcons.IgnoreRules; + +public class IgnoreRule +{ + public IgnoreRuleType Type { get; set; } + public string Pattern { get; set; } + public bool IsEnabled { get; set; } = true; + + public IgnoreRule() + { + } + + public IgnoreRule(IgnoreRuleType type, string pattern, bool isEnabled = true) + { + Type = type; + Pattern = pattern; + IsEnabled = isEnabled; + } + + public bool Matches(string metadata, string renderName) + { + if (!IsEnabled || string.IsNullOrWhiteSpace(Pattern)) + return false; + + return Type switch + { + IgnoreRuleType.MetadataExact => metadata.Equals(Pattern, StringComparison.OrdinalIgnoreCase), + IgnoreRuleType.MetadataStartsWith => metadata.StartsWith(Pattern, StringComparison.OrdinalIgnoreCase), + IgnoreRuleType.MetadataContains => metadata.Contains(Pattern, StringComparison.OrdinalIgnoreCase), + IgnoreRuleType.NameExact => renderName.Equals(Pattern, StringComparison.OrdinalIgnoreCase), + IgnoreRuleType.NameContains => renderName.Contains(Pattern, StringComparison.OrdinalIgnoreCase), + _ => false + }; + } + + public override string ToString() + { + var prefix = Type switch + { + IgnoreRuleType.MetadataExact => "[META=]", + IgnoreRuleType.MetadataStartsWith => "[META^]", + IgnoreRuleType.MetadataContains => "[META*]", + IgnoreRuleType.NameExact => "[NAME=]", + IgnoreRuleType.NameContains => "[NAME*]", + _ => "[???]" + }; + return $"{prefix} {Pattern}"; + } +} + +public enum IgnoreRuleType +{ + MetadataExact, // Exact metadata match + MetadataStartsWith, // Metadata starts with + MetadataContains, // Metadata contains + NameExact, // Exact name match + NameContains // Name contains +} diff --git a/IgnoreRules/IgnoreRulesManager.cs b/IgnoreRules/IgnoreRulesManager.cs new file mode 100644 index 0000000..871027f --- /dev/null +++ b/IgnoreRules/IgnoreRulesManager.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MinimapIcons.IgnoreRules; + +public class IgnoreRulesManager +{ + private readonly List _customRules = new(); + private readonly List _builtInRules = new(); + private readonly Dictionary _cache = new(); + private readonly string _customRulesFilePath; + + public IReadOnlyList CustomRules => _customRules.AsReadOnly(); + public IReadOnlyList BuiltInRules => _builtInRules.AsReadOnly(); + + public IgnoreRulesManager(string directoryFullName) + { + var configDir = Path.Combine(directoryFullName, "config"); + if (!Directory.Exists(configDir)) + Directory.CreateDirectory(configDir); + + _customRulesFilePath = Path.Combine(configDir, "custom_ignore_rules.txt"); + LoadBuiltInRules(); + LoadCustomRules(); + } + + private void LoadBuiltInRules() + { + _builtInRules.Clear(); + + // Hardcoded rules from MinimapIcons.cs + var builtInPatterns = new[] + { + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonEyes1", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonEyes2", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonEyes3", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonSpikes", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonSpikes2", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonSpikes3", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonPimple1", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonPimple2", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonPimple3", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatFillet1Vanish", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatFillet2Vanish", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatRhoa1Vanish", + "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatRhoa2Vanish", + "Metadata/Monsters/AtlasExiles/AtlasExile1@", + "Metadata/Monsters/AtlasExiles/CrusaderInfluenceMonsters/CrusaderArcaneRune", + "Metadata/Monsters/AtlasExiles/AtlasExile2_", + "Metadata/Monsters/AtlasExiles/EyrieInfluenceMonsters/EyrieFrostnadoDaemon", + "Metadata/Monsters/AtlasExiles/AtlasExile3@", + "Metadata/Monsters/AtlasExiles/AtlasExile3AcidPitDaemon", + "Metadata/Monsters/AtlasExiles/AtlasExile3BurrowingViperMelee", + "Metadata/Monsters/AtlasExiles/AtlasExile3BurrowingViperRanged", + "Metadata/Monsters/AtlasExiles/AtlasExile4@", + "Metadata/Monsters/AtlasExiles/AtlasExile4ApparitionCascade", + "Metadata/Monsters/AtlasExiles/AtlasExile5Apparition", + "Metadata/Monsters/AtlasExiles/AtlasExile5Throne", + "Metadata/Monsters/LeagueIncursion/VaalSaucerRoomTurret", + "Metadata/Monsters/LeagueIncursion/VaalSaucerTurret", + "Metadata/Monsters/LeagueBetrayal/BetrayalTaserNet", + "Metadata/Monsters/LeagueBetrayal/FortTurret/FortTurret1Safehouse", + "Metadata/Monsters/LeagueBetrayal/FortTurret/FortTurret1", + "Metadata/Monsters/LeagueBetrayal/MasterNinjaCop", + "Metadata/Monsters/LeagueBetrayal/BetrayalRikerMortarDaemon", + "Metadata/Monsters/LeagueBetrayal/BetrayalBoneNovaDaemon", + "Metadata/Monsters/LeagueBetrayal/BetrayalCatarinaPillarDaemon_", + "Metadata/Monsters/LeagueBetrayal/BetrayalUpgrades/BetrayalDaemonCorpseConsume", + "Metadata/Monsters/LegionLeague/LegionVaalGeneralProjectileDaemon", + "Metadata/Monsters/LegionLeague/LegionSergeantStampedeDaemon", + "Metadata/Monsters/LegionLeague/LegionSandTornadoDaemon", + "Metadata/Monsters/LegionLeague/LegionVaalGeneralMoveDaemonQuad", + "Metadata/Monsters/InvisibleFire/InvisibleSandstorm_", + "Metadata/Monsters/InvisibleFire/InvisibleFrostnado", + "Metadata/Monsters/InvisibleFire/InvisibleFireAfflictionDemonColdDegen", + "Metadata/Monsters/InvisibleFire/InvisibleFireAfflictionDemonColdDegenUnique", + "Metadata/Monsters/InvisibleFire/InvisibleFireAfflictionCorpseDegen", + "Metadata/Monsters/InvisibleFire/InvisibleFireEyrieHurricane", + "Metadata/Monsters/InvisibleFire/InvisibleIonCannonFrost", + "Metadata/Monsters/InvisibleFire/AfflictionBossFinalDeathZone", + "Metadata/Monsters/InvisibleFire/InvisibleFireDoedreSewers", + "Metadata/Monsters/InvisibleFire/InvisibleFireDelveFlameTornadoSpiked", + "Metadata/Monsters/InvisibleFire/InvisibleHolyCannon", + "Metadata/Monsters/InvisibleFire/DelveVaalBossInvisibleLight", + "Metadata/Monsters/InvisibleFire/InvisibleChaosstorm", + "Metadata/Monsters/InvisibleFire/InvisibleKitavaCannon", + "Metadata/Monsters/InvisibleCurse/InvisibleFrostbiteStationary", + "Metadata/Monsters/InvisibleCurse/InvisibleConductivityStationary", + "Metadata/Monsters/InvisibleCurse/InvisibleEnfeeble", + "Metadata/Monsters/InvisibleAura/InvisibleWrathStationary", + "Metadata/Monsters/Frog/FrogGod/SilverOrb", + "Metadata/Monsters/Frog/FrogGod/SilverPool", + "Metadata/Monsters/LunarisSolaris/SolarisCelestialFormAmbushUniqueMap", + "Metadata/Monsters/Invisible/MaligaroSoulInvisibleBladeVortex", + "Metadata/Monsters/Daemon", + "Metadata/Monsters/Daemon/MaligaroBladeVortexDaemon", + "Metadata/Monsters/Daemon/SilverPoolChillDaemon", + "Metadata/Monsters/AvariusCasticus/AvariusCasticusStatue", + "Metadata/Monsters/Maligaro/MaligaroDesecrate", + "Metadata/Monsters/Avatar/AvatarMagmaOrbDaemon", + "Metadata/Monsters/Monkeys/FlameBearerTalismanT2Ghost", + "Metadata/Monsters/Totems/TalismanTotem/TalismanTotemDeathscape", + "Metadata/Monsters/BeehiveBehemoth/BeehiveBehemothSwampDaemon", + "Metadata/Monsters/VaalWraith/VaalWraithChampionMinion", + "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret1", + "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret2", + "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret3", + "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret4", + "Metadata/Monsters/LeagueSynthesis/SynthesisWalkerSpawned_", + "Metadata/Monsters/LeagueRitual/FireMeteorDaemon", + "Metadata/Monsters/LeagueRitual/GenericSpeedDaemon", + "Metadata/Monsters/LeagueRitual/ColdRotatingBeamDaemon", + "Metadata/Monsters/LeagueRitual/ColdRotatingBeamDaemonUber", + "Metadata/Monsters/LeagueRitual/GenericEnergyShieldDaemon", + "Metadata/Monsters/LeagueRitual/GenericMassiveDaemon", + "Metadata/Monsters/LeagueRitual/ChaosGreenVinesDaemon_", + "Metadata/Monsters/LeagueRitual/ChaosSoulrendPortalDaemon", + "Metadata/Monsters/LeagueRitual/VaalAtziriDaemon", + "Metadata/Monsters/LeagueRitual/LightningPylonDaemon", + "Metadata/Monsters/LeagueBestiary/RootSpiderBestiaryAmbush", + "Metadata/Monsters/LeagueBestiary/BlackScorpionBestiaryBurrowTornado", + "Metadata/Monsters/LeagueBestiary/ModDaemonCorpseEruption", + "Metadata/Monsters/LeagueBestiary/ModDaemonSandLeaperExplode1", + "Metadata/Monsters/LeagueBestiary/ModDaemonStampede1", + "Metadata/Monsters/LeagueBestiary/ModDaemonGraspingPincers1", + "Metadata/Monsters/LeagueBestiary/ModDaemonPouncingShade1", + "Metadata/Monsters/LeagueBestiary/ModDaemonPouncingShadeQuickHit", + "Metadata/Monsters/LeagueBestiary/ModDaemonFire1", + "Metadata/Monsters/LeagueBestiary/ModDaemonVultureBomb1", + "Metadata/Monsters/LeagueBestiary/ModDaemonVultureBombCast1", + "Metadata/Monsters/LeagueBestiary/ModDaemonParasiticSquid1", + "Metadata/Monsters/LeagueBestiary/ModDaemonBloodRaven1", + "Metadata/Monsters/LeagueBestiary/SandLeaperBestiaryClone", + "Metadata/Monsters/LeagueBestiary/SpiderPlagueBestiaryExplode", + "Metadata/Monsters/LeagueBestiary/ParasiticSquidBestiaryClone", + "Metadata/Monsters/LeagueBestiary/HellionBestiaryClone", + "Metadata/Monsters/LeagueBestiary/BestiarySpiderCocoon", + "Metadata/Monsters/LeagueBestiary/GemFrogBestiaryClone", + "Metadata/Monsters/LeagueRitual/GoldenCoinDaemon", + "Metadata/Monsters/LeagueRitual/GenericLifeDaemon", + "Metadata/Monsters/LeagueRitual/GenericChargesDaemon" + }; + + foreach (var pattern in builtInPatterns) + { + _builtInRules.Add(new IgnoreRule(IgnoreRuleType.MetadataStartsWith, pattern, true)); + } + } + + public void LoadCustomRules() + { + _customRules.Clear(); + ClearCache(); + + if (!File.Exists(_customRulesFilePath)) + { + SaveCustomRules(); // Create default file + return; + } + + try + { + var lines = File.ReadAllLines(_customRulesFilePath); + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + if (string.IsNullOrWhiteSpace(trimmedLine) || trimmedLine.StartsWith("#")) + continue; + + var rule = ParseRule(trimmedLine); + if (rule != null) + _customRules.Add(rule); + } + } + catch + { + // Silent fail - error will be handled by caller + } + } + + public void SaveCustomRules() + { + try + { + var lines = new List + { + "# Custom Ignore Rules for MinimapIcons", + "# Format examples:", + "# META=Metadata/Monsters/Exact/Path - Exact metadata match", + "# META^Metadata/Monsters/Prefix - Metadata starts with", + "# META*PartialMetadata - Metadata contains", + "# NAME=Exact Entity Name - Exact name match", + "# NAME*Partial Name - Name contains", + "# Lines starting with # are comments", + "# Prefix with ! to disable a rule without deleting it", + "" + }; + + foreach (var rule in _customRules) + { + var prefix = rule.Type switch + { + IgnoreRuleType.MetadataExact => "META=", + IgnoreRuleType.MetadataStartsWith => "META^", + IgnoreRuleType.MetadataContains => "META*", + IgnoreRuleType.NameExact => "NAME=", + IgnoreRuleType.NameContains => "NAME*", + _ => "META^" + }; + + var line = $"{(rule.IsEnabled ? "" : "!")}{prefix}{rule.Pattern}"; + lines.Add(line); + } + + File.WriteAllLines(_customRulesFilePath, lines); + } + catch + { + // Silent fail - error will be handled by caller + } + } + + private IgnoreRule ParseRule(string line) + { + var isEnabled = !line.StartsWith("!"); + if (!isEnabled) + line = line.Substring(1); + + IgnoreRuleType type; + string pattern; + + if (line.StartsWith("META=")) + { + type = IgnoreRuleType.MetadataExact; + pattern = line.Substring(5); + } + else if (line.StartsWith("META^")) + { + type = IgnoreRuleType.MetadataStartsWith; + pattern = line.Substring(5); + } + else if (line.StartsWith("META*")) + { + type = IgnoreRuleType.MetadataContains; + pattern = line.Substring(5); + } + else if (line.StartsWith("NAME=")) + { + type = IgnoreRuleType.NameExact; + pattern = line.Substring(5); + } + else if (line.StartsWith("NAME*")) + { + type = IgnoreRuleType.NameContains; + pattern = line.Substring(5); + } + else + { + // Default to MetadataStartsWith for backward compatibility + type = IgnoreRuleType.MetadataStartsWith; + pattern = line; + } + + return new IgnoreRule(type, pattern, isEnabled); + } + + public void AddRule(IgnoreRule rule) + { + _customRules.Add(rule); + ClearCache(); + SaveCustomRules(); + } + + public void RemoveRule(IgnoreRule rule) + { + _customRules.Remove(rule); + ClearCache(); + SaveCustomRules(); + } + + public void ClearCache() + { + _cache.Clear(); + } + + public bool ShouldIgnore(string metadata, string renderName) + { + var cacheKey = $"{metadata}|{renderName}"; + + if (_cache.TryGetValue(cacheKey, out var cached)) + return cached; + + // Check built-in rules first + foreach (var rule in _builtInRules) + { + if (rule.Matches(metadata, renderName)) + { + _cache[cacheKey] = true; + return true; + } + } + + // Then check custom rules + foreach (var rule in _customRules) + { + if (rule.Matches(metadata, renderName)) + { + _cache[cacheKey] = true; + return true; + } + } + + _cache[cacheKey] = false; + return false; + } +} diff --git a/MapIconsSettings.cs b/MapIconsSettings.cs index 56e3151..6181205 100644 --- a/MapIconsSettings.cs +++ b/MapIconsSettings.cs @@ -2,6 +2,7 @@ using ExileCore.Shared.Interfaces; using ExileCore.Shared.Nodes; using MinimapIcons.IconsBuilder; +using MinimapIcons.IgnoreRules; namespace MinimapIcons; @@ -14,7 +15,6 @@ public class MapIconsSettings : ISettings public ToggleNode DrawReplacementsForGameIconsWhenOutOfRange { get; set; } = new ToggleNode(true); public ToggleNode IgnoreFullscreenPanels { get; set; } = new ToggleNode(false); public ToggleNode IgnoreLargePanels { get; set; } = new ToggleNode(false); - public ToggleNode IgnoreVolatileCores { get; set; } = new ToggleNode(true); [Menu("Cache breach entities", "Breaches spawn lots of entities, to avoid cluttering your minimap you can turn off this setting")] public ToggleNode CacheBreachEntities { get; set; } = new ToggleNode(true); @@ -33,5 +33,8 @@ public class MapIconsSettings : ISettings UseFlatItems = true, }; + [Menu("Custom Ignore Rules", CollapsedByDefault = true)] + public CustomIgnoreSettings CustomIgnoreSettings { get; set; } = new(); + public IconsBuilderSettings IconsBuilderSettings { get; set; } = new(); } \ No newline at end of file diff --git a/MinimapIcons.cs b/MinimapIcons.cs index 0681bf6..2730193 100644 --- a/MinimapIcons.cs +++ b/MinimapIcons.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; using ExileCore; using ExileCore.PoEMemory.Components; using ExileCore.PoEMemory.Elements; @@ -10,6 +6,11 @@ using ExileCore.Shared.Enums; using ExileCore.Shared.Helpers; using MinimapIcons.IconsBuilder.Icons; +using MinimapIcons.IgnoreRules; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using Color = SharpDX.Color; using RectangleF = SharpDX.RectangleF; using Vector2 = System.Numerics.Vector2; @@ -157,6 +158,7 @@ public class MinimapIcons : BaseSettingsPlugin private readonly Dictionary IgnoreCache = new Dictionary(); + private IgnoreRulesManager _ignoreRulesManager; private IngameUIElements _ingameUi; private bool? _largeMap; private float _mapScale; @@ -168,6 +170,7 @@ public class MinimapIcons : BaseSettingsPlugin public override bool Initialise() { + _ignoreRulesManager = new IgnoreRulesManager(DirectoryFullName); IconsBuilder.Initialise(); Settings.AlwaysShownIngameIcons.Content = Settings.AlwaysShownIngameIcons.Content.DistinctBy(x => x.Value).ToList(); Graphics.InitImage("sprites.png"); @@ -175,6 +178,48 @@ public override bool Initialise() CanUseMultiThreading = true; _iconListCache = CreateIconListCache(); Settings.IconListRefreshPeriod.OnValueChanged += (_, _) => _iconListCache = CreateIconListCache(); + + // Setup custom ignore rules UI handlers + Settings.CustomIgnoreSettings.ReloadRules.OnPressed += () => + { + _ignoreRulesManager.LoadCustomRules(); + DebugWindow.LogMsg("Custom ignore rules reloaded"); + }; + + Settings.CustomIgnoreSettings.OpenConfigFolder.OnPressed += () => + { + var configPath = System.IO.Path.Combine(DirectoryFullName, "config"); + Process.Start("explorer.exe", configPath); + }; + + Settings.CustomIgnoreSettings.AddRule.OnPressed += () => + { + var pattern = Settings.CustomIgnoreSettings.NewRulePattern.Value; + if (string.IsNullOrWhiteSpace(pattern)) + { + DebugWindow.LogMsg("Please enter a pattern for the rule"); + return; + } + + var ruleType = Settings.CustomIgnoreSettings.NewRuleType.Value switch + { + "Metadata Exact" => IgnoreRuleType.MetadataExact, + "Metadata Starts With" => IgnoreRuleType.MetadataStartsWith, + "Metadata Contains" => IgnoreRuleType.MetadataContains, + "Name Exact" => IgnoreRuleType.NameExact, + "Name Contains" => IgnoreRuleType.NameContains, + _ => IgnoreRuleType.MetadataStartsWith + }; + + var newRule = new IgnoreRule(ruleType, pattern); + _ignoreRulesManager.AddRule(newRule); + + DebugWindow.LogMsg($"Added ignore rule: {newRule}"); + + // Clear the pattern field after adding + Settings.CustomIgnoreSettings.NewRulePattern.Value = ""; + }; + return true; } @@ -257,12 +302,19 @@ public override void Render() if (!Settings.DrawMonsters && icon.Entity.Type == EntityType.Monster) continue; - if (Settings.IgnoreVolatileCores && icon.Entity.RenderName.Contains("Volatile Core")) - continue; + // Use custom ignore rules if enabled + if (Settings.CustomIgnoreSettings.EnableCustomIgnoreRules) + { + if (_ignoreRulesManager.ShouldIgnore(icon.Entity.Path, icon.Entity.RenderName)) + continue; + } + + // hardcoded ignore list if (IgnoreCache.GetOrAdd(icon.Entity.Path, () => Ignored.Any(x => icon.Entity.Path.StartsWith(x)))) continue; + if (icon.Entity.Path.StartsWith( "Metadata/Monsters/AtlasExiles/BasiliskInfluenceMonsters/BasiliskBurrowingViper", StringComparison.Ordinal) && icon.Entity.Rarity != MonsterRarity.Unique) diff --git a/config/custom_ignore_rules.txt b/config/custom_ignore_rules.txt new file mode 100644 index 0000000..d5eedc1 --- /dev/null +++ b/config/custom_ignore_rules.txt @@ -0,0 +1,25 @@ +# Custom Ignore Rules for MinimapIcons +# +# Rule formats: +# META=Metadata/Monsters/Exact/Path - Exact metadata match +# META^Metadata/Monsters/Prefix - Metadata starts with +# META*PartialMetadata - Metadata contains +# NAME=Exact Entity Name - Exact name match +# NAME*Partial Name - Name contains +# +# Lines starting with # are comments +# Prefix with ! to disable a rule without deleting it +# +# Examples: +# META*DoodadDaemon - Ignore all containing "DoodadDaemon" in metadata +# META^Metadata/Monsters/AtlasExiles/ - Ignore all starting with this path +# NAME*Volatile Core - Ignore by name containing "Volatile Core" +# !META^Metadata/Monsters/Disabled - Disabled rule (not applied) +# +# How to add entity to ignore: +# 1. Open plugin settings -> Custom Ignore Rules +# 2. Select rule type in "New Rule Type" +# 3. Enter pattern in "New Rule Pattern" +# 4. Click "Add Rule" +# +# Your rules below: From cf9a576ec15e8ded64232a3adcaa79e1b059a70d Mon Sep 17 00:00:00 2001 From: Helpless Date: Thu, 23 Oct 2025 19:28:27 +0300 Subject: [PATCH 3/3] Refactor IgnoreRulesManager to remove built-in rules handling --- IgnoreRules/IgnoreRulesManager.cs | 139 +----------------------------- 1 file changed, 1 insertion(+), 138 deletions(-) diff --git a/IgnoreRules/IgnoreRulesManager.cs b/IgnoreRules/IgnoreRulesManager.cs index 871027f..5ade124 100644 --- a/IgnoreRules/IgnoreRulesManager.cs +++ b/IgnoreRules/IgnoreRulesManager.cs @@ -1,19 +1,15 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; namespace MinimapIcons.IgnoreRules; public class IgnoreRulesManager { private readonly List _customRules = new(); - private readonly List _builtInRules = new(); private readonly Dictionary _cache = new(); private readonly string _customRulesFilePath; public IReadOnlyList CustomRules => _customRules.AsReadOnly(); - public IReadOnlyList BuiltInRules => _builtInRules.AsReadOnly(); public IgnoreRulesManager(string directoryFullName) { @@ -22,132 +18,9 @@ public IgnoreRulesManager(string directoryFullName) Directory.CreateDirectory(configDir); _customRulesFilePath = Path.Combine(configDir, "custom_ignore_rules.txt"); - LoadBuiltInRules(); LoadCustomRules(); } - private void LoadBuiltInRules() - { - _builtInRules.Clear(); - - // Hardcoded rules from MinimapIcons.cs - var builtInPatterns = new[] - { - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonEyes1", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonEyes2", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonEyes3", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonSpikes", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonSpikes2", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonSpikes3", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonPimple1", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonPimple2", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonPimple3", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatFillet1Vanish", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatFillet2Vanish", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatRhoa1Vanish", - "Metadata/Monsters/LeagueAffliction/DoodadDaemons/DoodadDaemonGoatRhoa2Vanish", - "Metadata/Monsters/AtlasExiles/AtlasExile1@", - "Metadata/Monsters/AtlasExiles/CrusaderInfluenceMonsters/CrusaderArcaneRune", - "Metadata/Monsters/AtlasExiles/AtlasExile2_", - "Metadata/Monsters/AtlasExiles/EyrieInfluenceMonsters/EyrieFrostnadoDaemon", - "Metadata/Monsters/AtlasExiles/AtlasExile3@", - "Metadata/Monsters/AtlasExiles/AtlasExile3AcidPitDaemon", - "Metadata/Monsters/AtlasExiles/AtlasExile3BurrowingViperMelee", - "Metadata/Monsters/AtlasExiles/AtlasExile3BurrowingViperRanged", - "Metadata/Monsters/AtlasExiles/AtlasExile4@", - "Metadata/Monsters/AtlasExiles/AtlasExile4ApparitionCascade", - "Metadata/Monsters/AtlasExiles/AtlasExile5Apparition", - "Metadata/Monsters/AtlasExiles/AtlasExile5Throne", - "Metadata/Monsters/LeagueIncursion/VaalSaucerRoomTurret", - "Metadata/Monsters/LeagueIncursion/VaalSaucerTurret", - "Metadata/Monsters/LeagueBetrayal/BetrayalTaserNet", - "Metadata/Monsters/LeagueBetrayal/FortTurret/FortTurret1Safehouse", - "Metadata/Monsters/LeagueBetrayal/FortTurret/FortTurret1", - "Metadata/Monsters/LeagueBetrayal/MasterNinjaCop", - "Metadata/Monsters/LeagueBetrayal/BetrayalRikerMortarDaemon", - "Metadata/Monsters/LeagueBetrayal/BetrayalBoneNovaDaemon", - "Metadata/Monsters/LeagueBetrayal/BetrayalCatarinaPillarDaemon_", - "Metadata/Monsters/LeagueBetrayal/BetrayalUpgrades/BetrayalDaemonCorpseConsume", - "Metadata/Monsters/LegionLeague/LegionVaalGeneralProjectileDaemon", - "Metadata/Monsters/LegionLeague/LegionSergeantStampedeDaemon", - "Metadata/Monsters/LegionLeague/LegionSandTornadoDaemon", - "Metadata/Monsters/LegionLeague/LegionVaalGeneralMoveDaemonQuad", - "Metadata/Monsters/InvisibleFire/InvisibleSandstorm_", - "Metadata/Monsters/InvisibleFire/InvisibleFrostnado", - "Metadata/Monsters/InvisibleFire/InvisibleFireAfflictionDemonColdDegen", - "Metadata/Monsters/InvisibleFire/InvisibleFireAfflictionDemonColdDegenUnique", - "Metadata/Monsters/InvisibleFire/InvisibleFireAfflictionCorpseDegen", - "Metadata/Monsters/InvisibleFire/InvisibleFireEyrieHurricane", - "Metadata/Monsters/InvisibleFire/InvisibleIonCannonFrost", - "Metadata/Monsters/InvisibleFire/AfflictionBossFinalDeathZone", - "Metadata/Monsters/InvisibleFire/InvisibleFireDoedreSewers", - "Metadata/Monsters/InvisibleFire/InvisibleFireDelveFlameTornadoSpiked", - "Metadata/Monsters/InvisibleFire/InvisibleHolyCannon", - "Metadata/Monsters/InvisibleFire/DelveVaalBossInvisibleLight", - "Metadata/Monsters/InvisibleFire/InvisibleChaosstorm", - "Metadata/Monsters/InvisibleFire/InvisibleKitavaCannon", - "Metadata/Monsters/InvisibleCurse/InvisibleFrostbiteStationary", - "Metadata/Monsters/InvisibleCurse/InvisibleConductivityStationary", - "Metadata/Monsters/InvisibleCurse/InvisibleEnfeeble", - "Metadata/Monsters/InvisibleAura/InvisibleWrathStationary", - "Metadata/Monsters/Frog/FrogGod/SilverOrb", - "Metadata/Monsters/Frog/FrogGod/SilverPool", - "Metadata/Monsters/LunarisSolaris/SolarisCelestialFormAmbushUniqueMap", - "Metadata/Monsters/Invisible/MaligaroSoulInvisibleBladeVortex", - "Metadata/Monsters/Daemon", - "Metadata/Monsters/Daemon/MaligaroBladeVortexDaemon", - "Metadata/Monsters/Daemon/SilverPoolChillDaemon", - "Metadata/Monsters/AvariusCasticus/AvariusCasticusStatue", - "Metadata/Monsters/Maligaro/MaligaroDesecrate", - "Metadata/Monsters/Avatar/AvatarMagmaOrbDaemon", - "Metadata/Monsters/Monkeys/FlameBearerTalismanT2Ghost", - "Metadata/Monsters/Totems/TalismanTotem/TalismanTotemDeathscape", - "Metadata/Monsters/BeehiveBehemoth/BeehiveBehemothSwampDaemon", - "Metadata/Monsters/VaalWraith/VaalWraithChampionMinion", - "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret1", - "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret2", - "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret3", - "Metadata/Monsters/LeagueSynthesis/SynthesisDroneBossTurret4", - "Metadata/Monsters/LeagueSynthesis/SynthesisWalkerSpawned_", - "Metadata/Monsters/LeagueRitual/FireMeteorDaemon", - "Metadata/Monsters/LeagueRitual/GenericSpeedDaemon", - "Metadata/Monsters/LeagueRitual/ColdRotatingBeamDaemon", - "Metadata/Monsters/LeagueRitual/ColdRotatingBeamDaemonUber", - "Metadata/Monsters/LeagueRitual/GenericEnergyShieldDaemon", - "Metadata/Monsters/LeagueRitual/GenericMassiveDaemon", - "Metadata/Monsters/LeagueRitual/ChaosGreenVinesDaemon_", - "Metadata/Monsters/LeagueRitual/ChaosSoulrendPortalDaemon", - "Metadata/Monsters/LeagueRitual/VaalAtziriDaemon", - "Metadata/Monsters/LeagueRitual/LightningPylonDaemon", - "Metadata/Monsters/LeagueBestiary/RootSpiderBestiaryAmbush", - "Metadata/Monsters/LeagueBestiary/BlackScorpionBestiaryBurrowTornado", - "Metadata/Monsters/LeagueBestiary/ModDaemonCorpseEruption", - "Metadata/Monsters/LeagueBestiary/ModDaemonSandLeaperExplode1", - "Metadata/Monsters/LeagueBestiary/ModDaemonStampede1", - "Metadata/Monsters/LeagueBestiary/ModDaemonGraspingPincers1", - "Metadata/Monsters/LeagueBestiary/ModDaemonPouncingShade1", - "Metadata/Monsters/LeagueBestiary/ModDaemonPouncingShadeQuickHit", - "Metadata/Monsters/LeagueBestiary/ModDaemonFire1", - "Metadata/Monsters/LeagueBestiary/ModDaemonVultureBomb1", - "Metadata/Monsters/LeagueBestiary/ModDaemonVultureBombCast1", - "Metadata/Monsters/LeagueBestiary/ModDaemonParasiticSquid1", - "Metadata/Monsters/LeagueBestiary/ModDaemonBloodRaven1", - "Metadata/Monsters/LeagueBestiary/SandLeaperBestiaryClone", - "Metadata/Monsters/LeagueBestiary/SpiderPlagueBestiaryExplode", - "Metadata/Monsters/LeagueBestiary/ParasiticSquidBestiaryClone", - "Metadata/Monsters/LeagueBestiary/HellionBestiaryClone", - "Metadata/Monsters/LeagueBestiary/BestiarySpiderCocoon", - "Metadata/Monsters/LeagueBestiary/GemFrogBestiaryClone", - "Metadata/Monsters/LeagueRitual/GoldenCoinDaemon", - "Metadata/Monsters/LeagueRitual/GenericLifeDaemon", - "Metadata/Monsters/LeagueRitual/GenericChargesDaemon" - }; - - foreach (var pattern in builtInPatterns) - { - _builtInRules.Add(new IgnoreRule(IgnoreRuleType.MetadataStartsWith, pattern, true)); - } - } public void LoadCustomRules() { @@ -292,17 +165,7 @@ public bool ShouldIgnore(string metadata, string renderName) if (_cache.TryGetValue(cacheKey, out var cached)) return cached; - // Check built-in rules first - foreach (var rule in _builtInRules) - { - if (rule.Matches(metadata, renderName)) - { - _cache[cacheKey] = true; - return true; - } - } - - // Then check custom rules + // Check only custom rules foreach (var rule in _customRules) { if (rule.Matches(metadata, renderName))