using System;
using UnityEngine;
using TD.Core;
namespace TD.Levels
{
///
/// Baked level data. Authored in a Unity scene via volume MonoBehaviours; produced by
/// ; consumed at runtime as the canonical map
/// definition.
///
///
/// LevelData is the canonical map identity. The lobby browses LevelData assets; loading a
/// map = read LevelData → load the referenced scene at .
///
/// All flat grid arrays use row-major indexing: grid[y * GridSize.x + x].
/// Origin-relative: is the world-tile coordinate that grid index
/// (0,0) corresponds to. Convert world-tile to grid-index via
/// worldTile - GridOriginTile.
///
[CreateAssetMenu(fileName = "LevelData", menuName = "TD/Level Data", order = 1)]
public class LevelData : ScriptableObject
{
// -------------------------------------------------------------------
// Lobby-facing metadata.
// -------------------------------------------------------------------
[Header("Map Metadata")]
public string MapName;
public int PlayerCount;
public string MapDescription;
public string Author;
[Tooltip("Auto-generated by bake. Use the Refresh Thumbnail button on LevelAuthoring to " +
"re-render without doing a full bake.")]
public Sprite MapThumbnail;
[Tooltip("Path to the scene this LevelData was baked from. Auto-populated by bake.")]
public string ScenePath;
// -------------------------------------------------------------------
// Bake metadata (used for dirty-detection and diagnostic display).
// -------------------------------------------------------------------
[Header("Bake Metadata")]
[Tooltip("Hash of the authoring inputs at last bake. Compared at Play-mode entry to detect " +
"unbaked changes. Captures volumes + LevelAuthoring metadata; does NOT capture " +
"visual scene content.")]
public string AuthoringHash;
[Tooltip("ISO 8601 UTC timestamp of the last successful bake.")]
public string LastBakeTimestamp;
public BakeOutcome LastBakeOutcome;
public int LastBakeWarningCount;
// -------------------------------------------------------------------
// Grid metadata.
// -------------------------------------------------------------------
[Header("Grid")]
[Tooltip("World-tile coordinate that grid index (0,0) corresponds to. Origin-relative " +
"addressing: worldTile - GridOriginTile gives the index into the flat arrays.")]
public Vector2Int GridOriginTile;
[Tooltip("Width × height of the grid in tiles.")]
public Vector2Int GridSize;
// -------------------------------------------------------------------
// Per-tile flat arrays. All indexed as grid[y * GridSize.x + x].
// -------------------------------------------------------------------
[Tooltip("Per-tile placement state: Outside / Buildable / Restricted. Length = GridSize.x * GridSize.y.")]
public PlacementState[] PlacementGrid;
[Tooltip("Per-tile initial walkability (does NOT account for towers — they stamp footprints " +
"at runtime). Length = GridSize.x * GridSize.y.")]
public bool[] WalkabilityGrid;
[Tooltip("Per-tile owning player slot. PlayerSlot.None for tiles not in any player zone. " +
"Length = GridSize.x * GridSize.y.")]
public PlayerSlot[] OwnerGrid;
// -------------------------------------------------------------------
// Per-zone and per-goal structures (populated by bake from volume data).
// -------------------------------------------------------------------
[Tooltip("One entry per declared player zone, sorted by Owner.")]
public PlayerZoneData[] PlayerZones;
[Tooltip("One entry per GoalVolume, sorted by min tile coordinate.")]
public GoalData[] Goals;
}
///
/// Per-zone baked data. The runtime can use this to enumerate a player's spawners and leak
/// exits without scanning the full grid.
///
[Serializable]
public class PlayerZoneData
{
public PlayerSlot Owner;
[Tooltip("Spawners in this zone, sorted by SpawnerIdInZone.")]
public SpawnerData[] Spawners;
[Tooltip("Leak exits OUT OF this zone, sorted by Target enum value. Empty for the final " +
"defender (whose zone is goal-adjacent and has no leak exit).")]
public LeakExitData[] LeakExits;
}
[Serializable]
public class SpawnerData
{
public int SpawnerIdInZone;
[Tooltip("Tile coordinate of the spawner's center (its volume's bounds center, projected to grid).")]
public Vector2Int TilePosition;
[Tooltip("Full tile coverage of the spawner volume.")]
public Vector2Int[] TileArea;
public Direction Facing;
}
[Serializable]
public class LeakExitData
{
public PlayerSlot Target;
[Tooltip("Full tile coverage of the leak exit volume.")]
public Vector2Int[] TileArea;
[Tooltip("Weight normalized so all leak exits sharing the same source zone sum to 1.0.")]
public float NormalizedWeight;
}
[Serializable]
public class GoalData
{
[Tooltip("Full tile coverage of the goal volume.")]
public Vector2Int[] TileArea;
}
}