diff --git a/web/client/src/components/ItemIcon.jsx b/web/client/src/components/ItemIcon.jsx index 40b32c7..8b90e1a 100644 --- a/web/client/src/components/ItemIcon.jsx +++ b/web/client/src/components/ItemIcon.jsx @@ -10,6 +10,19 @@ const TEXTURE_ALIASES = { // Renamed items in 1.20+ grass: 'short_grass', scute: 'turtle_scute', + // Animated items — pick a representative frame + compass: 'compass_16', + recovery_compass: 'recovery_compass_16', + clock: 'clock_22', + // Texture file named differently from item ID + magma_block: 'magma', + crossbow: 'crossbow_standby', + enchanted_golden_apple: 'golden_apple', + light: 'light_15', + // "Smooth" variants use their parent's face texture + smooth_sandstone: 'sandstone_top', + smooth_red_sandstone: 'red_sandstone_top', + smooth_quartz: 'quartz_block_bottom', }; // CC:Tweaked texture paths (registry name → actual file in the CC repo) @@ -38,6 +51,65 @@ const CC_TEXTURE_MAP = { printed_pages: 'item/printed_pages', }; +// Create mod — items whose textures live in nested directories +const CREATE_TEXTURE_MAP = { + // Stone types (deeply nested in palettes/) + veridium: 'block/palettes/stone_types/natural/veridium_0', + scorchia: 'block/palettes/stone_types/scorchia', + asurine: 'block/palettes/stone_types/natural/asurine_0', + crimsite: 'block/palettes/stone_types/natural/crimsite_0', + ochrum: 'block/palettes/stone_types/natural/ochrum_0', +}; + +// Wood types for carpet/wood/log resolution +const WOOD_TYPE_SET = new Set([ + 'oak', 'spruce', 'birch', 'jungle', 'acacia', 'dark_oak', + 'mangrove', 'cherry', 'bamboo', 'crimson', 'warped', 'pale_oak', +]); +const DYE_COLORS = new Set([ + 'white', 'orange', 'magenta', 'light_blue', 'yellow', 'lime', + 'pink', 'gray', 'light_gray', 'cyan', 'purple', 'blue', + 'brown', 'green', 'red', 'black', +]); + +/** + * Resolve item names that follow a pattern (carpets, wood, etc.) + * to their actual texture name + folder. Returns { name, isBlock } or null. + */ +function resolveDynamicAlias(name) { + // Carpets use their wool texture: white_carpet → white_wool (block/) + if (name.endsWith('_carpet')) { + const color = name.slice(0, -'_carpet'.length); + if (DYE_COLORS.has(color)) { + return { name: `${color}_wool`, isBlock: true }; + } + } + + // Wood (all-bark block) uses log texture: spruce_wood → spruce_log (block/) + if (name.endsWith('_wood')) { + const base = name.slice(0, -'_wood'.length); + const stripped = base.startsWith('stripped_') ? base.slice('stripped_'.length) : null; + const woodType = stripped || base; + if (WOOD_TYPE_SET.has(woodType)) { + return { name: stripped ? `stripped_${woodType}_log` : `${woodType}_log`, isBlock: true }; + } + } + + // Beds, banners, skulls/heads — entity-only textures, skip to emoji immediately + if (name.endsWith('_bed') && DYE_COLORS.has(name.slice(0, -'_bed'.length))) return { name: null }; + if (name.endsWith('_banner') && DYE_COLORS.has(name.slice(0, -'_banner'.length))) return { name: null }; + if (name.endsWith('_skull') || name.endsWith('_head')) return { name: null }; + + // Other entity/3D-model-only items with no flat texture + const ENTITY_ONLY = new Set([ + 'chest', 'ender_chest', 'trapped_chest', 'shield', 'conduit', + 'bell', 'decorated_pot', 'trident', + ]); + if (ENTITY_ONLY.has(name)) return { name: null }; + + return null; +} + // Items whose texture lives in the block/ folder instead of item/ const BLOCK_TEXTURES = new Set([ 'stone', 'granite', 'polished_granite', 'diorite', 'polished_diorite', 'andesite', @@ -103,6 +175,14 @@ const BLOCK_TEXTURES = new Set([ 'mushroom_stem', 'brown_mushroom_block', 'red_mushroom_block', 'oak_leaves', 'spruce_leaves', 'birch_leaves', 'jungle_leaves', 'acacia_leaves', 'dark_oak_leaves', 'mangrove_leaves', 'cherry_leaves', 'azalea_leaves', + // Trapdoors + 'oak_trapdoor', 'spruce_trapdoor', 'birch_trapdoor', 'jungle_trapdoor', + 'acacia_trapdoor', 'dark_oak_trapdoor', 'mangrove_trapdoor', 'cherry_trapdoor', + 'bamboo_trapdoor', 'crimson_trapdoor', 'warped_trapdoor', 'iron_trapdoor', + 'copper_trapdoor', 'exposed_copper_trapdoor', 'weathered_copper_trapdoor', + 'oxidized_copper_trapdoor', 'pale_oak_trapdoor', + // Dirt path and magma + 'dirt_path', 'magma', // Additional blocks commonly seen as items 'smooth_stone', 'smooth_sandstone', 'smooth_red_sandstone', 'smooth_quartz', 'chiseled_sandstone', 'cut_sandstone', 'chiseled_red_sandstone', 'cut_red_sandstone', @@ -160,6 +240,8 @@ const BLOCK_TEXTURE_SUFFIXES = { grass_block: '_top', mycelium: '_top', podzol: '_top', + dirt_path: '_top', + quartz_block: '_side', pumpkin: '_side', carved_pumpkin: '_front', jack_o_lantern: '_front', @@ -171,7 +253,6 @@ const BLOCK_TEXTURE_SUFFIXES = { bone_block: '_side', basalt: '_side', polished_basalt: '_side', - quartz_pillar: '_side', purpur_pillar: '_side', tnt: '_side', composter: '_side', @@ -231,8 +312,12 @@ function getTextureUrls(fullItemName) { return urls; } - // Create mod → item/ then block/ + // Create mod → curated map first, then item/ then block/ if (namespace === 'create') { + const mapped = CREATE_TEXTURE_MAP[shortName]; + if (mapped) { + urls.push(`${TEXTURE_PROXY_BASE}/create/${mapped}.png`); + } urls.push(`${TEXTURE_PROXY_BASE}/create/item/${shortName}.png`); urls.push(`${TEXTURE_PROXY_BASE}/create/block/${shortName}.png`); return urls; @@ -244,6 +329,17 @@ function getTextureUrls(fullItemName) { } // === Vanilla (minecraft) === + + // Dynamic aliases: carpets→wool, wood→log, entity-only→skip + const dynamic = resolveDynamicAlias(shortName); + if (dynamic) { + if (dynamic.name === null) return urls; // entity-only → instant emoji + if (dynamic.isBlock) { + urls.push(`${TEXTURE_PROXY_BASE}/minecraft/block/${dynamic.name}.png`); + return urls; + } + } + const alias = TEXTURE_ALIASES[shortName] || shortName; // Derivative blocks (stairs, slabs, fences, walls, buttons) → parent texture