From 20f9e19bf91e4bd99aa1568c034939cf8266f751 Mon Sep 17 00:00:00 2001 From: Code-Grub <34581585+Code-Grub@users.noreply.github.com> Date: Thu, 6 Aug 2026 12:48:06 -0400 Subject: [PATCH] stop a flat top stamping its rim down the plateau A cliff mound is drawn as a rim over a body: its top edge, then the same rock the whole way down. The top face cycles the first two drawn rows to fill its depth, so it laid that rim again every second tile. The mound the Diglett's Cave mouth is cut into came out with three rim lines across it instead of one along its north edge. Where the drawing says the body is all one tile, lay the rim once and hold the body after it. Art that genuinely repeats keeps cycling: the Safari Zone's fence alternates two tiles the whole way down, and there the repeat is what the drawing says. Answered per column and per region, because each catches what the other misses. The columns carrying a mound's cave mouth end in the mouth's own tiles, so per column alone they kept cycling while their neighbours held, leaving rim stubs above the doorway. A region vote alone silences a real rim-over-body column standing in a region of repeating art, of which the Safari Zone has three. A column holds if either says so. Geometry is untouched: the silhouette is pixel for pixel what it was, and only the texel a top face wears changes. Of 3088 flat-topped runs, the 1336 rim-over-body ones change and nothing else does. tests/flat_top_test.lua walks every map and fails if any rim-over-body run revisits an earlier drawn row. --- lib/ChunkMesher.lua | 23 +++++++++- lib/Structures.lua | 38 +++++++++++++++++ tests/flat_top_test.lua | 95 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 tests/flat_top_test.lua diff --git a/lib/ChunkMesher.lua b/lib/ChunkMesher.lua index eb2dbb9..e9b4c39 100644 --- a/lib/ChunkMesher.lua +++ b/lib/ChunkMesher.lua @@ -64,6 +64,26 @@ end local ChunkMesher = {} +-- Which drawn row a FLAT-topped volume's top face wears at depth `ty`. +-- +-- A structure is usually deeper than the art that draws it, so the rows +-- cycle and the drawing repeats down the top. That is right for art which +-- genuinely repeats -- the Safari Zone's fence alternates two tiles the +-- whole way down -- and wrong for a RIM over a uniform body: a cliff +-- mound's first row is its top edge, and cycling lays that edge again +-- every second tile, striping a plateau with rims it should not have. +-- +-- Where Structures found the body uniform, the rim is laid once at the +-- north edge and the body held after it. Everything else cycles as before. +function ChunkMesher.flatTopRow(run, ty) + local m = math.min(2, run.extent) + local d = ty - run.north + if run.topUniform then + return run.north + math.min(d, m - 1) + end + return run.north + (d % m) +end + -- Ring of border blocks meshed around the body, matching the width -- TileRenderer draws so the two modes end at the same place. local RING = 3 @@ -528,8 +548,7 @@ local function runGeometry(map, bodyOnly, masks, sink, waterSink) { x0 + 8, neY, z0 }, { x0, nwY, z0 } }, { { u0, v1 }, { u1, v1 }, { u1, v0 }, { u0, v0 } }, 0.95) elseif run then - local m = math.min(2, run.extent) - local topTile = map:tileAt(tx, run.north + ((ty - run.north) % m)) + local topTile = map:tileAt(tx, ChunkMesher.flatTopRow(run, ty)) topQuad(x0, z0, h, topTile, VOLUME_TOP_SHADE) else local topTile = tile diff --git a/lib/Structures.lua b/lib/Structures.lua index 2c99c8d..8950380 100644 --- a/lib/Structures.lua +++ b/lib/Structures.lua @@ -2225,6 +2225,43 @@ function Structures.buildVolume(S, map, tiles) -- whether the region's dominant columns are flat repeats (a cliff -- mound's plateau) rather than drawn facades (a house's front) local modeRepeat = (repeatVotes[modeH] or 0) * 2 > modeN + + -- Whether this REGION's tops are a rim over a uniform body -- what every + -- cliff mound is drawn as: a top edge, then the same rock the whole way + -- down. The top face may then lay that rim once along its north edge and + -- hold the body after it, instead of cycling the rim back every second + -- tile and striping a plateau with edges it should not have. + -- + -- Answered per column AND per region, because each catches what the + -- other misses. A mound is one structure many columns wide, and the + -- columns carrying its cave mouth read differently from their neighbours + -- (their drawing ends in the mouth's own tiles): per column alone, those + -- kept cycling while the rest held, leaving rim stubs above the doorway. + -- But a region vote alone silences a genuine rim-over-body column that + -- happens to stand in a region of repeating art -- three of them in the + -- Safari Zone. A column holds if EITHER says so. + -- + -- Art that genuinely repeats is not uniform and keeps cycling: the + -- Safari Zone's fence alternates two tiles the whole way down, and there + -- the repeat IS what the drawing says. + local uniformVotes, uniformTotal = 0, 0 + for _, r in ipairs(runs) do + local run = r.run + if run.extent > 2 then + uniformTotal = uniformTotal + 1 + local body = map:tileAt(r.tx, run.north + 1) + local uniform = true + for d = 2, run.extent - 1 do + if map:tileAt(r.tx, run.north + d) ~= body then + uniform = false + break + end + end + run.ownUniform = uniform + if uniform then uniformVotes = uniformVotes + 1 end + end + end + local regionUniform = uniformTotal > 0 and uniformVotes * 2 > uniformTotal for _, r in ipairs(runs) do local run = r.run local h = run.unit * 8 @@ -2272,6 +2309,7 @@ function Structures.buildVolume(S, map, tiles) run.rise = roofRows * 8 run.peak = h run.h = h - run.rise -- facade height: what sides build to + run.topUniform = run.ownUniform or regionUniform for ty = run.north, run.front do S.runs[keyOf(r.tx, ty)] = run end diff --git a/tests/flat_top_test.lua b/tests/flat_top_test.lua new file mode 100644 index 0000000..14035c0 --- /dev/null +++ b/tests/flat_top_test.lua @@ -0,0 +1,95 @@ +-- A flat top must not stamp its rim twice. +-- +-- ChunkMesher.flatTopRow decides which drawn row a flat-topped volume's top +-- face wears at each depth. Where the drawing is a RIM over a uniform body +-- -- every cliff mound in the game, and the mound the Diglett's Cave mouth +-- is cut into -- the rim belongs at the plateau's north edge and nowhere +-- else. Cycling the first two rows lays it again every second tile. +-- +-- The invariant: on such a run the sampled row never goes BACKWARDS as ty +-- moves south. Art that genuinely repeats (the Safari Zone's fence +-- alternates two tiles the whole way down) is exempt: there the repeat is +-- what the drawing says, and the run is not rim-over-body. +-- +-- POKEPORT_DRIVER=mods/DramaticShapeVoxelMod/tests/flat_top_test.lua lovec . +return function(game) + local U = dofile("tests/drivers/util.lua") + + local V = game.mods.exports["DRAMATIC_SHAPE"] + V = V and V.lib + local Structures = V and V.require("Structures") + local ChunkMesher = V and V.require("ChunkMesher") + if not (Structures and ChunkMesher and ChunkMesher.flatTopRow) then + print("[flattop] FAIL mod, Structures or ChunkMesher.flatTopRow missing") + love.event.quit(1) + return + end + local function keyOf(tx, ty) return (ty + 64) * 4096 + (tx + 64) end + + local MAPS = {} + for id in pairs((game.data and game.data.maps) or {}) do + MAPS[#MAPS + 1] = id + end + table.sort(MAPS) + + local checked, offenders, examples = 0, 0, {} + for _, mapId in ipairs(MAPS) do + U.teleport(game, mapId, 5, 5, "up") + U.wait(6) + local ow = game.overworld + if ow and ow.map and ow.map.def and ow.map.def.id == mapId then + local map = ow.map + local S = Structures.forMap(map) + local seen = {} + for tx = 0, map.def.width * 4 - 1 do + for ty = 0, map.def.height * 4 - 1 do + local run = S.runs[keyOf(tx, ty)] + local sig = run and (tostring(run) .. ":" .. tx) + if run and not seen[sig] and (run.rise or 0) == 0 then + seen[sig] = true + local ext = run.front - run.north + 1 + -- rim over a uniform body: the shape the rim must not repeat on + local uniform = ext > 2 + if uniform then + local body = map:tileAt(tx, run.north + 1) + for d = 2, ext - 1 do + if map:tileAt(tx, run.north + d) ~= body then + uniform = false + break + end + end + end + if uniform then + checked = checked + 1 + local prev = -1 + for ty2 = run.north, run.front do + local row = ChunkMesher.flatTopRow(run, ty2) + if row < prev then + offenders = offenders + 1 + if #examples < 5 then + examples[#examples + 1] = ("%s tx=%d north=%d ext=%d " + .. "went back to row %d at ty %d") + :format(mapId, tx, run.north, ext, row, ty2) + end + break + end + prev = row + end + end + end + end + end + end + end + + print(("[flattop] %d rim-over-body runs checked, %d repeat their rim") + :format(checked, offenders)) + for _, e in ipairs(examples) do print("[flattop] " .. e) end + if offenders > 0 then + print("[flattop] FAIL") + love.event.quit(1) + else + print("[flattop] PASS") + love.event.quit(0) + end +end