Skip to content

Commit

Permalink
Merge pull request #556 from xanunderscore/obmap-saved
Browse files Browse the repository at this point in the history
load bitmaps from manifest stream
  • Loading branch information
awgil authored Dec 11, 2024
2 parents 6dc2b72 + a573c43 commit 50dfbec
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 34 deletions.
5 changes: 5 additions & 0 deletions BossMod/BossMod.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup Condition="'$(Configuration)' == 'Release'">
<EmbeddedResource Include="Pathfinding\ObstacleMaps\maplist.json" />
<EmbeddedResource Include="Pathfinding\ObstacleMaps\*.bmp" />
</ItemGroup>
</Project>
62 changes: 41 additions & 21 deletions BossMod/Pathfinding/ObstacleMapDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Reflection;
using System.Text.Json;

namespace BossMod.Pathfinding;
Expand All @@ -19,37 +20,56 @@ public sealed record class Entry(Vector3 MinBounds, Vector3 MaxBounds, WPos Orig

public readonly Dictionary<uint, List<Entry>> Entries = [];

public void Load(string listPath)
public void LoadFromAssembly()
{
Entries.Clear();
try
{
using var json = Serialization.ReadJson(listPath);
foreach (var jentries in json.RootElement.EnumerateObject())
{
var sep = jentries.Name.IndexOf('.', StringComparison.Ordinal);
var zone = sep >= 0 ? uint.Parse(jentries.Name.AsSpan()[..sep]) : uint.Parse(jentries.Name);
var cfc = sep >= 0 ? uint.Parse(jentries.Name.AsSpan()[(sep + 1)..]) : 0;
var entries = Entries[(zone << 16) | cfc] = [];
foreach (var jentry in jentries.Value.EnumerateArray())
{
entries.Add(new(
ReadVec3(jentry, nameof(Entry.MinBounds)),
ReadVec3(jentry, nameof(Entry.MaxBounds)),
ReadWPos(jentry, nameof(Entry.Origin)),
jentry.GetProperty(nameof(Entry.ViewWidth)).GetInt32(),
jentry.GetProperty(nameof(Entry.ViewHeight)).GetInt32(),
jentry.GetProperty(nameof(Entry.Filename)).GetString() ?? ""
));
}
}
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("BossMod.Pathfinding.ObstacleMaps.maplist.json") ?? throw new InvalidDataException("Embedded obstacle map file missing");
LoadInternal(stream);
}
catch (Exception ex)
{
Service.Log($"Failed to load embedded obstacle map database: {ex}");
}
}

public void LoadFromFile(string listPath)
{
using var fstream = File.OpenRead(listPath);
try
{
LoadInternal(fstream);
}
catch (Exception ex)
{
Service.Log($"Failed to load obstacle map database '{listPath}': {ex}");
}
}

private void LoadInternal(Stream stream)
{
Entries.Clear();
using var json = JsonDocument.Parse(stream, new JsonDocumentOptions() { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip });
foreach (var jentries in json.RootElement.EnumerateObject())
{
var sep = jentries.Name.IndexOf('.', StringComparison.Ordinal);
var zone = sep >= 0 ? uint.Parse(jentries.Name.AsSpan()[..sep]) : uint.Parse(jentries.Name);
var cfc = sep >= 0 ? uint.Parse(jentries.Name.AsSpan()[(sep + 1)..]) : 0;
var entries = Entries[(zone << 16) | cfc] = [];
foreach (var jentry in jentries.Value.EnumerateArray())
{
entries.Add(new(
ReadVec3(jentry, nameof(Entry.MinBounds)),
ReadVec3(jentry, nameof(Entry.MaxBounds)),
ReadWPos(jentry, nameof(Entry.Origin)),
jentry.GetProperty(nameof(Entry.ViewWidth)).GetInt32(),
jentry.GetProperty(nameof(Entry.ViewHeight)).GetInt32(),
jentry.GetProperty(nameof(Entry.Filename)).GetString() ?? ""
));
}
}
}

public void Save(string listPath)
{
try
Expand Down
56 changes: 45 additions & 11 deletions BossMod/Pathfinding/ObstacleMapManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace BossMod.Pathfinding;
using System.Reflection;

namespace BossMod.Pathfinding;

[ConfigDisplay(Name = "Obstacle map development", Order = 8)]
public sealed class ObstacleMapConfig : ConfigNode
Expand All @@ -19,6 +21,8 @@ public sealed class ObstacleMapManager : IDisposable
private readonly EventSubscriptions _subscriptions;
private readonly List<(ObstacleMapDatabase.Entry entry, Bitmap data)> _entries = [];

public bool LoadFromSource => _config.LoadFromSource;

public ObstacleMapManager(WorldState ws)
{
World = ws;
Expand All @@ -41,10 +45,19 @@ public void Dispose()

public void ReloadDatabase()
{
var dbPath = _config.LoadFromSource ? _config.SourcePath : ""; // TODO: load from near assembly instead
Service.Log($"Loading obstacle database from '{dbPath}'");
Database.Load(dbPath);
RootPath = dbPath[..(dbPath.LastIndexOfAny(['\\', '/']) + 1)];
if (LoadFromSource)
{
var dbPath = _config.SourcePath;
Service.Log($"Loading obstacle database from '{dbPath}'");
Database.LoadFromFile(dbPath);
RootPath = dbPath[..(dbPath.LastIndexOfAny(['\\', '/']) + 1)];
}
else
{
Service.Log($"Loading embedded obstacle database");
Database.LoadFromAssembly();
}

LoadMaps(World.CurrentZone, World.CurrentCFCID);
}

Expand All @@ -63,15 +76,36 @@ private void LoadMaps(ushort zoneId, ushort cfcId)
{
foreach (var e in entries)
{
var filename = RootPath + e.Filename;
try
if (LoadFromSource)
{
var bitmap = new Bitmap(filename);
_entries.Add((e, bitmap));
var filename = RootPath + e.Filename;
try
{
var bitmap = new Bitmap(filename);
_entries.Add((e, bitmap));
}
catch (Exception ex)
{
Service.Log($"Failed to load map {filename} for {zoneId}.{cfcId}: {ex}");
}
}
catch (Exception ex)
else
{
Service.Log($"Failed to load map {filename} for {zoneId}.{cfcId}: {ex}");
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossMod.Pathfinding.ObstacleMaps.{e.Filename}");
if (stream == null)
{
Service.Log($"Embedded map missing for {zoneId}.{cfcId}");
continue;
}
try
{
var bitmap = new Bitmap(stream);
_entries.Add((e, bitmap));
}
catch (Exception ex)
{
Service.Log($"Failed to load embedded map for {zoneId}.{cfcId}: {ex}");
}
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions BossMod/Util/Bitmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,8 @@ public Bitmap(int width, int height, Color color0, Color color1, int resolution
Pixels = new byte[height * BytesPerRow];
}

public Bitmap(string filename)
public Bitmap(Stream fstream, string filename = "<none>")
{
using var fstream = File.OpenRead(filename);
using var reader = new BinaryReader(fstream);
var fileHeader = fstream.ReadStruct<FileHeader>();
if (fileHeader.Type != Magic)
Expand Down Expand Up @@ -183,6 +182,8 @@ public Bitmap(string filename)
Pixels = reader.ReadBytes(Height * BytesPerRow);
}

public Bitmap(string filename) : this(File.OpenRead(filename), filename) { }

public void Save(string filename)
{
using var fstream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
Expand Down

0 comments on commit 50dfbec

Please sign in to comment.