CI / build-test (push) Failing after 1m7s
Collisions: init bucket heads to -1 (QueryAabb hung before the first rebuild), reset query stamps on truncated QueryAabb (later queries silently dropped entities), inside-origin raycasts hit at fraction 0 for circles too, exactly-touching boxes now pair like touching circles. Graphics: render into the letterbox viewport so the picture matches ScreenToWorld/WorldToScreen instead of stretching; Y-sort by the transform pivot rather than the quad center; lock-free snapshot LayerRegistry (parallel submit read it unsynchronized); validate InitialCapacity; warn when UseRenderer2D drops options of a later scene. Core: scenes are explicitly single-use (re-loading threw silently duplicated systems/entities before — now it throws), Scene.RegisterUnload for per-scene resources, a switch requested during the reveal phase covers again instead of hard-swapping, borderless fullscreen (HardwareModeSwitch off), InputCapture service for input-suppressing overlays, host disposes the transition renderer and IDisposable services on shutdown. Input: game input reads as released while InputCapture is held; mouse position and wheel freeze so deltas stay zero. DevConsole: holds InputCapture while open (typing no longer drives the camera), Revision increments only under the lock, quoted command arguments, history capped at 256. UI: scene Desktop skips Myra input processing while the console is open (clicks no longer fall through), is disposed on scene unload, and Myra init no longer depends on a process-static flag. Audio: validate channel count/sample rate before stopping the previous track, empty looped oggs no longer hang FillBuffers, the instance stops when a non-looping track drains (IsPlaying was stuck true). Atlases: metadata v2 stores per-source size+mtime snapshots, so timestamp-preserving copies and renames invalidate correctly; loader checks the version and disposes pages on partial load failure; shared pages never exceed a non-POT MaxPageSize; oversized items pack first onto exact-size pages instead of splitting an open shared page; the CLI validates numeric options. Assets.Generator: file names are escaped in XML docs and string literals, members no longer collide with the enclosing class (CS0542), and the Assets root is resolved against build_property.projectdir so nested "Assets" directories do not shift region paths. Pathfinding: queries throw when the grid was resized after construction; generation stamps survive int overflow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71 lines
2.3 KiB
C#
71 lines
2.3 KiB
C#
using System.Diagnostics;
|
|
using MrGameEng.Atlases;
|
|
|
|
if (args.Length < 2 || args.Contains("--help") || args.Contains("-h"))
|
|
{
|
|
Console.WriteLine(
|
|
"""
|
|
MrGameEng.AtlasTool — packs a directory tree of images into texture atlases.
|
|
|
|
Usage: MrGameEng.AtlasTool <source-dir> <output-dir> [options]
|
|
|
|
Options:
|
|
--group-depth <n> directories forming one atlas (0 = single atlas; default 1)
|
|
--page-size <n> maximum page size in pixels (default 2048)
|
|
--padding <n> gap between images in pixels (default 2)
|
|
--root-name <name> atlas name for files above group depth (default "Atlas")
|
|
--force rebuild even when sources are unchanged
|
|
""");
|
|
return args.Length < 2 && !args.Contains("--help") && !args.Contains("-h") ? 1 : 0;
|
|
}
|
|
|
|
int Option(string name, int fallback)
|
|
{
|
|
var index = Array.IndexOf(args, name);
|
|
if (index < 0)
|
|
{
|
|
return fallback;
|
|
}
|
|
|
|
if (index + 1 < args.Length && int.TryParse(args[index + 1], out var value) && value >= 0)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
Console.Error.WriteLine($"Option {name} requires a non-negative integer value.");
|
|
Environment.Exit(1);
|
|
return fallback; // недостижимо
|
|
}
|
|
|
|
var rootNameIndex = Array.IndexOf(args, "--root-name");
|
|
var options = new AtlasBuildOptions
|
|
{
|
|
SourceDirectory = args[0],
|
|
OutputDirectory = args[1],
|
|
GroupDepth = Option("--group-depth", 1),
|
|
MaxPageSize = Option("--page-size", 2048),
|
|
Padding = Option("--padding", 2),
|
|
RootAtlasName = rootNameIndex >= 0 && rootNameIndex + 1 < args.Length ? args[rootNameIndex + 1] : "Atlas",
|
|
Force = args.Contains("--force"),
|
|
};
|
|
|
|
var stopwatch = Stopwatch.StartNew();
|
|
var result = AtlasBuilder.Build(options);
|
|
stopwatch.Stop();
|
|
|
|
foreach (var group in result.Groups)
|
|
{
|
|
Console.WriteLine(group.Skipped
|
|
? $" {group.Name}: up to date ({group.RegionCount} regions, {group.PageCount} pages)"
|
|
: $" {group.Name}: {group.RegionCount} regions -> {group.PageCount} pages");
|
|
}
|
|
|
|
foreach (var orphan in result.DeletedOrphans)
|
|
{
|
|
Console.WriteLine($" deleted orphan {orphan}");
|
|
}
|
|
|
|
var built = result.Groups.Count(g => !g.Skipped);
|
|
Console.WriteLine($"Done: {built} atlases built, {result.Groups.Count - built} up to date, {stopwatch.Elapsed.TotalSeconds:F1}s.");
|
|
return 0;
|