diff --git a/src/components/mapart/workers/mapCanvas.jsworker b/src/components/mapart/workers/mapCanvas.jsworker index 92abd981..98ccbfbb 100644 --- a/src/components/mapart/workers/mapCanvas.jsworker +++ b/src/components/mapart/workers/mapCanvas.jsworker @@ -230,6 +230,9 @@ function getMapartImageDataAndMaterials() { ) { divisor = chosenDitherMethod.ditherDivisor; } + + const unnecessarySupportBlock = new Map(); + for (let i = 0; i < canvasImageData.data.length; i += 4) { const indexR = i; const indexG = i + 1; @@ -242,6 +245,18 @@ function getMapartImageDataAndMaterials() { const whichMap_x = Math.floor(multimap_x / 128); const whichMap_y = Math.floor(multimap_y / 128); const individualMap_y = multimap_y % 128; + + const unnecessarySupportBlockMapIndex = + (whichMap_y * optionValue_mapSize_x + whichMap_x) * 128 + + (multimap_x % 128); + if (!unnecessarySupportBlock.has(unnecessarySupportBlockMapIndex)) { + unnecessarySupportBlock.set(unnecessarySupportBlockMapIndex, { + ascending: false, + plateauLength: 0, + count: 0, + }); + } + if (multimap_x === 0) { postMessage({ head: "PROGRESS_REPORT", @@ -555,9 +570,36 @@ function getMapartImageDataAndMaterials() { } } maps[whichMap_y][whichMap_x].materials[closestColourSetIdAndTone.colourSetId] += 1; + + if (optionValue_staircasing === MapModes.SCHEMATIC_NBT.staircaseModes.VALLEY.uniqueId) { + // In valley mode, we count for unnecessary support block. + const data = unnecessarySupportBlock.get( + unnecessarySupportBlockMapIndex + ); + if (data.ascending && closestColourSetIdAndTone.tone === "dark") { + data.ascending = false; + if (data.plateauLength > 0) { + data.count += 1; + } + } else if (closestColourSetIdAndTone.tone === "light") { + data.ascending = true; + data.plateauLength = 0; + } else { + data.plateauLength += 1; + } + unnecessarySupportBlock.set(unnecessarySupportBlockMapIndex, data); + } } } } + + for (const [index, value] of unnecessarySupportBlock.entries()) { + const row = index % 128; + const whichMap_x = ((index - row) / 128) % optionValue_mapSize_x; + const whichMap_y = + ((index - row) / 128 - whichMap_x) / optionValue_mapSize_x; + maps[whichMap_y][whichMap_x].supportBlockCount -= value.count; + } } onmessage = (e) => { diff --git a/src/components/mapart/workers/nbt.jsworker b/src/components/mapart/workers/nbt.jsworker index eeb54da4..d439e35e 100644 --- a/src/components/mapart/workers/nbt.jsworker +++ b/src/components/mapart/workers/nbt.jsworker @@ -586,6 +586,7 @@ class Map_NBT { plateaus.push({ startIndex: physicalColumn.length, endIndex: physicalColumn.length }); let nonPlateauPulldownHeights = [Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]; + const ignoredBlocks = []; while (plateaus.length !== 1) { let pullDownHeight = Number.MAX_SAFE_INTEGER; for (let i = plateaus[0].endIndex; i < plateaus[1].startIndex; i++) { @@ -600,9 +601,59 @@ class Map_NBT { for (let i = plateaus[0].startIndex; i < plateaus[0].endIndex; i++) { physicalColumn[i].pos.value.value[1] -= plateauPulldownHeight; } + + if ( + physicalColumn[plateaus[0].endIndex].pos.value.value[2] - + physicalColumn[plateaus[0].startIndex].pos.value.value[2] > + 1 + ) { + // If a plateau is longer than 1 block, there is an overhang that is unneccessary for building in survival mode + if ( + optionValue_whereSupportBlocks === + WhereSupportBlocksModes.ALL_DOUBLE_OPTIMIZED.uniqueId + ) { + // In All Double (optimized) mode, there are 2 support blocks under the top block of the edge of the particular plateau, we ignore the lowest one. + ignoredBlocks.push( + plateauPulldownHeight === nonPlateauPulldownHeights[0] + ? plateaus[0].endIndex - 1 + : plateaus[0].startIndex + 2 + ); + } else if ( + optionValue_whereSupportBlocks === + WhereSupportBlocksModes.ALL_OPTIMIZED.uniqueId + ) { + // In All Blocks (optimized) mode, we ignore the lowest support block. (There may be 1 or 2 support blocks in this mode.) + ignoredBlocks.push( + plateauPulldownHeight === nonPlateauPulldownHeights[0] + ? // If the plateau is connected to the valley on the north side, the endIndex - 1 is always the lowest support block. + plateaus[0].endIndex - 1 + : // If the plateau is connected to the valley on the south side, we check if startIndex + 2 is still the support block, by comparing + // its Z coordinate to the top block (startIndex), and choose the block to be ignored appropiately. + physicalColumn[plateaus[0].startIndex].pos.value.value[2] === + physicalColumn[plateaus[0].startIndex + 2].pos.value + .value[2] + ? plateaus[0].startIndex + 2 + : plateaus[0].startIndex + 1 + ); + } + } + plateaus.shift(); nonPlateauPulldownHeights[0] = nonPlateauPulldownHeights[1]; } + + if ( + optionValue_whereSupportBlocks === + WhereSupportBlocksModes.ALL_DOUBLE_OPTIMIZED.uniqueId || + optionValue_whereSupportBlocks === + WhereSupportBlocksModes.ALL_OPTIMIZED.uniqueId + ) { + // Filter out the overhangs + physicalColumn = physicalColumn.filter( + (_, i) => !ignoredBlocks.includes(i) + ); + } + break; } case MapModes.SCHEMATIC_NBT.staircaseModes.CLASSIC.uniqueId: {