diff --git a/src/lib/services/catalog-audit.ts b/src/lib/services/catalog-audit.ts index af9cb25639..eaafa83b80 100644 --- a/src/lib/services/catalog-audit.ts +++ b/src/lib/services/catalog-audit.ts @@ -344,9 +344,11 @@ export async function runCatalogAudit( const missingIconClassnames: string[] = []; for (let i = 0; i < items.length; i++) { const item = items[i]; - // Badge items use .gif icons, not .png icons. - if (item.interaction_type === "badge") continue; - if (!iconSet.has(`${item.item_name}_icon.png`)) { + // Badge items use .gif icons stored as badge__icon.png, + // not _icon.png like regular furni. + const iconFileName = `${item.item_name}_icon.png`; + const badgeIconFileName = `badge_${item.item_name}_icon.png`; + if (!iconSet.has(iconFileName) && !iconSet.has(badgeIconFileName)) { missingIconClassnames.push(item.item_name); issues.push({ type: "missing_icon", diff --git a/src/lib/services/repair-icons.ts b/src/lib/services/repair-icons.ts index 1651b0cc8c..f62ae4568e 100644 --- a/src/lib/services/repair-icons.ts +++ b/src/lib/services/repair-icons.ts @@ -140,14 +140,11 @@ export async function repairMissingIcons( ...targets.mirrorDirs.map((d) => d.nitroDir), ]); - let items: Array<{ id: number; item_name: string; interaction_type: string }>; + let items: Array<{ id: number; item_name: string }>; try { const [rows] = (await db.execute(sql` - SELECT id, item_name, interaction_type FROM items_base ORDER BY id - `)) as unknown as [ - Array<{ id: number; item_name: string; interaction_type: string }>, - unknown, - ]; + SELECT id, item_name FROM items_base ORDER BY id + `)) as unknown as [Array<{ id: number; item_name: string }>, unknown]; items = rows; } catch (err) { onEvent?.({ @@ -160,17 +157,15 @@ export async function repairMissingIcons( const total = items.length; onEvent?.({ type: "started", total }); - const processItem = async (classname: string, interactionType: string) => { - // Badge items use .gif icons, not .png icons. - if (interactionType === "badge") { - return { status: "skipped" } as const; - } + const processItem = async (classname: string) => { const fileName = `${classname}_icon.png`; + const badgeFileName = `badge_${classname}_icon.png`; - // A dir may already have the icon (e.g. the full gamedata) while the - // webroot is missing it — treat the item as present when every target has it. - const presentDirs = iconDirs.filter((dir) => - existsSync(path.join(dir, fileName)), + // Badge items store icons as badge__icon.png, not _icon.png. + const presentDirs = iconDirs.filter( + (dir) => + existsSync(path.join(dir, fileName)) || + existsSync(path.join(dir, badgeFileName)), ); const missingDirs = iconDirs.filter((dir) => !presentDirs.includes(dir)); @@ -244,6 +239,7 @@ export async function repairMissingIcons( for (const source of sources) { const iconCandidates = [ `${classname}_icon.png`, + `badge_${classname}_icon.png`, // Variant classnames (e.g. `table_silo_med*10`) often only exist // on sources under their base name (e.g. `table_silo_med_icon.png`) // or with the `*` replaced by `_` (e.g. `table_silo_med_10_icon.png`). @@ -333,7 +329,7 @@ export async function repairMissingIcons( await runPool(items, REPAIR_CONCURRENCY, async (item, i) => { const classname = item.item_name; - const result = await processItem(classname, item.interaction_type); + const result = await processItem(classname); if (result.status === "skipped") { skipped++; onEvent?.({