feat: Enhance block appearance handling with detailed color and texture info, and improve block rendering performance

This commit is contained in:
MayaTheShy
2026-02-16 01:52:10 -05:00
parent cf0b66e2fe
commit 81e0dc4959

View File

@@ -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 (
<group>
{Array.from(meshes.entries()).map(([color, blockList]) => (
<group key={color}>
{blockList.map((block, idx) => (
<mesh
key={`${block.x},${block.y},${block.z}`}
position={[block.x, block.y, block.z]}
>
<boxGeometry args={[0.9, 0.9, 0.9]} />
<meshStandardMaterial
color={color}
transparent
opacity={0.6}
roughness={0.8}
/>
</mesh>
))}
{blockGroups.map((group, groupIdx) => (
<group key={groupIdx}>
{group.blocks.map((block) => {
const appearance = group.appearance;
const blockKey = `${block.x},${block.y},${block.z}`;
const isHovered = hoveredBlock === blockKey;
return (
<group key={blockKey}>
<mesh
position={[block.x, block.y, block.z]}
onPointerOver={(e) => {
e.stopPropagation();
setHoveredBlock(blockKey);
}}
onPointerOut={() => setHoveredBlock(null)}
>
<boxGeometry args={[1.0, 1.0, 1.0]} />
<meshStandardMaterial
color={appearance.color}
emissive={appearance.emissive || appearance.color}
emissiveIntensity={isHovered ? (appearance.intensity || 0.05) + 0.3 : (appearance.intensity || 0.05)}
roughness={appearance.pattern === 'ore' ? 0.4 : 0.8}
metalness={appearance.pattern === 'ore' ? 0.3 : 0.0}
transparent
opacity={isHovered ? 0.95 : 0.85}
/>
</mesh>
{/* Block label on hover */}
{isHovered && (
<Text
position={[block.x, block.y + 0.8, block.z]}
fontSize={0.3}
color="white"
anchorX="center"
anchorY="middle"
outlineWidth={0.05}
outlineColor="#000000"
>
{block.name.replace('minecraft:', '').replace(/_/g, ' ').toUpperCase()}
</Text>
)}
</group>
);
})}
</group>
))}
</group>