Skip to content

Commit

Permalink
Merge branch 'merge' into mergeWIP
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Dec 12, 2024
2 parents f3995f0 + e3f783e commit ee6a361
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 53 deletions.
4 changes: 4 additions & 0 deletions BossMod/BossModReborn.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,8 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup Condition="'$(Configuration)' == 'Release'">
<EmbeddedResource Include="Pathfinding\ObstacleMaps\*" />
</ItemGroup>
</Project>
12 changes: 7 additions & 5 deletions BossMod/Debug/DebugObstacles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ protected override void DrawSidebar()
ImGui.SameLine();
if (ImGui.Button("Reload"))
{
CheckpointNoClone(new(owner.Obstacles.RootPath + e.Filename));
using var stream = File.OpenRead(owner.Obstacles.RootPath + e.Filename);
CheckpointNoClone(new(stream));
}

ImGui.SetNextItemWidth(100);
Expand Down Expand Up @@ -162,6 +163,7 @@ public void Draw()
private void DrawEntries(List<ObstacleMapDatabase.Entry> entries)
{
Action? modifications = null;
using var disableScope = ImRaii.Disabled(!Obstacles.CanEditDatabase());
for (int i = 0; i < entries.Count; ++i)
{
using var id = ImRaii.PushId(i);
Expand All @@ -174,9 +176,8 @@ private void DrawEntries(List<ObstacleMapDatabase.Entry> entries)
if (ImGui.Button("Move down"))
modifications += () => (entries[index], entries[index + 1]) = (entries[index + 1], entries[index]);
ImGui.SameLine();
using (ImRaii.Disabled(!Obstacles.CanEditDatabase()))
if (ImGui.Button("Delete"))
modifications += () => DeleteMap(entries, index);
if (ImGui.Button("Delete"))
modifications += () => DeleteMap(entries, index);
ImGui.SameLine();
if (ImGui.Button("Edit"))
OpenEditor(entries[index]);
Expand Down Expand Up @@ -230,7 +231,8 @@ private string GenerateMapName()

private void OpenEditor(ObstacleMapDatabase.Entry entry)
{
var editor = new Editor(this, new(Obstacles.RootPath + entry.Filename), entry);
using var stream = File.OpenRead(Obstacles.RootPath + entry.Filename);
var editor = new Editor(this, new(stream), entry);
_ = new UISimpleWindow($"Obstacle map {entry.Filename}", editor.Draw, true, new(1000, 1000));
}
}
39 changes: 16 additions & 23 deletions BossMod/Pathfinding/ObstacleMapDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,28 @@ 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 Load(Stream stream)
{
Entries.Clear();
try
using var json = Serialization.ReadJson(stream);
foreach (var jentries in json.RootElement.EnumerateObject())
{
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())
{
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() ?? ""
));
}
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() ?? ""
));
}
}
catch (Exception ex)
{
Service.Log($"Failed to load obstacle map database '{listPath}': {ex}");
}
}

public void Save(string listPath)
Expand Down
33 changes: 25 additions & 8 deletions BossMod/Pathfinding/ObstacleMapManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace BossMod.Pathfinding;
using System.IO;
using System.Reflection;

namespace BossMod.Pathfinding;

[ConfigDisplay(Name = "Obstacle map development", Order = 8)]
public sealed class ObstacleMapConfig : ConfigNode
Expand All @@ -19,6 +22,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 +46,20 @@ 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)];
Service.Log($"Loading obstacle database from {(_config.LoadFromSource ? _config.SourcePath : "<embedded>")}");
RootPath = _config.LoadFromSource ? _config.SourcePath[..(_config.SourcePath.LastIndexOfAny(['\\', '/']) + 1)] : "";

try
{
using var dbStream = _config.LoadFromSource ? File.OpenRead(_config.SourcePath) : GetEmbeddedResource("maplist.json");
Database.Load(dbStream);
}
catch (Exception ex)
{
Service.Log($"Failed to load obstacle database: {ex}");
Database.Entries.Clear();
}

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

Expand All @@ -63,17 +78,19 @@ private void LoadMaps(ushort zoneId, ushort cfcId)
{
foreach (var e in entries)
{
var filename = RootPath + e.Filename;
try
{
var bitmap = new Bitmap(filename);
using var eStream = _config.LoadFromSource ? File.OpenRead(RootPath + e.Filename) : GetEmbeddedResource(e.Filename);
var bitmap = new Bitmap(eStream);
_entries.Add((e, bitmap));
}
catch (Exception ex)
{
Service.Log($"Failed to load map {filename} for {zoneId}.{cfcId}: {ex}");
Service.Log($"Failed to load map {e.Filename} from {(_config.LoadFromSource ? RootPath : "<embedded>")} for {zoneId}.{cfcId}: {ex}");
}
}
}
}

private Stream GetEmbeddedResource(string name) => Assembly.GetExecutingAssembly().GetManifestResourceStream($"BossMod.Pathfinding.ObstacleMaps.{name}") ?? throw new InvalidDataException($"Missing embedded resource {name}");
}
25 changes: 12 additions & 13 deletions BossMod/Util/Bitmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,29 +150,28 @@ public Bitmap(int width, int height, Color color0, Color color1, int resolution
Pixels = new byte[height * BytesPerRow];
}

public Bitmap(string filename)
public Bitmap(Stream stream)
{
using var fstream = File.OpenRead(filename);
using var reader = new BinaryReader(fstream);
var fileHeader = fstream.ReadStruct<FileHeader>();
using var reader = new BinaryReader(stream);
var fileHeader = stream.ReadStruct<FileHeader>();
if (fileHeader.Type != Magic)
throw new ArgumentException($"File '{filename}' is not a bitmap: magic is {fileHeader.Type:X4}");
throw new ArgumentException($"Not a bitmap: magic is {fileHeader.Type:X4}");

var header = fstream.ReadStruct<BitmapInfoHeader>();
var header = stream.ReadStruct<BitmapInfoHeader>();
if (header.SizeInBytes != Marshal.SizeOf<BitmapInfoHeader>())
throw new ArgumentException($"Bitmap '{filename}' has unsupported header size {header.SizeInBytes}");
throw new ArgumentException($"Bitmap has unsupported header size {header.SizeInBytes}");
if (header.Width <= 0)
throw new ArgumentException($"Bitmap '{filename}' has non-positive width {header.Width}");
throw new ArgumentException($"Bitmap has non-positive width {header.Width}");
if (header.Height >= 0)
throw new ArgumentException($"Bitmap '{filename}' is not top-down (height={header.Height})");
throw new ArgumentException($"Bitmap is not top-down (height={header.Height})");
if (header.BitCount != 1)
throw new ArgumentException($"Bitmap '{filename}' is not 1bpp (bitcount={header.BitCount})");
throw new ArgumentException($"Bitmap is not 1bpp (bitcount={header.BitCount})");
if (header.Compression != 0)
throw new ArgumentException($"Bitmap '{filename}' has unsupported compression method {header.Compression:X8}");
throw new ArgumentException($"Bitmap has unsupported compression method {header.Compression:X8}");
if (header.XPixelsPerMeter != header.YPixelsPerMeter || header.XPixelsPerMeter <= 0)
throw new ArgumentException($"Bitmap '{filename}' has inconsistent or non-positive resolution {header.XPixelsPerMeter}x{header.YPixelsPerMeter}");
throw new ArgumentException($"Bitmap has inconsistent or non-positive resolution {header.XPixelsPerMeter}x{header.YPixelsPerMeter}");
if (header.ColorUsedCount is not 0 or 2)
throw new ArgumentException($"Bitmap '{filename}' has wrong palette size {header.ColorUsedCount}");
throw new ArgumentException($"Bitmap has wrong palette size {header.ColorUsedCount}");

Width = header.Width;
Height = -header.Height;
Expand Down
3 changes: 2 additions & 1 deletion BossMod/Util/Serialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ public class JsonTypeConverter : JsonConverter<Type>
public static JsonDocument ReadJson(string path)
{
using var fstream = File.OpenRead(path);
return JsonDocument.Parse(fstream, new JsonDocumentOptions() { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip });
return ReadJson(fstream);
}

public static JsonDocument ReadJson(Stream stream) => JsonDocument.Parse(stream, new JsonDocumentOptions() { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip });
public static Utf8JsonWriter WriteJson(Stream fstream, bool indented = true) => new(fstream, new JsonWriterOptions() { Indented = indented });

public static unsafe T ReadStruct<T>(this Stream stream) where T : unmanaged
Expand Down
2 changes: 0 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ general:
- zone modules: module info ui
- refactor ipc/dtr
- questbattles
- collisions for pathfinding
-- embedded mode

boss modules:
- timers
Expand Down
4 changes: 3 additions & 1 deletion UIDev/BitmapEditorTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BossMod;
using ImGuiNET;
using System.IO;

namespace UIDev;

Expand Down Expand Up @@ -43,7 +44,8 @@ protected override void DrawSidebar()

if (ImGui.Button("load"))
{
CheckpointNoClone(new("D:\\test.bmp"));
using var stream = File.OpenRead("D:\\test.bmp");
CheckpointNoClone(new(stream));
}
}

Expand Down

0 comments on commit ee6a361

Please sign in to comment.