diff --git a/BossMod/BossModReborn.csproj b/BossMod/BossModReborn.csproj
index 2262b938b..2f892e1b3 100644
--- a/BossMod/BossModReborn.csproj
+++ b/BossMod/BossModReborn.csproj
@@ -55,6 +55,7 @@
+
@@ -105,7 +106,6 @@
PreserveNewest
-
@@ -119,5 +119,8 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/BossMod/Modules/Global/DeepDungeon/DDTrapsData.sqlite3 b/BossMod/DDTrapsData.sqlite3
similarity index 100%
rename from BossMod/Modules/Global/DeepDungeon/DDTrapsData.sqlite3
rename to BossMod/DDTrapsData.sqlite3
diff --git a/BossMod/Framework/Plugin.cs b/BossMod/Framework/Plugin.cs
index fe908d624..5ca8cf9be 100644
--- a/BossMod/Framework/Plugin.cs
+++ b/BossMod/Framework/Plugin.cs
@@ -108,6 +108,8 @@ public unsafe Plugin(IDalamudPluginInterface dalamud, ICommandManager commandMan
dalamud.UiBuilder.Draw += DrawUI;
dalamud.UiBuilder.OpenMainUi += () => OpenConfigUI();
dalamud.UiBuilder.OpenConfigUi += () => OpenConfigUI();
+
+ Global.DeepDungeon.DDTrapsData.Initialize(dalamud);
}
public void Dispose()
diff --git a/BossMod/Modules/Global/DeepDungeon/AutoClear.cs b/BossMod/Modules/Global/DeepDungeon/AutoClear.cs
index 9c8af37a5..60d1f4c6c 100644
--- a/BossMod/Modules/Global/DeepDungeon/AutoClear.cs
+++ b/BossMod/Modules/Global/DeepDungeon/AutoClear.cs
@@ -142,7 +142,6 @@ protected override void Dispose(bool disposing)
_subscriptions.Dispose();
_obstacles.Dispose();
base.Dispose(disposing);
- DDTrapsData.CleanupTemporaryDatabase();
}
protected virtual void OnCastStarted(Actor actor) { }
@@ -393,8 +392,13 @@ public override void CalculateAIHints(int playerSlot, Actor player, AIHints hint
if (!Config.Enable || Palace.IsBossFloor || BetweenFloors)
return;
- foreach (var (w, rot) in Walls)
- hints.AddForbiddenZone(ShapeDistance.Rect(w.Position, (rot ? 90f : 0f).Degrees(), w.Depth, w.Depth, 20));
+ var countWalls = Walls.Count;
+ for (var i = 0; i < countWalls; ++i)
+ {
+ var wall = Walls[i];
+ var w = wall.Wall;
+ hints.AddForbiddenZone(ShapeDistance.Rect(w.Position, (wall.Rotated ? 90f : 0f).Degrees(), w.Depth, w.Depth, 20f));
+ }
HandleFloorPathfind(player, hints);
DrawAOEs(playerSlot, player, hints);
@@ -461,17 +465,19 @@ public override void CalculateAIHints(int playerSlot, Actor player, AIHints hint
if (Config.TrapHints && _trapsHidden)
{
- var count = _trapsCurrentZone.Count;
- var traps = new List>(count);
+ var countTraps = _trapsCurrentZone.Count;
+ var traps = new List>(countTraps);
- foreach (var trap in _trapsCurrentZone)
+ for (var i = 0; i < countTraps; ++i)
{
+ var trap = _trapsCurrentZone[i];
if (trap.InCircle(player.Position, 30f))
{
var shouldIgnore = false;
- foreach (var b in IgnoreTraps)
+ var countIgnoreTraps = IgnoreTraps.Count;
+ for (var j = 0; i < countIgnoreTraps; ++j)
{
- if (b.AlmostEqual(trap, 1f))
+ if (IgnoreTraps[i].AlmostEqual(trap, 1f))
{
shouldIgnore = true;
break;
@@ -562,8 +568,10 @@ void pickBetterTarget(Actor t)
bestTarget = t;
}
- foreach (var pp in hints.PotentialTargets)
+ var counttargets = hints.PotentialTargets.Count;
+ for (var i = 0; i < counttargets; ++i)
{
+ var pp = hints.PotentialTargets[i];
// enemy is petrified, any damage will kill
if (pp.Actor.FindStatus((uint)SID.StoneCurse)?.ExpireAt > World.FutureTime(1.5d))
pickBetterTarget(pp.Actor);
@@ -573,10 +581,26 @@ void pickBetterTarget(Actor t)
pickBetterTarget(pp.Actor);
// if player does not have a target, prioritize everything so that AI picks one - skip dangerous enemies
- else if (shouldTargetMobs && !pp.Actor.Statuses.Any(s => IsDangerousOutOfCombatStatus(s.ID)))
- pickBetterTarget(pp.Actor);
- }
+ else if (shouldTargetMobs)
+ {
+ var hasDangerousStatus = false;
+ var len = pp.Actor.Statuses.Length;
+ ref var statuses = ref pp.Actor.Statuses;
+ for (var j = 0; j < len; ++j)
+ {
+ if (IsDangerousOutOfCombatStatus(statuses[j].ID))
+ {
+ hasDangerousStatus = true;
+ break;
+ }
+ }
+ if (!hasDangerousStatus)
+ {
+ pickBetterTarget(pp.Actor);
+ }
+ }
+ }
hints.ForcedTarget = bestTarget;
}
@@ -831,72 +855,46 @@ private static bool IsBlocked(Bitmap map, Vector2 point, Vector2 origin, float m
return false;
}
- private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossModReborn.Modules.Global.DeepDungeon.{name}") ?? throw new InvalidDataException($"Missing embedded resource {name}");
+ private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossModReborn.Modules.Global.DeepDungeon.{name}")!;
}
-static class DDTrapsData
+public static class DDTrapsData
{
- private const string EmbeddedDbResourceName = "BossModReborn.Modules.Global.DeepDungeon.DDTrapsData.sqlite3";
- private static string? _tempDbFilePath;
+ private static string? _path;
- private static string GetTempDbFilePath()
+ public static void Initialize(Dalamud.Plugin.IDalamudPluginInterface dalamud)
{
- if (_tempDbFilePath != null)
- {
- return _tempDbFilePath;
- }
-
- var tempFileName = Path.GetTempFileName() + ".sqlite3";
- _tempDbFilePath = tempFileName;
-
- using (var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(EmbeddedDbResourceName))
- {
- if (resourceStream == null)
- {
- throw new FileNotFoundException($"Embedded resource '{EmbeddedDbResourceName}' not found.");
- }
-
- using var fileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.Write);
- resourceStream.CopyTo(fileStream);
- }
- return tempFileName;
+ _path = Path.Combine(dalamud.AssemblyLocation.DirectoryName!, "DDTrapsData.sqlite3");
}
-
+ // TODO: find a better solution, performance does not seem that good and creates a copy of SQLite.Interop.dll in temp folder for some reason which does not automatically get cleaned up
public static List GetTrapLocationsForZone(uint zone)
{
List locations = [];
- var tempDbPath = GetTempDbFilePath();
- using (var connection = new SQLiteConnection($"Data Source={tempDbPath};Version=3;Read Only=True;"))
+ try
{
- connection.Open();
+ using (var connection = new SQLiteConnection($"Data Source={_path}"))
+ {
+ connection.Open();
- var command = connection.CreateCommand();
- command.CommandText = @"select X,Z from Locations where Type = 1 and TerritoryType = $tt";
- command.Parameters.AddWithValue("$tt", zone);
+ var command = connection.CreateCommand();
+ command.CommandText = @"select X,Z from Locations where Type = 1 and TerritoryType = $tt";
+ command.Parameters.AddWithValue("$tt", zone);
- using var reader = command.ExecuteReader();
- while (reader.Read())
- {
- var x = reader.GetFloat(0);
- var z = reader.GetFloat(1);
- locations.Add(new(x, z));
+ using var reader = command.ExecuteReader();
+ while (reader.Read())
+ {
+ var x = reader.GetFloat(0);
+ var z = reader.GetFloat(1);
+ locations.Add(new(x, z));
+ }
}
- }
- return locations;
- }
- public static void CleanupTemporaryDatabase()
- {
- if (_tempDbFilePath != null)
+ return locations;
+ }
+ catch (SQLiteException e)
{
- var baseTempPath = Path.GetFileNameWithoutExtension(_tempDbFilePath);
- var tempDirPath = Path.GetDirectoryName(_tempDbFilePath) ?? "";
-
- string[] extensions = [".sqlite3", ".sqlite3-shm", ".sqlite3-wal", ""];
-
- for (var i = 0; i < 4; ++i)
- File.Delete(Path.Combine(tempDirPath, baseTempPath + extensions[i]));
+ Service.Log($"unable to load traps for zone ${zone}: ${e}");
+ return [];
}
- _tempDbFilePath = null;
}
}
diff --git a/BossMod/Modules/Global/DeepDungeon/Config.cs b/BossMod/Modules/Global/DeepDungeon/Config.cs
index 75993cf94..6f23bc124 100644
--- a/BossMod/Modules/Global/DeepDungeon/Config.cs
+++ b/BossMod/Modules/Global/DeepDungeon/Config.cs
@@ -19,7 +19,7 @@ public enum ClearBehavior
public bool Enable = true;
[PropertyDisplay("Enable minimap")]
public bool EnableMinimap = true;
- [PropertyDisplay("Try to avoid traps", tooltip: "Avoid known trap locations sourced from PalacePal data. Does not need PalacePal installed since data is embedded into BMR. (Traps revealed by a Pomander of Sight will always be avoided regardless of this setting.)")]
+ [PropertyDisplay("Try to avoid traps", tooltip: "Avoid known trap locations sourced from PalacePal data. Does not need PalacePal installed since data is included in BMR. (Traps revealed by a Pomander of Sight will always be avoided regardless of this setting.)")]
public bool TrapHints = true;
[PropertyDisplay("Automatically navigate to Cairn of Passage")]
public bool AutoPassage = true;