A corner piece in the middle of a field, an edge facing the wrong way. Page 1 gives you two answers that cannot both be true — "it picks the closest match" and "the algorithm is non-deterministic" — and neither one measures anything. On Godot 4.7 the painting is deterministic, it will never leave the cell empty, and it will never borrow from another terrain. So the wrong tile almost always means your set has no tile for that neighbourhood, and the engine substituted one without telling you. Paint a region below and find the cell.
Click cells to paint and unpaint. Each painted cell shows the neighbourhood it asks the engine for.
Terrain painting in 4.7 picks the tile that disagrees with the fewest peering bits, restricted to tiles that belong to the terrain you are painting. It will not leave the cell empty and it will not borrow from a neighbouring terrain. That is the whole reason you see a wrong tile instead of an error: the engine would rather give you an ugly tile of the right terrain than no tile at all.
Every claim below carries an id (T1, T4, …) asserted by verify_terrain_choice.gd, which re-runs the lot against your Godot build and exits non-zero if any of it stops holding. 24 checks, measured 2026-08-18 against 4.7.stable.official.5b4e0cb0f.
The "non-deterministic" claim does not reproduce. Four ways of asking:
| id | what was done | result |
|---|---|---|
| T1 | the same paint repeated 30× in 30 fresh layers | 1 distinct tile |
| T2 | the same cells passed in reversed array order | same tile |
| T3 | the region painted cell-by-cell vs all at once | same tiles |
| T13 | 30× repeat of a neighbourhood with no exact match | 1 distinct tile |
| T19 | 20× repeat with the needed tile deleted from the atlas | 1 distinct tile |
Same input, same output — including in the ambiguous cases, which is exactly where a random tie-break would show up if there were one.
Take the complete 47-tile blob set and delete the one tile that means "surrounded on all eight sides" (mask 255). Paint a 3×3 block, whose centre needs exactly that tile. The centre is still painted (T17) — no error, no warning. It gets the tile with mask 247:
wanted: 255 = N NE E SE S SW W NW
placed: 247 = N NE E S SW W NW (247 = 255 - 8, the SE corner bit)
^^ one bit off
One bit off is the best any remaining tile can do (T18). But 247 is not the only tile that scores 1: so do 127, 223 and 253, and the engine's choice among those four is not explained by the score. Sweeping the whole set — knock out each of the 47 tiles in turn and ask for exactly the neighbourhood it answered:
| id | over all 47 holes | result |
|---|---|---|
| T20 | is the substitute always a minimum-mismatch tile? | 47 of 47 — yes, every time |
| T21 | how often does exactly one tile reach that minimum? | 0 of 47. Between 3 and 8 tiles tie |
So the score tells you how wrong the substitute will look, and never which of the tied tiles you get. It is not the lowest-numbered one (2 of 47) and not the first one in the atlas (7 of 47). The tool at the top of this page reports the score and the tie set for that reason, and deliberately refuses to name a tile — a predictor that guessed would be right about a third of the time and unfalsifiable the rest.
An earlier version of this write-up said "exactly one tile ties at 1", citing T18. T18 never asserted that: its note printed how many times one mask appeared in an array, which in a set without duplicate tiles is always 1. The sweep above is what replaced it, and the note now counts ties properly.
The same rule with a sides-only set (T12): the fallback still matches every side the neighbourhood asked for, and only ever gives up corner information.
There is a well-travelled issue titled "TileMap Terrain paints incorrect tiles from unrelated terrains". On 4.7 we could not make that happen.
If your terrain looks like it borrowed a tile from a neighbour, check whether those tiles are assigned to the terrain you think they are. A peering bit holds a terrain index, not a boolean — = 0 means terrain 0, and a bit pointing at another terrain looks set in the inspector while counting for somebody else.
This is the most common surprise, and it is not a bug. Paint a 3×3 block on an empty layer: the centre gets the fully-surrounded tile (T4) and the corner does not (T5).
corner (0,0): mask 28 = E SE S — an outer-corner tile edge (1,0): mask 124 = E SE S SW W — a top-edge tile centre (1,1): mask 255 — fully surrounded
The empty cells outside the block count as "not this terrain", so the border of anything you paint gets edge tiles. If you generate a map in chunks, the seam between two chunks is painted against emptiness and then rewritten when the neighbouring chunk arrives (T9). Switch the tool above to left half first, then the rest and the rewritten cells are outlined. Paint the whole region in one call, or accept that borders are provisional.
ignore_empty_terrains does not turn that offset_cells_terrain_connect() takes a 4th argument, ignore_empty_terrains, and it is the first thing people reach for here. In three constructions it changed nothing on 4.7: neighbours with no tile at all → 0 of 9 cells differ (T6); neighbours holding a tile of no terrain → no difference; the only exact match belonging to no terrain → no difference (T7).
Honest limit: a negative result is not proof that the flag does nothing. It means we could not build a case on 4.7 where it bites, and the three obvious readings of its name are all wrong. If you have a repro where it changes the output it belongs in an issue on the repo, and it becomes a fixture. What we can say is: if you are chasing a wrong border tile, this flag is not the lever.
A terrain set has a mode, and it silently caps what your tiles can express:
| mode | bits used | distinct neighbourhoods |
|---|---|---|
MATCH_CORNERS_AND_SIDES | all 8 | 47 |
MATCH_SIDES | 4 sides | 16 |
MATCH_CORNERS | 4 corners | 16 |
A sides-only set paints all 256 neighbourhoods without complaint (T10) and can only ever produce its own 16 tiles (T11). It is not broken and not incomplete — it cannot see corners, so every corner-only difference collapses to the same tile. If you drew 47 tiles and the set is in sides mode, 31 of them are unreachable and nothing will tell you. Pick sides-only in the tool above and watch the neighbourhood numbers collapse.
(There is no is_valid_terrain_peering_bit() on TileSet in 4.7 — asking a sides-only set for a corner bit is an engine error, not a zero. Derive the valid bits from get_terrain_set_mode(), as the script does.)
In the order worth checking:
Two free MIT scripts in the Blobsmith Autotile Wirer repo, no dependencies, nothing to install:
# the predictor this page runs, in your terminal — no engine needed node docs/predict_terrain_paint.js your_tileset.tres --rect 5x3 --chunks # and the 24 claims above, re-asserted against YOUR Godot build godot --headless --script docs/verify_terrain_choice.gd -- res://your_tileset.tres res://sides16.tres
The predictor exits 1 if any cell of the region has no exact tile in your set, so it drops into a build script. The verifier prints PASS/FAIL per claim and exits non-zero if any stops holding — point it at a newer Godot and it tells you exactly which line of this page changed. Omit the second argument and the six claims that need a sides-only set print SKIP; the rest still run and still gate the exit code.
The predictor in this page is the same file the terminal runs, byte for byte — terrain-choice-core.js. A test refuses to ship this page if the copy served here has drifted, and a second test replays 258 cells of engine-measured output (terrain-paint-fixtures.json, dumped straight out of Godot) and fails if the predictor disagrees on one of them. Full write-up: why-terrain-paints-the-wrong-tile.md.
Being straight about this, since most of what is above is your TileSet and not our software:
TileSet with the terrain bits set.Why a blob autotile is 47 tiles and not 256 · Thin lines between tiles: the four causes · The byte layout of tile_map_data · Godot shows the raw key instead of the translation · The player changes language and half the UI doesn't · Boxes instead of characters after translating