using System;
namespace IslaApocalypse.Core
{
///
/// A material's IDENTITY. → `Design - Data - Material Schema.md`, D-054.
///
/// ⚠⚠ IDENTITY IS A REGISTRY KEY, NEVER A POSITIONAL ORDINAL.
///
/// This is deliberately a stable string key and not an enum. The prototype's blueprint format
/// keyed on enum ordinals, which made the enum's DECLARATION ORDER a wire format: inserting a
/// value in the middle silently reinterpreted every world already generated
/// (→ `Design - Tooling - Offline Generation.md`: "anything that changes its format or its enum
/// ordinals breaks every world already generated"). The registry is also the mod surface
/// (→ D-011, D-043) — a mod adds rows, and rows cannot be given ordinals by a third party.
///
/// So: adding a material is one new row, appended anywhere, in any order, by anyone, forever.
///
/// No serialization is built this phase. This type exists so that when it is, the identity it
/// writes is already the key rather than a position.
///
public readonly struct MaterialKey : IEquatable
{
/// The stable identity. Lowercase, dot-namespaced: "core.limestone", "mod.basalt".
public readonly string Value;
public MaterialKey(string value)
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("A material key may not be null or blank.", nameof(value));
Value = value;
}
/// The unset key. Distinguishable from any real row; never registered.
public static readonly MaterialKey None = default;
public bool IsNone => Value == null;
public bool Equals(MaterialKey other) => string.Equals(Value, other.Value, StringComparison.Ordinal);
public override bool Equals(object obj) => obj is MaterialKey k && Equals(k);
public override int GetHashCode() => Value == null ? 0 : StringComparer.Ordinal.GetHashCode(Value);
public override string ToString() => Value ?? "";
public static bool operator ==(MaterialKey a, MaterialKey b) => a.Equals(b);
public static bool operator !=(MaterialKey a, MaterialKey b) => !a.Equals(b);
}
}