129 lines
6.1 KiB
C#
129 lines
6.1 KiB
C#
using ProjectM.Simulation;
|
|
using UnityEngine;
|
|
using UnityEngine.TextCore.Text;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace ProjectM.Client
|
|
{
|
|
/// <summary>
|
|
/// Curated Synty sci-fi-soldier HUD skin — serialized <see cref="Sprite"/> + <see cref="Font"/> references
|
|
/// harvested from the InterfaceSciFiSoldierHUD / InterfaceCore packs and authored into
|
|
/// <c>Assets/_Project/Resources/HudTheme.asset</c>. Those source sprites/fonts live under
|
|
/// <c>Assets/Synty/…</c> (NOT a Resources folder), so a serialized asset like this is the build-safe way to
|
|
/// pull a curated subset into the player build (the dependency walker follows the refs). Loaded null-safe via
|
|
/// <see cref="Get"/> (mirrors <see cref="MenuUi.LoadPanelSettings"/>); EVERY consumer must null-check the theme
|
|
/// AND each field and fall back to the flat-color HUD, so a missing asset/ref never breaks (or magenta-s) the
|
|
/// HUD. Fonts are applied as cached SDF font definitions: a <see cref="FontAsset"/> is built once per font from
|
|
/// the serialized <see cref="Font"/> (crisp at any size, supports outlines) and re-built per play session (the
|
|
/// static cache is reset on play-enter, like the project's other static presentation bridges).
|
|
/// </summary>
|
|
[CreateAssetMenu(menuName = "ProjectM/HUD Theme", fileName = "HudTheme")]
|
|
public class HudTheme : ScriptableObject
|
|
{
|
|
[Header("Fonts")]
|
|
public Font DisplayFont; // Orbitron-ExtraBold — numerics + phase words (the HUD's authoritative voice)
|
|
public Font BodyFont; // Exo 2.0 SemiBold — labels
|
|
public Font BodyLightFont; // Exo 2.0 Regular — captions / hints
|
|
|
|
[Header("Panels & meters")]
|
|
public Sprite PanelBox; // 9-sliced card background (tinted per cluster)
|
|
public Sprite BarTrack; // bar fill skin
|
|
public Sprite Vignette; // radial edge gradient (low-HP / hurt flash / downed)
|
|
public Sprite Glow; // soft glow accent (selection / pulse)
|
|
public Sprite PipActive; // filled hex pip (goal meter)
|
|
public Sprite PipInactive; // empty hex pip
|
|
|
|
[Header("Status / info icons")]
|
|
public Sprite HealthIcon;
|
|
public Sprite ShieldIcon;
|
|
public Sprite ThreatIcon;
|
|
public Sprite GoalIcon;
|
|
public Sprite CooldownIcon;
|
|
public Sprite LocationBaseIcon;
|
|
public Sprite LocationExpeditionIcon;
|
|
|
|
[Header("Resource icons")]
|
|
public Sprite AetherIcon;
|
|
public Sprite OreIcon;
|
|
public Sprite BioIcon;
|
|
|
|
[Header("Structure icons")]
|
|
public Sprite TurretIcon;
|
|
public Sprite WallIcon;
|
|
public Sprite PylonIcon;
|
|
public Sprite HarvesterIcon;
|
|
public Sprite FabricatorIcon;
|
|
public Sprite ConveyorIcon;
|
|
|
|
[Header("Build-mode control glyphs")]
|
|
public Sprite KbmPlace; // LMB
|
|
public Sprite KbmCancel; // RMB
|
|
public Sprite PadPlace; // gamepad A / south
|
|
public Sprite PadCancel; // gamepad B / east
|
|
public Sprite PadRotate; // gamepad LB
|
|
public Sprite PadExit; // gamepad Menu / start
|
|
|
|
// ---- null-safe load + cache (mirrors MenuUi.LoadPanelSettings Resources idiom) ----
|
|
static HudTheme _cached;
|
|
static bool _tried;
|
|
|
|
/// <summary>The loaded theme, or null if the asset is missing. Callers MUST null-check this and each field.</summary>
|
|
public static HudTheme Get()
|
|
{
|
|
if (_tried) return _cached;
|
|
_tried = true;
|
|
_cached = Resources.Load<HudTheme>("HudTheme");
|
|
return _cached;
|
|
}
|
|
|
|
/// <summary>Icon for a <see cref="StructureType"/> byte (null → caller falls back to the structure name text).</summary>
|
|
public Sprite StructureIcon(byte type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case StructureType.Turret: return TurretIcon;
|
|
case StructureType.Wall: return WallIcon;
|
|
case StructureType.Pylon: return PylonIcon;
|
|
case StructureType.Harvester: return HarvesterIcon;
|
|
case StructureType.Fabricator: return FabricatorIcon;
|
|
case StructureType.Conveyor: return ConveyorIcon;
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
// ---- cached SDF font definitions (one FontAsset per font, built once, reset per play session) ----
|
|
static FontAsset _displayFa, _bodyFa, _bodyLightFa;
|
|
static bool _displayTried, _bodyTried, _bodyLightTried;
|
|
|
|
/// <summary>Apply the display font (Orbitron) to a style, if available. No-op otherwise (stock font).</summary>
|
|
public void ApplyDisplay(IStyle style) => Apply(style, DisplayFont, ref _displayFa, ref _displayTried);
|
|
|
|
/// <summary>Apply the body font (Exo 2.0 SemiBold) to a style, if available.</summary>
|
|
public void ApplyBody(IStyle style) => Apply(style, BodyFont, ref _bodyFa, ref _bodyTried);
|
|
|
|
/// <summary>Apply the light body font (Exo 2.0 Regular) to a style, if available.</summary>
|
|
public void ApplyBodyLight(IStyle style) => Apply(style, BodyLightFont, ref _bodyLightFa, ref _bodyLightTried);
|
|
|
|
static void Apply(IStyle style, Font font, ref FontAsset fa, ref bool tried)
|
|
{
|
|
if (!tried)
|
|
{
|
|
tried = true;
|
|
if (font != null) fa = FontAsset.CreateFontAsset(font); // dynamic SDF atlas, built once per session
|
|
}
|
|
if (fa != null)
|
|
style.unityFontDefinition = new StyleFontDefinition(FontDefinition.FromSDFFont(fa));
|
|
}
|
|
|
|
// Fast-enter-playmode keeps statics alive across sessions; the runtime FontAssets are destroyed on play-exit,
|
|
// so a stale cache would reference a destroyed atlas. Reset everything so it re-loads/re-builds per session.
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
static void ResetStatics()
|
|
{
|
|
_cached = null; _tried = false;
|
|
_displayFa = _bodyFa = _bodyLightFa = null;
|
|
_displayTried = _bodyTried = _bodyLightTried = false;
|
|
}
|
|
}
|
|
}
|