diff --git a/tools/bench-prefab-filter.ts b/tools/bench-prefab-filter.ts index 5df01615..0dfbf087 100644 --- a/tools/bench-prefab-filter.ts +++ b/tools/bench-prefab-filter.ts @@ -1,6 +1,8 @@ -// Phase-level CPU benchmark of the block-name matching pipeline in -// src/worker/lib/prefab-filter.ts (#matchByBlockName equivalent), run directly -// under Deno so no browser / dev server is needed. +/** + * Phase-level CPU benchmark of the block-name matching pipeline in + * `src/worker/lib/prefab-filter.ts` (`#matchByBlockName` equivalent). + * Runs directly under Deno so no browser or dev server is needed. + */ import { matchAndHighlight, MATCHED_BLOCKS_LIMIT, @@ -145,7 +147,7 @@ function runOnce(pattern: RegExp) { ); t.sort = performance.now() - t0; - // structuredClone approximates the postMessage serialize cost. + // WHY: structuredClone approximates the postMessage serialize cost. t0 = performance.now(); structuredClone(result); t.cloneAll = performance.now() - t0; diff --git a/tools/build.ts b/tools/build.ts index 8c3def35..680a42e7 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -59,11 +59,9 @@ if (args[0] === "serve") { console.log(`Serving at http://${hosts[0]}:${port}`); - // Keep alive await new Promise(() => {}); } else if (args[0] === "serve-static") { - // esbuild's serve drops response bodies under CI load, giving E2E 0-byte map - // files (issue 202); build once, then serve public/ from a real static server. + // WHY: esbuild's own serve drops response bodies under CI load, giving E2E 0-byte map files (see issue #202). Build once, then serve public/ from a real static server. await esbuild.build({ ...commonOpts, ...serveOpts }); esbuild.stop(); diff --git a/tools/copy-map-files.ts b/tools/copy-map-files.ts index c34eea99..f3e240d3 100644 --- a/tools/copy-map-files.ts +++ b/tools/copy-map-files.ts @@ -13,9 +13,11 @@ import { const WORLDS_DIR = vanillaDir("Data", "Worlds"); const DST_DIR = publishDir("maps"); -// Concurrency for top-level world processing. Each world fans out into -// parallel per-file copies internally, so this value is intentionally small -// to avoid thrashing disk I/O across many large PNG/raw streams. +/** + * Concurrency for top-level world processing. Each world fans out into + * parallel per-file copies internally, so this value stays small to + * avoid thrashing disk I/O across many large PNG/raw streams. + */ const WORLD_CONCURRENCY = 8; async function main() { diff --git a/tools/extract-added-prefabs.ts b/tools/extract-added-prefabs.ts index bb995756..4d5b68c9 100644 --- a/tools/extract-added-prefabs.ts +++ b/tools/extract-added-prefabs.ts @@ -6,15 +6,18 @@ import { writeJsonFile, } from "./lib/utils.ts"; -// index.json only tracks the prefabs of the latest game version; there is no -// tag-per-release history of it. Experimental versions also add/remove -// prefabs across many commits without ever bumping the version tag, so each -// version's added set is computed as (names at its `ref`) minus (names at -// the previous version's `ref`), not from a single tagged snapshot. -// -// The last entry is the in-progress version: its `ref` stays "HEAD" until -// that version is tagged, at which point set it to the new tag and append a -// new in-progress entry for the version after it. +/** + * `index.json` only tracks prefabs of the latest game version. There is + * no tag-per-release history, and experimental versions add or remove + * prefabs across many commits without ever bumping the version tag. So + * each version's added set is computed as (names at its `ref`) minus + * (names at the previous version's `ref`), not from a single tagged + * snapshot. + * + * The last entry is the in-progress version. Its `ref` stays `"HEAD"` + * until that version is tagged. On release, change it to the new tag + * and append a new in-progress entry for the version after it. + */ const VERSIONS: readonly { version: string; ref: string }[] = [ { version: "2.6", ref: "v2.6" }, { version: "3.0", ref: "v3.0" }, diff --git a/tools/generate-favicon.ts b/tools/generate-favicon.ts index 39cf43ed..5d13dc64 100644 --- a/tools/generate-favicon.ts +++ b/tools/generate-favicon.ts @@ -3,7 +3,7 @@ import { Resvg } from "@resvg/resvg-js"; import { handleMain, publishDir } from "./lib/utils.ts"; import { buildIco } from "./lib/ico.ts"; -// Standard Windows/browser favicon resolutions. +/** Standard Windows/browser favicon resolutions. */ const SIZES = [16, 32, 48]; async function main() { diff --git a/tools/generate-font-subsets.ts b/tools/generate-font-subsets.ts index 51a66f52..a6018077 100644 --- a/tools/generate-font-subsets.ts +++ b/tools/generate-font-subsets.ts @@ -12,17 +12,17 @@ interface FontJob { dist: string; } -// Each entry scans its `target` files for symbol/emoji characters and -// subsets only the glyphs its own font actually contains: pyftsubset drops -// codepoints missing from a font's cmap silently rather than erroring, so -// the same candidate character set can safely be offered to multiple fonts -// without cross-contamination (verified empirically before adopting this). +/** + * Font subset jobs. Each entry scans its `target` files for symbol + * and emoji characters and subsets only the glyphs its own font + * actually contains. `pyftsubset` silently drops codepoints missing + * from a font's cmap rather than erroring, so the same candidate + * character set can be offered to multiple fonts without + * cross-contamination. + */ const JOBS: Readonly> = { "NotoColorEmoji-COLRv1.ttf": { - // DOM-facing source only. The ✘/🚩 map markers under src/worker/ stamp - // baked Path2D shapes (see tools/generate-glyph-markers.ts) in a - // specific solid marker color; this layered color font would never - // apply to them even if scanned. + // WHY: exclude src/worker/. The ✘/🚩 map markers there stamp baked Path2D shapes (see tools/generate-glyph-markers.ts) in a solid marker color, so a layered color font would never apply to them. target: ["src/**/*.ts", "public/*.html", "tools/lib/prefab-html.ts"], exclude: [`${path.sep}worker${path.sep}`], dist: "NotoColorEmoji.subset.woff2", @@ -95,8 +95,11 @@ async function collectFiles(job: FontJob): Promise { return [...files]; } -// Reads maxp.numGlyphs from a raw (non-woff2) sfnt buffer, to sanity-check -// that a subset job actually kept more than just the mandatory .notdef glyph. +/** + * Reads `maxp.numGlyphs` from a raw (non-woff2) sfnt buffer as a + * sanity check that the subset job kept more than just the mandatory + * `.notdef` glyph. + */ function countGlyphs(sfnt: Uint8Array): number { const view = new DataView(sfnt.buffer, sfnt.byteOffset, sfnt.byteLength); const numTables = view.getUint16(4); diff --git a/tools/generate-glyph-markers.ts b/tools/generate-glyph-markers.ts index 6d4c6b49..2da78aba 100644 --- a/tools/generate-glyph-markers.ts +++ b/tools/generate-glyph-markers.ts @@ -15,19 +15,25 @@ import { interface MarkerJob { fontFile: string; glyph: string; - // Hand-tuned placement of `glyph` within the shared VIEWPORT square. + /** Hand-tuned placement of `glyph` within the shared `VIEWPORT` square. */ x: number; y: number; - // Point in the VIEWPORT square that render time should align with the - // target coordinate (e.g. the flag's pole base, not its bbox centre). + /** + * Point in the `VIEWPORT` square that render time should align with + * the target coordinate (e.g. the flag's pole base, not its bbox + * centre). + */ anchor: { x: number; y: number }; } -// Baked at build time; each job writes public/{name}.svg and -// public/{name}-path.json for canvas/SVG use without runtime font loading. +/** + * Marker jobs baked at build time. Each job writes + * `public/{name}.svg` and `public/{name}-path.json` for canvas/SVG + * use without runtime font loading. + */ const MARKERS: Readonly> = { "heavy-ballot-x": { - // U+2718 HEAVY BALLOT X, used for the Prefab Sign / Toggle Sign marker. + // WHY: U+2718 HEAVY BALLOT X drives the Prefab Sign / Toggle Sign marker. fontFile: "NotoSansSymbols2-Regular.ttf", glyph: "✘", x: 52, @@ -35,9 +41,7 @@ const MARKERS: Readonly> = { anchor: { x: 125.8, y: 117 }, }, "triangular-flag": { - // U+1F6A9 TRIANGULAR FLAG ON POST, used for the flag marker. Uses the - // "old" Noto Emoji release, which draws a filled flag; the current - // release's 🚩 is hollow and hard to see against map terrain. + // WHY: NotoEmojiOld draws a filled U+1F6A9 flag. The current release's 🚩 is hollow and hard to see against map terrain. fontFile: "NotoEmojiOld-Regular.ttf", glyph: "🚩", x: -18, diff --git a/tools/generate-labels-jsons.ts b/tools/generate-labels-jsons.ts index cd54ae78..1d38caee 100644 --- a/tools/generate-labels-jsons.ts +++ b/tools/generate-labels-jsons.ts @@ -18,8 +18,7 @@ async function main() { vanillaDir("Data", "Config", "Localization.csv"), ); - // Pre-group labels by their source file once, so per-language extraction - // does not re-scan the full label Map for every (lang, file) pair. + // WHY: per-language extraction would otherwise re-scan the full label Map for every (lang, file) pair. const labelsByFile = buildArrayMapByEntries( Array.from(labels, ([id, label]) => [label.file, [id, label] as const]), ); diff --git a/tools/generate-prefab-html.ts b/tools/generate-prefab-html.ts index 66a0db3c..52ad0ef1 100644 --- a/tools/generate-prefab-html.ts +++ b/tools/generate-prefab-html.ts @@ -89,7 +89,6 @@ async function copyJpg(xmlFileName: string) { await fs.copyFile(jpg, dist); } catch (e) { if (isErrnoException(e) && e.code === "ENOENT") { - // No jpg return; } throw e; diff --git a/tools/generate-prefab-properties-jsons.ts b/tools/generate-prefab-properties-jsons.ts index bb20c166..3d92c98f 100644 --- a/tools/generate-prefab-properties-jsons.ts +++ b/tools/generate-prefab-properties-jsons.ts @@ -96,8 +96,11 @@ function extractDifficulties(prefabXmls: PrefabXmls) { ); } -// PrefabSize "X, Y, Z" β†’ [X (width), Z (depth), Y (height), yOffset]. Absent or -// zero footprint (sign/part) is skipped; a malformed present value throws. +/** + * Reshapes `PrefabSize` from `"X, Y, Z"` into `[X (width), Z (depth), + * Y (height), yOffset]`. Prefabs with an absent or zero footprint + * (signs, embedded parts) are skipped. A malformed present value throws. + */ export function extractMeshSizes(prefabXmls: PrefabXmls) { return Object.fromEntries( Object.entries(prefabXmls) @@ -116,7 +119,7 @@ export function extractMeshSizes(prefabXmls: PrefabXmls) { number, number, ]; - // Zero/negative footprints (embedded parts) have no drawable box. + // WHY: zero or negative footprints belong to embedded parts and have no drawable box. if (x <= 0 || z <= 0) return []; const yOffset = parseYOffset( findValueEntry(entries, "YOffset")?.value, @@ -129,8 +132,11 @@ export function extractMeshSizes(prefabXmls: PrefabXmls) { ); } -// YOffset is authored as an integer string; reject anything else so a schema -// change surfaces loudly instead of coercing to a wrong box depth. +/** + * Parses the `YOffset` property. It is authored as an integer string, + * so anything else is rejected. Silent coercion would push the drawable + * box to the wrong depth on a schema change. + */ function parseYOffset(raw: string | undefined, prefabName: string): number { if (raw === undefined) return 0; if (!/^-?\d+$/.test(raw.trim())) { @@ -139,10 +145,13 @@ function parseYOffset(raw: string | undefined, prefabName: string): number { return parseInt(raw.trim(), 10); } -// Mirrors PrefabData.Init: DensityScore = (TotalVertices + 50000) / 100000 -// using C# integer division, so the result is always an int. Prefabs without -// a Stats block (or TotalVertices=0) get 0 and become "low density" which the -// renderer treats as Γ—0.4 brightness, matching the game preview. +/** + * Mirrors `PrefabData.Init`: `DensityScore = (TotalVertices + 50000) / + * 100000` using C# integer division, so the result is always an int. + * Prefabs without a `Stats` block (or `TotalVertices=0`) get 0 and + * become "low density", which the renderer treats as Γ—0.4 brightness + * to match the game preview. + */ function extractDensityScores(prefabXmls: PrefabXmls) { return Object.fromEntries( Object.entries(prefabXmls) @@ -168,9 +177,11 @@ function rgbFloatToHex([r, g, b]: [number, number, number]): string { return `#${hex(r)}${hex(g)}${hex(b)}`; } -// District preview_color lookup table consumed by the renderer at draw time. -// Districts without a preview_color are dropped so the renderer can fall back -// to the wilderness default. +/** + * Builds the district `preview_color` lookup table consumed by the + * renderer at draw time. Districts without a `preview_color` are + * dropped so the renderer can fall back to the wilderness default. + */ function extractDistrictColors(districts: District[]) { return Object.fromEntries( districts diff --git a/tools/lib/ico.ts b/tools/lib/ico.ts index b82a8870..4c9794e6 100644 --- a/tools/lib/ico.ts +++ b/tools/lib/ico.ts @@ -1,7 +1,3 @@ -// Builds a multi-resolution .ico file from PNG-encoded images, using the -// ICONDIR/ICONDIRENTRY layout from the ICO format spec. Modern ICO readers -// (Windows Vista+, browsers) accept PNG-compressed entries directly, so no -// BMP conversion is needed. const ICONDIR_BYTES = 6; const ICONDIRENTRY_BYTES = 16; @@ -10,6 +6,26 @@ export interface IcoImage { png: Uint8Array; } +/** + * Builds a multi-resolution `.ico` file from PNG-encoded images. Modern + * ICO readers (Windows Vista+, browsers) accept PNG-compressed entries + * directly, so no BMP conversion is needed. + * + * ICONDIR (6 bytes): + * 0 uint16 reserved (0) + * 2 uint16 type (1 = icon) + * 4 uint16 image count + * + * ICONDIRENTRY (16 bytes, one per image): + * 0 uint8 width (0 encodes 256) + * 1 uint8 height (0 encodes 256) + * 2 uint8 color count (0 = no palette) + * 3 uint8 reserved + * 4 uint16 color planes + * 6 uint16 bits per pixel + * 8 uint32 image size + * 12 uint32 image offset + */ export function buildIco(images: readonly IcoImage[]): Uint8Array { if (images.length === 0) { throw new Error("buildIco: at least one image is required"); @@ -28,19 +44,19 @@ export function buildIco(images: readonly IcoImage[]): Uint8Array { const out = new Uint8Array(totalSize); const view = new DataView(out.buffer); - view.setUint16(0, 0, true); // reserved - view.setUint16(2, 1, true); // type: 1 = icon + view.setUint16(0, 0, true); + view.setUint16(2, 1, true); view.setUint16(4, images.length, true); let dataOffset = dirSize; images.forEach(({ size, png }, i) => { const entryOffset = ICONDIR_BYTES + ICONDIRENTRY_BYTES * i; - out[entryOffset] = size === 256 ? 0 : size; // width, 0 means 256 - out[entryOffset + 1] = size === 256 ? 0 : size; // height, 0 means 256 - out[entryOffset + 2] = 0; // color count: 0 = no palette - out[entryOffset + 3] = 0; // reserved - view.setUint16(entryOffset + 4, 1, true); // color planes - view.setUint16(entryOffset + 6, 32, true); // bits per pixel + out[entryOffset] = size === 256 ? 0 : size; + out[entryOffset + 1] = size === 256 ? 0 : size; + out[entryOffset + 2] = 0; + out[entryOffset + 3] = 0; + view.setUint16(entryOffset + 4, 1, true); + view.setUint16(entryOffset + 6, 32, true); view.setUint32(entryOffset + 8, png.length, true); view.setUint32(entryOffset + 12, dataOffset, true); diff --git a/tools/lib/prefab-files.ts b/tools/lib/prefab-files.ts index e49520f8..6ed0e3eb 100644 --- a/tools/lib/prefab-files.ts +++ b/tools/lib/prefab-files.ts @@ -2,14 +2,14 @@ import * as path from "node:path"; import { expandGlob } from "@std/fs/expand-glob"; import { vanillaDir } from "./utils.ts"; -// Known prefab sidecar suffixes. Order matters: longer suffixes (e.g. -// ".blocks.nim") must precede shorter ones (".nim") so stripping picks the -// most specific match. +// INVARIANT: longer suffixes must precede shorter ones so that stripping picks the most specific match (e.g. `.blocks.nim` before `.nim`). const PREFAB_SUFFIXES = [".blocks.nim", ".tts", ".xml", ".jpg"] as const; -// Predicate for prefab XML files that should be ignored β€” currently the -// auto-generated `_signs.xml` companion files. Consolidated here so that -// any future exclusions live in a single place. +/** + * Predicate for prefab XML files that should be ignored, currently the + * auto-generated `_signs.xml` companion files. Consolidated so + * future exclusions live in one place. + */ function isIgnoredPrefabXml(p: string): boolean { return p.endsWith("_signs.xml"); } diff --git a/tools/lib/symbol-chars.ts b/tools/lib/symbol-chars.ts index a6449eed..f070ad49 100644 --- a/tools/lib/symbol-chars.ts +++ b/tools/lib/symbol-chars.ts @@ -1,28 +1,44 @@ import { requireNonnull } from "./utils.ts"; -// Hand-picked Unicode block ranges covering emoji/pictograph/dingbat/symbol -// characters used across the app, both as literal DOM text and as canvas -// marker glyphs. Deliberately broader than a "recognized emoji" list (e.g. -// @twemoji/parser's), so symbol-only characters such as ✘ (U+2718, in the -// Dingbats block) are matched too even though no emoji font renders them -// with emoji presentation. +/** + * Hand-picked Unicode block ranges covering the emoji, pictograph, + * dingbat, and symbol characters the app renders. Deliberately broader + * than a "recognized emoji" list (e.g. `@twemoji/parser`'s) so + * symbol-only characters such as ✘ (U+2718, Dingbats block) are matched + * too even though no emoji font renders them with emoji presentation. + * + * 0x1f100-0x1f1ff: Enclosed alphanumeric supplement (e.g. πŸ†•), regional indicators + * 0x1f300-0x1faff: Misc symbols and pictographs, emoticons, transport, supplemental symbols + * 0x2100-0x214f: Letterlike symbols (e.g. β„Ή) + * 0x2190-0x21ff: Arrows + * 0x2300-0x23ff: Misc technical (e.g. βŒ›, βŒ–) + * 0x25a0-0x25ff: Geometric shapes (e.g. β–½) + * 0x2600-0x27bf: Misc symbols and Dingbats (e.g. ✘, βœ…, ☒, ⚠, ❌) + * 0x2b00-0x2bff: Misc symbols and arrows (e.g. ⬇) + */ const SYMBOL_RANGES: readonly (readonly [number, number])[] = [ - [0x1f100, 0x1f1ff], // Enclosed alphanumeric supplement (e.g. πŸ†•) + regional indicators - [0x1f300, 0x1faff], // Misc symbols/pictographs, emoticons, transport, supplemental symbols - [0x2100, 0x214f], // Letterlike symbols (e.g. β„Ή) - [0x2190, 0x21ff], // Arrows - [0x2300, 0x23ff], // Misc technical (e.g. βŒ›, βŒ–) - [0x25a0, 0x25ff], // Geometric shapes (e.g. β–½) - [0x2600, 0x27bf], // Misc symbols + Dingbats (e.g. ✘, βœ…, ☒, ⚠, ❌) - [0x2b00, 0x2bff], // Misc symbols and arrows (e.g. ⬇) + [0x1f100, 0x1f1ff], + [0x1f300, 0x1faff], + [0x2100, 0x214f], + [0x2190, 0x21ff], + [0x2300, 0x23ff], + [0x25a0, 0x25ff], + [0x2600, 0x27bf], + [0x2b00, 0x2bff], ]; -// Not symbols by themselves, but needed to render some glyphs' intended form -// (e.g. U+FE0F selects the emoji-style πŸ—ΊοΈ over the plain πŸ—Ί text glyph). +/** + * Not symbols by themselves, but needed to render some glyphs' intended + * form (e.g. U+FE0F selects emoji-style πŸ—ΊοΈ over the plain text πŸ—Ί). + * + * 0xfe0f: variation selector-16 (emoji presentation) + * 0x200d: zero-width joiner (ZWJ sequences) + * 0x20e3: combining enclosing keycap + */ const EXTRA_CODE_POINTS = new Set([ - 0xfe0f, // variation selector-16 (emoji presentation) - 0x200d, // zero-width joiner (ZWJ sequences) - 0x20e3, // combining enclosing keycap + 0xfe0f, + 0x200d, + 0x20e3, ]); export function extractSymbolChars(text: string): Set { diff --git a/tools/lib/utils.ts b/tools/lib/utils.ts index 76fdec58..638a3233 100644 --- a/tools/lib/utils.ts +++ b/tools/lib/utils.ts @@ -12,8 +12,11 @@ export function publishDir(...pathList: string[]): string { return projectRoot("public", ...pathList); } -// Must stay a static project-relative path: `deno task` input-based -// caching needs it expressible as a glob in `deno.jsonc:files`. +/** + * Resolves a project-relative path under `tools/vanilla`. Must stay a + * static project-relative path because `deno task` input-based caching + * needs to express it as a glob in `deno.jsonc:files`. + */ export function vanillaDir(...pathList: string[]): string { return projectRoot("tools", "vanilla", ...pathList); } @@ -53,8 +56,11 @@ export async function writeJsonFile( console.log("Write %s", file); } -// Same line structure as JSON.stringify(json, null, "\t") so diffs stay -// per-entry, but without indentation or spaces after ":" and ",". +/** + * Serializes JSON with the same line structure as `JSON.stringify(json, + * null, "\t")` so diffs stay per-entry, but without indentation or + * spaces after `":"` and `","`. + */ function compactStringify( value: unknown, collapseLeafArrays: boolean, @@ -84,10 +90,12 @@ function isJsonPrimitive(value: unknown): boolean { typeof value === "number" || typeof value === "boolean"; } -// Folds tab-indented arrays of primitives onto a single line so callers like -// the mesh-sizes table render as `"name": [w, d]` instead of spanning four -// lines. Only matches JSON primitives (numbers / strings / booleans / null), -// so structured elements stay pretty-printed. +/** + * Folds tab-indented arrays of primitives onto a single line so callers + * like the mesh-sizes table render as `"name": [w, d]` instead of + * spanning four lines. Only matches JSON primitives (numbers, strings, + * booleans, null), so structured elements stay pretty-printed. + */ function collapseLeafArrays(body: string): string { const primitive = `(?:-?\\d+(?:\\.\\d+)?|"(?:[^"\\\\]|\\\\.)*"|true|false|null)`; diff --git a/tools/lint-plugins/require-comment-rationale.ts b/tools/lint-plugins/require-comment-rationale.ts index 120d8a7a..a515f882 100644 --- a/tools/lint-plugins/require-comment-rationale.ts +++ b/tools/lint-plugins/require-comment-rationale.ts @@ -66,23 +66,6 @@ const EXCLUDED_PATHS: readonly string[] = [ "/src/worker/lib/prefab-filter.ts", "/src/worker/map-renderer.ts", "/src/worker/prefabs-filter.ts", - "/tools/bench-prefab-filter.ts", - "/tools/build.ts", - "/tools/copy-map-files.ts", - "/tools/extract-added-prefabs.ts", - "/tools/generate-favicon.ts", - "/tools/generate-font-subsets.ts", - "/tools/generate-glyph-markers.ts", - "/tools/generate-labels-jsons.ts", - "/tools/generate-prefab-html.ts", - "/tools/generate-prefab-properties-jsons.ts", - "/tools/lib/ico.ts", - "/tools/lib/prefab-files.ts", - "/tools/lib/symbol-chars.ts", - "/tools/lib/utils.ts", - "/tools/print-png-pixel-stat.ts", - "/tools/print-tts.ts", - "/tools/verify-steel-wrench-filter.ts", "/e2e/index.spec.ts", "/e2e/prefabs.spec.ts", "/playwright.config.ts", diff --git a/tools/print-png-pixel-stat.ts b/tools/print-png-pixel-stat.ts index 3ffc44e5..649a652e 100644 --- a/tools/print-png-pixel-stat.ts +++ b/tools/print-png-pixel-stat.ts @@ -34,8 +34,7 @@ export function statDecodedPixels(decoded: DecodedPng): Map { const data = decoded.data; const stat = new Map(); for (let i = 0; i < data.length; i += 4) { - // Pack RGBA into a single non-negative 32-bit integer so the Map key - // is a number rather than an allocated string per pixel. + // WHY: pack RGBA into a single non-negative 32-bit integer so the Map key is a number rather than an allocated string per pixel. // deno-lint-ignore no-non-null-assertion const key = data[i]! * 0x1000000 + // deno-lint-ignore no-non-null-assertion diff --git a/tools/print-tts.ts b/tools/print-tts.ts index c41ef818..0bc7e976 100644 --- a/tools/print-tts.ts +++ b/tools/print-tts.ts @@ -17,7 +17,6 @@ async function main() { console.log("Each number of blocks:"); console.log(tts.blockNums); - // print block IDs slicing horizontally. for (let y = 0; y < tts.maxy; y += 1) { console.log("height = %d", y); for (let z = 0; z < tts.maxz; z += 1) { diff --git a/tools/verify-steel-wrench-filter.ts b/tools/verify-steel-wrench-filter.ts index abc62735..37c7aac6 100644 --- a/tools/verify-steel-wrench-filter.ts +++ b/tools/verify-steel-wrench-filter.ts @@ -3,7 +3,6 @@ import { loadBlocks } from "./lib/xmls/blocks-xml.ts"; import { loadMaterials } from "./lib/xmls/materials-xml.ts"; async function main() { - // Collect blocks that pass the programmatic filter const blocks = await loadBlocks(); const materials = await loadMaterials(); const harvests = blocks.getHarvestsWithMaxDamage(materials).filter((drop) => @@ -14,18 +13,17 @@ async function main() { if (gunSafeScore === 0) throw new Error("gunSafeScore is 0"); const filtered = new Set(); for (const harvest of harvests) { - // Avoid high durability blocks harder than gunSafeScore + // WHY: skip blocks harder than gunSafeScore so the effective steel yield is not overstated. if (harvest.countPerDamage <= gunSafeScore) continue; - // Avoid working vending machines + // WHY: skip working vending machines because their broken variants alone drop steel. if (/^cntVending.*(? b.name).filter((name) => regexp.test(name)), );