Painting over identical tiles no longer adds an empty undo step (#212)
A rectangle drawn over cells that already hold exactly that tile
pushed a command that changed nothing. Undo then seemed to do nothing
and the project was marked as modified. PaintTilesCommand.changes()
was meant to prevent that, but nothing called it since #128.
- New paintTiles() in tilemapCommands.ts returns the command for a
finished stroke or fill, or null when no cell changes. It is the
first caller of PaintTilesCommand.changes().
- All three paint paths in the Scene View go through it: brush and
eraser, rectangle (both in endStroke) and flood fill (fillFrom).
- Flood fill was not affected, because floodFill already returns []
for the same tile. The guard is there anyway, as the issue asked.
- A rectangle that changes even one cell stays a normal undo step.
Tests:
- ./check.sh: 145 files, 2190 tests, CHECK EXIT 0 (before 2187).
- 3 new unit tests in tests/core/tilemap.test.ts: same rectangle
twice gives no command, a wider rectangle still does, a fill that
finds nothing gives no command.
- 1 new e2e check in 40d: the same rectangle again, then one undo
must take 9 cells to 0. A redo restores them for later blocks.
- GM_STEPS=39,40 on the final build: ALL PASSED, 81 checks.
- Counter-probe with changes(...) || true: exactly the two unit
tests fail, and in the browser exactly the new check fails with
{"afterUndo":9}. Original restored via cmp (IDENTICAL), rebuilt.
- Editor suite check total: CI measured 1312 at 0e85856, new total
1313 (calculated) in README and wiki.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0e8585665a
commit
487b3aa5b4
5 files changed
+80
-20
No files matched your search
@@ -117,6 +117,7 @@ export async function tilemap(t) {
|
||||
shot,
|
||||
settle,
|
||||
undo,
|
||||
redo,
|
||||
select,
|
||||
} = t;
|
||||
const { saved, api, navigate, projectId } = t;
|
||||
@@ -287,6 +288,20 @@ export async function tilemap(t) {
|
||||
Object.keys(cells).length === 9 && cells['1,1'] === 'at-grass' && cells['2,2'] === 'at-grass',
|
||||
JSON.stringify(Object.keys(cells).sort()),
|
||||
);
|
||||
// The same box again changes no cell, so it leaves no step behind (#212): the one undo takes
|
||||
// back the first rectangle, and redo brings it back for the blocks below.
|
||||
await drag(corner.x, corner.y, far.x, far.y);
|
||||
await settle();
|
||||
await undo();
|
||||
await settle();
|
||||
const afterUndo = Object.keys(await painted()).length;
|
||||
await redo();
|
||||
await settle();
|
||||
check(
|
||||
'a rectangle over cells that already hold its tile is no undo step',
|
||||
afterUndo === 0 && Object.keys(await painted()).length === 9,
|
||||
JSON.stringify({ afterUndo, redone: Object.keys(await painted()).length }),
|
||||
);
|
||||
|
||||
// 40e. The pixels. While the animation runs the block under the pointer changes between the two
|
||||
// steps, so it is cut down to one for the reading and put back afterwards (as step 39 does).
|
||||
|
||||
Reference in new issue
Block a user