UITK HUD rework + build palette (click-to-place ghost)

Rebuild the in-game HUD on UI Toolkit (HudUi/HudSystem, Aether palette) consistent with the menu; build-palette bar (BuildPaletteState) drives cursor->cell ground-ghost preview (green/red via BuildPreviewMath), left-click place / right-click cancel / rotate; fire suppressed in build mode; combat juice restyle. +4 BuildPreviewMath EditMode tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 15:05:49 -07:00
parent f31ffe910b
commit a4edf7a03b
13 changed files with 579 additions and 219 deletions
@@ -0,0 +1,55 @@
using NUnit.Framework;
using ProjectM.Simulation;
using Unity.Mathematics;
namespace ProjectM.Tests
{
/// <summary>
/// Pure tests for <see cref="BuildPreviewMath"/> — the client build-ghost validity (in-plot, unoccupied,
/// affordable) that mirrors the server's authoritative BuildPlaceSystem check, colouring the ground ghost
/// green (valid) vs red (the first failing reason).
/// </summary>
public class BuildPreviewMathTests
{
static BaseAnchor Anchor() => new BaseAnchor
{
AnchorPos = new float3(0, 0, 0),
GridOrigin = new float3(0, 0, 0),
CellSize = 1f,
GridDims = new int2(8, 8),
};
[Test]
public void InPlot_Unoccupied_Affordable_IsValid()
{
Assert.AreEqual(BuildPreviewMath.Valid,
BuildPreviewMath.Evaluate(Anchor(), new int2(3, 3), occupied: false, have: 50, cost: 20));
}
[Test]
public void OutOfPlot_Reported_First()
{
Assert.AreEqual(BuildPreviewMath.OutOfPlot,
BuildPreviewMath.Evaluate(Anchor(), new int2(99, 0), occupied: true, have: 0, cost: 999),
"Out-of-plot is reported before occupancy / cost.");
Assert.AreEqual(BuildPreviewMath.OutOfPlot,
BuildPreviewMath.Evaluate(Anchor(), new int2(-1, 3), occupied: false, have: 50, cost: 10));
}
[Test]
public void Occupied_Cell_IsBlocked()
{
Assert.AreEqual(BuildPreviewMath.Occupied,
BuildPreviewMath.Evaluate(Anchor(), new int2(3, 3), occupied: true, have: 50, cost: 10));
}
[Test]
public void Unaffordable_When_Have_Below_Cost_Exact_Funds_Ok()
{
Assert.AreEqual(BuildPreviewMath.Unaffordable,
BuildPreviewMath.Evaluate(Anchor(), new int2(3, 3), occupied: false, have: 5, cost: 20));
Assert.AreEqual(BuildPreviewMath.Valid,
BuildPreviewMath.Evaluate(Anchor(), new int2(3, 3), occupied: false, have: 20, cost: 20));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2d3f16d92d3045044a9efd5545320111