public struct Tile { public Corners Height; // TODO: Replace with enum or something more permanent? public byte TexturePrimary; public byte TextureSecondary; public byte TextureBlend; public readonly bool IsDefault => Height == default && TexturePrimary == 0 && TextureSecondary == 0 && TextureBlend == 0; public readonly override string ToString() => $"Tile {{ Height = {Height}, TexturePrimary = {TexturePrimary}, TextureSecondary = {TextureSecondary}, TextureBlend = {TextureBlend} }}"; } public readonly record struct TilePos(int X, int Z) { public Vector2 Center => new(X + 0.5f, Z + 0.5f); public static TilePos operator +(TilePos left, Vector2I right) => new(left.X + right.X, left.Z + right.Y); public static TilePos operator +(TilePos left, (int X, int Y) right) => new(left.X + right.X, left.Z + right.Y); public static TilePos operator -(TilePos left, Vector2I right) => new(left.X - right.X, left.Z - right.Y); public static TilePos operator -(TilePos left, (int X, int Y) right) => new(left.X - right.X, left.Z - right.Y); public static explicit operator TilePos(Vector2I value) => new(value.X, value.Y); public static explicit operator TilePos(Vector2 value) => new(FloorToInt(value.X), FloorToInt(value.Y)); public static explicit operator Vector2I(TilePos pos) => new(pos.X, pos.Z); } public struct Corners(T topLeft, T topRight, T bottomRight, T bottomLeft) : IEquatable> where T : IEquatable { public T TopLeft = topLeft; public T TopRight = topRight; public T BottomRight = bottomRight; public T BottomLeft = bottomLeft; public Corners(T value) : this(value, value, value, value) { } public T this[Corner corner] { readonly get => corner switch { Corner.TopLeft => TopLeft, Corner.TopRight => TopRight, Corner.BottomRight => BottomRight, Corner.BottomLeft => BottomLeft, _ => throw new ArgumentException($"Invalid Corner value '{corner}'", nameof(corner)), }; set { switch (corner) { case Corner.TopLeft : TopLeft = value; break; case Corner.TopRight : TopRight = value; break; case Corner.BottomRight : BottomRight = value; break; case Corner.BottomLeft : BottomLeft = value; break; default: throw new ArgumentException($"Invalid Corner value '{corner}'", nameof(corner)); } } } public readonly bool Equals(Corners other) => TopLeft .Equals(other.TopLeft ) && TopRight .Equals(other.TopRight ) && BottomRight.Equals(other.BottomRight) && BottomLeft .Equals(other.BottomLeft ); public readonly override bool Equals(object obj) => (obj is Corners other) && Equals(other); public readonly override int GetHashCode() => HashCode.Combine(TopLeft, TopRight, BottomRight, BottomLeft); public readonly override string ToString() => $"Corners(TopLeft: {TopLeft}, TopRight: {TopRight}, BottomRight: {BottomRight}, BottomLeft: {BottomLeft})"; public static bool operator ==(Corners left, Corners right) => left.Equals(right); public static bool operator !=(Corners left, Corners right) => !left.Equals(right); }