From 81e0dc4959c5f9f74a8a8d664f383c24808265ce Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Mon, 16 Feb 2026 01:52:10 -0500 Subject: [PATCH] feat: Enhance block appearance handling with detailed color and texture info, and improve block rendering performance --- client/src/components/Map3D.jsx | 129 ++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 46 deletions(-) diff --git a/client/src/components/Map3D.jsx b/client/src/components/Map3D.jsx index 44640b2..0cd3964 100644 --- a/client/src/components/Map3D.jsx +++ b/client/src/components/Map3D.jsx @@ -18,7 +18,8 @@ function TurtleModel({ turtle, isSelected, onClick }) { if (!position) return null; // Calculate rotation based on facing (0=North(-Z), 1=East(+X), 2=South(+Z), 3=West(-X)) - const rotation = facing !== undefined ? [0, (facing * Math.PI / 2), 0] : [0, 0, 0]; + // Add 180 degrees (Math.PI) to face the head forward initially, then apply facing rotation + const rotation = facing !== undefined ? [0, (facing * Math.PI / 2) + Math.PI, 0] : [0, Math.PI, 0]; const color = mode === 'mining' ? '#4ade80' : mode === 'exploring' ? '#60a5fa' : @@ -134,69 +135,105 @@ function PathTrail({ turtle }) { ); } -// Get color for block type -function getBlockColor(blockName) { - if (!blockName) return '#888'; +// Get color and texture info for block type +function getBlockAppearance(blockName) { + if (!blockName) return { color: '#888', pattern: 'solid' }; const name = blockName.toLowerCase(); - // Ores - if (name.includes('diamond')) return '#00ffff'; - if (name.includes('emerald')) return '#00ff00'; - if (name.includes('gold')) return '#ffd700'; - if (name.includes('iron')) return '#d4d4d4'; - if (name.includes('coal')) return '#1a1a1a'; - if (name.includes('redstone')) return '#ff0000'; - if (name.includes('lapis')) return '#0000ff'; - if (name.includes('copper')) return '#ff8c00'; + // Ores - bright colors with sparkle + if (name.includes('diamond')) return { color: '#00ffff', pattern: 'ore', emissive: '#00ffff', intensity: 0.3 }; + if (name.includes('emerald')) return { color: '#00ff00', pattern: 'ore', emissive: '#00ff00', intensity: 0.3 }; + if (name.includes('gold')) return { color: '#ffd700', pattern: 'ore', emissive: '#ffd700', intensity: 0.2 }; + if (name.includes('iron')) return { color: '#d4d4d4', pattern: 'ore' }; + if (name.includes('coal')) return { color: '#1a1a1a', pattern: 'ore' }; + if (name.includes('redstone')) return { color: '#ff0000', pattern: 'ore', emissive: '#ff0000', intensity: 0.2 }; + if (name.includes('lapis')) return { color: '#1e40af', pattern: 'ore' }; + if (name.includes('copper')) return { color: '#ff8c00', pattern: 'ore' }; - // Common blocks - if (name.includes('stone')) return '#7f7f7f'; - if (name.includes('dirt')) return '#8b4513'; - if (name.includes('grass')) return '#228b22'; - if (name.includes('sand')) return '#f4a460'; - if (name.includes('gravel')) return '#808080'; - if (name.includes('bedrock')) return '#222'; - if (name.includes('obsidian')) return '#1a0033'; - if (name.includes('netherrack')) return '#8b0000'; + // Common blocks - textured + if (name.includes('stone') && !name.includes('cobble')) return { color: '#7f7f7f', pattern: 'stone' }; + if (name.includes('cobblestone')) return { color: '#808080', pattern: 'cobble' }; + if (name.includes('dirt')) return { color: '#8b4513', pattern: 'dirt' }; + if (name.includes('grass')) return { color: '#228b22', pattern: 'grass' }; + if (name.includes('sand')) return { color: '#f4a460', pattern: 'sand' }; + if (name.includes('gravel')) return { color: '#808080', pattern: 'gravel' }; + if (name.includes('bedrock')) return { color: '#222', pattern: 'solid' }; + if (name.includes('obsidian')) return { color: '#1a0033', pattern: 'solid' }; + if (name.includes('netherrack')) return { color: '#8b0000', pattern: 'netherrack' }; - return '#666666'; // Default + return { color: '#666666', pattern: 'solid' }; } // WorldBlocks component to render discovered blocks function WorldBlocks({ blocks }) { - const meshes = useMemo(() => { - const instances = new Map(); + const [hoveredBlock, setHoveredBlock] = React.useState(null); + + // Group blocks by appearance for better performance + const blockGroups = useMemo(() => { + const groups = new Map(); blocks.forEach(block => { - const color = getBlockColor(block.name); - if (!instances.has(color)) { - instances.set(color, []); + const appearance = getBlockAppearance(block.name); + const key = `${appearance.color}-${appearance.pattern}`; + + if (!groups.has(key)) { + groups.set(key, { appearance, blocks: [] }); } - instances.get(color).push(block); + groups.get(key).blocks.push(block); }); - return instances; + return Array.from(groups.values()); }, [blocks]); return ( - {Array.from(meshes.entries()).map(([color, blockList]) => ( - - {blockList.map((block, idx) => ( - - - - - ))} + {blockGroups.map((group, groupIdx) => ( + + {group.blocks.map((block) => { + const appearance = group.appearance; + const blockKey = `${block.x},${block.y},${block.z}`; + const isHovered = hoveredBlock === blockKey; + + return ( + + { + e.stopPropagation(); + setHoveredBlock(blockKey); + }} + onPointerOut={() => setHoveredBlock(null)} + > + + + + + {/* Block label on hover */} + {isHovered && ( + + {block.name.replace('minecraft:', '').replace(/_/g, ' ').toUpperCase()} + + )} + + ); + })} ))}