mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-02 08:07:40 -05:00
Move app to apps/web-react in pnpm workspace layout
This commit is contained in:
51
apps/web-react/app/features/scanner/node/resources.ts
Normal file
51
apps/web-react/app/features/scanner/node/resources.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Node IO for ScoreboardResources: reads the scanner asset sets from the local
|
||||
* sendou-ink/assets checkout (tests and atlas builders never touch the
|
||||
* CDN). Game icons come from the checkout's shared `img/**` tree, the
|
||||
* scanner-specific atlases from `scanner/v1/**`. What the bundle contains — every
|
||||
* key, template option set, and atlas name — lives in core/resources.ts,
|
||||
* shared with the worker's HTTP loader.
|
||||
*/
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
loadPlannerStages,
|
||||
type PlannerManifest,
|
||||
type PlannerStage,
|
||||
} from "../core/detectors/minimap/stage";
|
||||
import type { ScoreboardResources } from "../core/detectors/scoreboard/index";
|
||||
import { type AtlasMeta, type GlyphSet, loadGlyphSet } from "../core/glyphs";
|
||||
import { assembleScoreboardResources } from "../core/resources";
|
||||
import { SCANNER_ASSETS_DIR as ASSETS_DIR, GAME_IMG_DIR } from "./assets-dir";
|
||||
import { readImage } from "./image-io";
|
||||
|
||||
/** Decode eagerly, defer the (CPU-heavy) glyph slicing to first access. */
|
||||
async function loadAtlasLazy(name: string): Promise<() => GlyphSet | null> {
|
||||
const png = join(ASSETS_DIR, "glyphs", `${name}.png`);
|
||||
const json = join(ASSETS_DIR, "glyphs", `${name}.json`);
|
||||
if (!existsSync(png) || !existsSync(json)) return () => null;
|
||||
const meta = JSON.parse(readFileSync(json, "utf8")) as AtlasMeta;
|
||||
const image = await readImage(png);
|
||||
let set: GlyphSet | null = null;
|
||||
return () => (set ??= loadGlyphSet(image, meta));
|
||||
}
|
||||
|
||||
/** Planner stage signatures; the (CPU) tile slicing runs on first access. */
|
||||
async function loadPlannerStagesLazy(): Promise<() => PlannerStage[] | null> {
|
||||
const png = join(ASSETS_DIR, "planner", "signatures.png");
|
||||
const json = join(ASSETS_DIR, "planner", "manifest.json");
|
||||
if (!existsSync(png) || !existsSync(json)) return () => null;
|
||||
const manifest = JSON.parse(readFileSync(json, "utf8")) as PlannerManifest;
|
||||
const atlas = await readImage(png);
|
||||
let stages: PlannerStage[] | null = null;
|
||||
return () => (stages ??= loadPlannerStages(atlas, manifest));
|
||||
}
|
||||
|
||||
/** Requires loadOpenCV() to have resolved. */
|
||||
export function loadScoreboardResources(): Promise<ScoreboardResources> {
|
||||
return assembleScoreboardResources({
|
||||
readIcon: (dir, id) => readImage(join(GAME_IMG_DIR, dir, `${id}.avif`)),
|
||||
loadAtlas: loadAtlasLazy,
|
||||
loadPlannerStages: loadPlannerStagesLazy,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user