diff --git a/BossMod/BossModReborn.csproj b/BossMod/BossModReborn.csproj
index 041817aa5..798c4e155 100644
--- a/BossMod/BossModReborn.csproj
+++ b/BossMod/BossModReborn.csproj
@@ -105,9 +105,16 @@
PreserveNewest
+
-
+
+
+
+
+ PreserveNewest
+
+
diff --git a/BossMod/Modules/Global/DeepDungeon/AutoClear.cs b/BossMod/Modules/Global/DeepDungeon/AutoClear.cs
index 9542bee46..9c8af37a5 100644
--- a/BossMod/Modules/Global/DeepDungeon/AutoClear.cs
+++ b/BossMod/Modules/Global/DeepDungeon/AutoClear.cs
@@ -129,7 +129,7 @@ protected AutoClear(WorldState ws, int LevelCap) : base(ws)
})
);
- _trapsCurrentZone = PalacePalInterop.GetTrapLocationsForZone(ws.CurrentZone);
+ _trapsCurrentZone = DDTrapsData.GetTrapLocationsForZone(ws.CurrentZone);
LoadedFloors = JsonSerializer.Deserialize>>(GetEmbeddedResource("Walls.json"))!;
ProblematicTrapLocations = JsonSerializer.Deserialize>(GetEmbeddedResource("BadTraps.json"))!;
@@ -142,6 +142,7 @@ protected override void Dispose(bool disposing)
_subscriptions.Dispose();
_obstacles.Dispose();
base.Dispose(disposing);
+ DDTrapsData.CleanupTemporaryDatabase();
}
protected virtual void OnCastStarted(Actor actor) { }
@@ -830,45 +831,72 @@ private static bool IsBlocked(Bitmap map, Vector2 point, Vector2 origin, float m
return false;
}
- private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossMod.Modules.Global.DeepDungeon.{name}") ?? throw new InvalidDataException($"Missing embedded resource {name}");
+ private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossModReborn.Modules.Global.DeepDungeon.{name}") ?? throw new InvalidDataException($"Missing embedded resource {name}");
}
-static class PalacePalInterop
+static class DDTrapsData
{
- // TODO make an IPC for this? wouldn't work in uidev
- private static readonly string PalacePalDbFile = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "XIVLauncher", "pluginConfigs", "PalacePal", "palace-pal.data.sqlite3");
+ private const string EmbeddedDbResourceName = "BossModReborn.Modules.Global.DeepDungeon.DDTrapsData.sqlite3";
+ private static string? _tempDbFilePath;
- public static List GetTrapLocationsForZone(uint zone)
+ private static string GetTempDbFilePath()
{
- List locations = [];
+ if (_tempDbFilePath != null)
+ {
+ return _tempDbFilePath;
+ }
+
+ var tempFileName = Path.GetTempFileName() + ".sqlite3";
+ _tempDbFilePath = tempFileName;
- try
+ using (var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(EmbeddedDbResourceName))
{
- using (var connection = new SQLiteConnection($"Data Source={PalacePalDbFile}"))
+ if (resourceStream == null)
{
- connection.Open();
+ throw new FileNotFoundException($"Embedded resource '{EmbeddedDbResourceName}' not found.");
+ }
- var command = connection.CreateCommand();
- command.CommandText = @"
- select X,Z from Locations where Type = 1 and TerritoryType = $tt
- ";
- command.Parameters.AddWithValue("$tt", zone);
+ using var fileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.Write);
+ resourceStream.CopyTo(fileStream);
+ }
+ return tempFileName;
+ }
- using var reader = command.ExecuteReader();
- while (reader.Read())
- {
- var x = reader.GetFloat(0);
- var z = reader.GetFloat(1);
- locations.Add(new(x, z));
- }
- }
+ public static List GetTrapLocationsForZone(uint zone)
+ {
+ List locations = [];
+ var tempDbPath = GetTempDbFilePath();
+ using (var connection = new SQLiteConnection($"Data Source={tempDbPath};Version=3;Read Only=True;"))
+ {
+ connection.Open();
- return locations;
+ 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));
+ }
}
- catch (SQLiteException e)
+ return locations;
+ }
+
+ public static void CleanupTemporaryDatabase()
+ {
+ if (_tempDbFilePath != null)
{
- Service.Log($"unable to load traps for zone ${zone}: ${e}");
- return [];
+ 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]));
}
+ _tempDbFilePath = null;
}
}
diff --git a/BossMod/Modules/Global/DeepDungeon/Config.cs b/BossMod/Modules/Global/DeepDungeon/Config.cs
index e12659350..75993cf94 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. (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 embedded into 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;
diff --git a/BossMod/Modules/Global/DeepDungeon/DDTrapsData.sqlite3 b/BossMod/Modules/Global/DeepDungeon/DDTrapsData.sqlite3
new file mode 100644
index 000000000..7f684d16c
Binary files /dev/null and b/BossMod/Modules/Global/DeepDungeon/DDTrapsData.sqlite3 differ
diff --git a/BossMod/Pathfinding/ObstacleMapManager.cs b/BossMod/Pathfinding/ObstacleMapManager.cs
index 7b9662fc4..c71041417 100644
--- a/BossMod/Pathfinding/ObstacleMapManager.cs
+++ b/BossMod/Pathfinding/ObstacleMapManager.cs
@@ -9,7 +9,7 @@ public sealed class ObstacleMapConfig : ConfigNode
[PropertyDisplay("Developer mode: load obstacle maps from source rather than from plugin distribution")]
public bool LoadFromSource;
- [PropertyDisplay("Developer mode: source path", tooltip: "Should be /BossMod/Pathfinding/ObstacleMaps/maplist.json")]
+ [PropertyDisplay("Developer mode: source path", tooltip: "Should be /BossModReborn/Pathfinding/ObstacleMaps/maplist.json")]
public string SourcePath = "";
}
@@ -92,5 +92,5 @@ private void LoadMaps(ushort zoneId, ushort cfcId)
}
}
- private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossMod.Pathfinding.ObstacleMaps.{name}") ?? throw new InvalidDataException($"Missing embedded resource {name}");
+ private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossModReborn.Pathfinding.ObstacleMaps.{name}") ?? throw new InvalidDataException($"Missing embedded resource {name}");
}
diff --git a/BossMod/System.Data.SQLite.dll b/BossMod/System.Data.SQLite.dll
new file mode 100644
index 000000000..d99b135ad
Binary files /dev/null and b/BossMod/System.Data.SQLite.dll differ