Documentation
¶
Overview ¶
Package maplint runs the studio's quality checks against a parsed TNT map + OTA metadata, returning a list of diagnostics. It's the shared implementation behind both `kbot studio`'s Quality Checker dialog and the `kbot tnt lint` CLI / MCP entry points.
The package is deliberately framework-agnostic: callers build an Input value (tnt.Map plus a small set of neutral structs) and get back []Diagnostic. No HTTP, no JSON, no studio-specific types.
The constants at the top tune the heuristics; the studio's UI references the same values when wrapping diagnostics with auto-fix metadata.
Index ¶
- Constants
- func ParsePlayerCounts(s string) []int
- type Diagnostic
- func CheckDuplicateTiles(in Input) Diagnostic
- func CheckHeightDiscontinuities(in Input) Diagnostic
- func CheckMetalProximity(in Input) Diagnostic
- func CheckMissingOTAFields(in Input) Diagnostic
- func CheckSchemaSlotsVsPlayers(in Input) Diagnostic
- func CheckStartPositionsInBounds(in Input) Diagnostic
- func CheckVoidIslands(in Input) Diagnostic
- func Run(in Input) []Diagnostic
- type FeaturePlacement
- type Input
- type OTAInfo
- type SchemaInfo
- type Severity
- type StartPos
Constants ¶
const ( // VoidFeature — the canonical sentinel TA writes into // TileAttr.Feature for impassable / void cells. 0xFFFF means "no // feature, passable"; 0xFFFE / 0xFFFD also appear in the wild on a // handful of early Cavedog maps (Metal Heck has 724 of them on // what are clearly buildable steam-vent cells, and Lava Run has a // similar pattern) — their semantics are not "void" in the engine // and we treat them as "no feature" defensively. VoidFeature = uint16(0xFFFC) // MetalProximityTiles — a start position is flagged when its // nearest metal-producing feature is further than this many // tiles (1 tile = 32 game-pixels, 1 attribute cell = 16 px). // 24 tiles ≈ 1.5× commander beam reach, generous early-game // expansion range. MetalProximityTiles = 24 // HeightDiscontinuityThreshold — adjacent attribute cells with // |Δheight| beyond this read as cliffs that walking units // can't traverse. TA's units can step ~16 height per attr // cell; 32 is double that and a reliable "this looks broken" // floor. HeightDiscontinuityThreshold = 32 // MetalRichSurfaceThreshold — when a schema's SurfaceMetal is // at or above this value the map is considered metal-rich // (Metal Heck uses 255). In that mode the engine extracts // metal from open ground via mexes anywhere, so the // metal-proximity check skips that schema's starts. MetalRichSurfaceThreshold = 8 // VoidIslandsTolerance — flood-fill from starts will routinely // strand a few cells in tight corners or behind feature // footprints. Anything under this count is treated as // acceptable noise and the check stays green. VoidIslandsTolerance = 20 )
Tunable thresholds shared across all callers. Documented here so a future maintainer can change behaviour in one place.
Variables ¶
This section is empty.
Functions ¶
func ParsePlayerCounts ¶
ParsePlayerCounts splits a numplayers string like "2, 3, 4" into its individual integer entries.
Types ¶
type Diagnostic ¶
Diagnostic is one result row. ID is a stable, machine-readable identifier for the rule; Label is a short human title; Message is the per-run description ("12 cells stranded" etc.).
func CheckDuplicateTiles ¶
func CheckDuplicateTiles(in Input) Diagnostic
CheckDuplicateTiles flags any byte-identical entries in the TNT tile pool. When the "compressTiles" fix has already been applied the pool is dedup-by-construction, so we shortcut to OK without re-hashing.
func CheckHeightDiscontinuities ¶
func CheckHeightDiscontinuities(in Input) Diagnostic
CheckHeightDiscontinuities counts adjacent attribute cell pairs whose height delta exceeds HeightDiscontinuityThreshold.
func CheckMetalProximity ¶
func CheckMetalProximity(in Input) Diagnostic
CheckMetalProximity walks each start and reports any whose nearest metal-producing feature exceeds MetalProximityTiles. Schemas configured as metal-rich (SurfaceMetal ≥ threshold) skip the check.
func CheckMissingOTAFields ¶
func CheckMissingOTAFields(in Input) Diagnostic
CheckMissingOTAFields walks the lobby-displayed metadata and flags blank required fields.
func CheckSchemaSlotsVsPlayers ¶
func CheckSchemaSlotsVsPlayers(in Input) Diagnostic
CheckSchemaSlotsVsPlayers verifies every declared player count can be hosted by at least one schema (i.e. its StartPos array has ≥ that many spawns).
func CheckStartPositionsInBounds ¶
func CheckStartPositionsInBounds(in Input) Diagnostic
CheckStartPositionsInBounds confirms every schema's start positions land on a passable attribute cell that's inside the map.
func CheckVoidIslands ¶
func CheckVoidIslands(in Input) Diagnostic
CheckVoidIslands flood-fills from every start over the passable attribute grid and counts cells the fill never reached.
func Run ¶
func Run(in Input) []Diagnostic
Run executes every check against the supplied Input and returns diagnostics in a stable order (the studio's UI relies on it).
type FeaturePlacement ¶
FeaturePlacement records where a named feature sits on the map in attribute-cell coordinates (16 game pixels per cell).
type Input ¶
type Input struct {
Map *tnt.Map
OTA *OTAInfo
Features []FeaturePlacement
FeatureRegistry map[string]int // lowercased feature name → metal yield (0 = non-metal)
AppliedFixes []string
}
Input bundles everything the lint needs. Map is required; the remaining fields are optional but unlock the corresponding checks.
- OTA nil → schema, start-position, metal-proximity, metadata checks all skip with an "ok" message.
- FeatureRegistry nil → metal-proximity check skips with a "feature library unavailable" note.
AppliedFixes lets the caller short-circuit individual rules once their fix has been applied (e.g. compressTiles disables the duplicate-tiles report).
type OTAInfo ¶
type OTAInfo struct {
MissionName string
MissionDescription string
Planet string
NumPlayers string
Size string
SeaLevel int
Schemas []SchemaInfo
}
OTAInfo is the subset of an .ota file the lint inspects.
type SchemaInfo ¶
SchemaInfo carries the schema fields the checks read. The studio adapter pulls these from its saveRequest's nested otaSchema; the CLI builds them by parsing an .ota file.