From f19facbe5c156436d3e417d107e9b9780459b0d9 Mon Sep 17 00:00:00 2001 From: 44r0n7 <44r0n7+gitea@pm.me> Date: Sun, 25 Oct 2026 20:21:31 -0400 Subject: [PATCH] Grains resting on anything built cast no shadow (t37) Co-Authored-By: Claude Opus 5.5 --- docs/PROJECT_MAP.md | 2 +- docs/agent-log.md | 9 +++++++++ src/render/light.js | 3 +-- test/t_light.js | 37 ++++++++++++++++++++++++++++++++++--- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/docs/PROJECT_MAP.md b/docs/PROJECT_MAP.md index ab5ddbc..98064af 100644 --- a/docs/PROJECT_MAP.md +++ b/docs/PROJECT_MAP.md @@ -352,7 +352,7 @@ Drawing (src/render/): browser only. This file: the renderer state R, colour tab - functions: glowIndex, thermIdx, pipeCellColor, pipeBodyCell, thinPipeColor, beltLike, buildSky, initRender, resizeRender, viewCells, updateCamera, snapCamera, screenToWorld, worldToScreenPx, renderMonoFont - variables: R, GLOW_W, GLOW_R, GLOW_G, GLOW_B, THERM, PC, TREE_R, TREE_G, TREE_B, BG, SKY_R, SKY_G, SKY_B -### src/render/light.js (104 lines) +### src/render/light.js (103 lines) Propagated coloured light from glowing and burning cells. - functions: builtForLight, looseForLight, computeLight diff --git a/docs/agent-log.md b/docs/agent-log.md index ecc76e1..87a6cc8 100644 --- a/docs/agent-log.md +++ b/docs/agent-log.md @@ -4,6 +4,15 @@ What agents have done, newest first. Add an entry for every piece of work: the d note or request it was for, what changed, the files touched, the tests run, and anything left open or not verified. Keep each entry short; the git history has the details. +## 2026-10-25: t37 follow-up: grains on built things cast no shadows (Claude Code, Codex) + +- The owner saw a flickering shadow under a grinder fed by a stream: grains resting on its + housing for a moment shaded. `looseForLight` (`src/render/light.js`) now treats a loose stack + that rests on any `builtForLight` cell, or ends in air or gas, as see-through. Stacks on natural + ground or deeper than 12 cells still shade. +- `test/t_light.js` (a grinder stream checked for 180 ticks in both lighting modes); + `run_all.py --browser` ALL PASSED. + ## 2026-10-25: t37 follow-up: falling grains cast no shadows (Claude Code, Codex) - The owner saw a single falling grain darken a column of sky. `onBeltForLight` became diff --git a/src/render/light.js b/src/render/light.js index 05903b2..9221eb9 100644 --- a/src/render/light.js +++ b/src/render/light.js @@ -8,8 +8,7 @@ function builtForLight(i, x, y) { function looseForLight(i) { for (let depth = 0; depth <= 12 && i < N; depth++, i += W) { const m = mat[i], ph = PH[m]; - if (m === BELTL || m === BELTR || part[i] === P_FILTER) return true; - if (part[i]) return false; + if (builtForLight(i, i % W, (i / W) | 0)) return true; if (ph !== PH_POWDER && ph !== PH_LIQUID) return m === EMPTY || ph === PH_GAS; } return false; diff --git a/test/t_light.js b/test/t_light.js index 6b62e1c..b84f48d 100644 --- a/test/t_light.js +++ b/test/t_light.js @@ -97,9 +97,10 @@ for (const [name, support, depth, gap, expected] of [ ['12 falling grains', '', 12, '', true], ['13 falling grains', '', 13, '', false], ['natural ledge', 'mat[i] = STONE; flags[i] = F_NAT', 3, '', false], - ['wall floor', 'mat[i] = STONE', 3, '', false], - ['tube', 'part[i] = P_TR', 3, '', false], - ['loaded tube', 'mat[i] = SAND; part[i] = P_TR', 3, '', false], + ['deep natural heap', 'mat[i] = SAND; flags[i] = F_NAT', 13, '', false], + ['wall floor', 'mat[i] = STONE', 3, '', true], + ['tube', 'part[i] = P_TR', 3, '', true], + ['loaded tube', 'mat[i] = SAND; part[i] = P_TR', 3, '', true], ]) { run(` for (let y = 40; y <= 53; y++) { const i = y * W + 300; mat[i] = SAND; part[i] = 0; flags[i] = 0; } @@ -112,4 +113,34 @@ run('mat[40 * W + 300] = SAND; mat[41 * W + 300] = EMPTY;'); check('a single grain in mid-air is see-through', run('looseForLight(40 * W + 300)')); run('mat[(H - 1) * W + 300] = SAND;'); check('loose cell detection stops at the world bottom', run('!looseForLight((H - 1) * W + 300)')); + +flatWorld(run, 320, 200, 160); +run(` + bot.lamp = false; stats.refined = 0; + placeBlock(BP_GRIND, 0, 20, 20, true); + for (let bx = 8; bx < 30; bx++) placeBlock(BP_BELT, 1, bx, 36, true); + setCell(79 * W + 80, SAND, AMB[79], 0); +`); +check('sand resting on grinder housing is see-through', run('looseForLight(79 * W + 80)')); +for (const mode of ['full', 'fast']) { + const result = run(`(() => { + SET.lighting = '${mode}'; + let mismatches = 0, first = ''; + for (let t = 0; t < 180; t++) { + if (t % 4 === 0) setCell(48 * W + 80, SAND, AMB[48], 0); + simTick(); + computeLight(); + for (const a of [R.lr, R.lg, R.lb]) for (let x = 76; x < 88; x += 2) { + const below = lightAt(a, x, 160), open = lightAt(a, 152, 160); + if (Math.abs(below - open) > 1e-6) { + mismatches++; + if (!first) first = 'tick ' + tick + ', x ' + x + ': ' + below + ' / ' + open; + } + } + } + return { mismatches, first }; + })()`); + check(`${mode}: streaming grinder leaves ground in daylight for 180 consecutive ticks`, result.mismatches === 0, result.first || 'no shadow'); +} +check('the streaming grinder actually processes its input', run('stats.refined > 0'), run('stats.refined')); done();