feat: Enhance block appearance handling with detailed color and texture info, and improve block rendering performance
This commit is contained in:
@@ -18,7 +18,8 @@ function TurtleModel({ turtle, isSelected, onClick }) {
|
|||||||
if (!position) return null;
|
if (!position) return null;
|
||||||
|
|
||||||
// Calculate rotation based on facing (0=North(-Z), 1=East(+X), 2=South(+Z), 3=West(-X))
|
// 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' :
|
const color = mode === 'mining' ? '#4ade80' :
|
||||||
mode === 'exploring' ? '#60a5fa' :
|
mode === 'exploring' ? '#60a5fa' :
|
||||||
@@ -134,69 +135,105 @@ function PathTrail({ turtle }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get color for block type
|
// Get color and texture info for block type
|
||||||
function getBlockColor(blockName) {
|
function getBlockAppearance(blockName) {
|
||||||
if (!blockName) return '#888';
|
if (!blockName) return { color: '#888', pattern: 'solid' };
|
||||||
|
|
||||||
const name = blockName.toLowerCase();
|
const name = blockName.toLowerCase();
|
||||||
|
|
||||||
// Ores
|
// Ores - bright colors with sparkle
|
||||||
if (name.includes('diamond')) return '#00ffff';
|
if (name.includes('diamond')) return { color: '#00ffff', pattern: 'ore', emissive: '#00ffff', intensity: 0.3 };
|
||||||
if (name.includes('emerald')) return '#00ff00';
|
if (name.includes('emerald')) return { color: '#00ff00', pattern: 'ore', emissive: '#00ff00', intensity: 0.3 };
|
||||||
if (name.includes('gold')) return '#ffd700';
|
if (name.includes('gold')) return { color: '#ffd700', pattern: 'ore', emissive: '#ffd700', intensity: 0.2 };
|
||||||
if (name.includes('iron')) return '#d4d4d4';
|
if (name.includes('iron')) return { color: '#d4d4d4', pattern: 'ore' };
|
||||||
if (name.includes('coal')) return '#1a1a1a';
|
if (name.includes('coal')) return { color: '#1a1a1a', pattern: 'ore' };
|
||||||
if (name.includes('redstone')) return '#ff0000';
|
if (name.includes('redstone')) return { color: '#ff0000', pattern: 'ore', emissive: '#ff0000', intensity: 0.2 };
|
||||||
if (name.includes('lapis')) return '#0000ff';
|
if (name.includes('lapis')) return { color: '#1e40af', pattern: 'ore' };
|
||||||
if (name.includes('copper')) return '#ff8c00';
|
if (name.includes('copper')) return { color: '#ff8c00', pattern: 'ore' };
|
||||||
|
|
||||||
// Common blocks
|
// Common blocks - textured
|
||||||
if (name.includes('stone')) return '#7f7f7f';
|
if (name.includes('stone') && !name.includes('cobble')) return { color: '#7f7f7f', pattern: 'stone' };
|
||||||
if (name.includes('dirt')) return '#8b4513';
|
if (name.includes('cobblestone')) return { color: '#808080', pattern: 'cobble' };
|
||||||
if (name.includes('grass')) return '#228b22';
|
if (name.includes('dirt')) return { color: '#8b4513', pattern: 'dirt' };
|
||||||
if (name.includes('sand')) return '#f4a460';
|
if (name.includes('grass')) return { color: '#228b22', pattern: 'grass' };
|
||||||
if (name.includes('gravel')) return '#808080';
|
if (name.includes('sand')) return { color: '#f4a460', pattern: 'sand' };
|
||||||
if (name.includes('bedrock')) return '#222';
|
if (name.includes('gravel')) return { color: '#808080', pattern: 'gravel' };
|
||||||
if (name.includes('obsidian')) return '#1a0033';
|
if (name.includes('bedrock')) return { color: '#222', pattern: 'solid' };
|
||||||
if (name.includes('netherrack')) return '#8b0000';
|
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
|
// WorldBlocks component to render discovered blocks
|
||||||
function WorldBlocks({ blocks }) {
|
function WorldBlocks({ blocks }) {
|
||||||
const meshes = useMemo(() => {
|
const [hoveredBlock, setHoveredBlock] = React.useState(null);
|
||||||
const instances = new Map();
|
|
||||||
|
// Group blocks by appearance for better performance
|
||||||
|
const blockGroups = useMemo(() => {
|
||||||
|
const groups = new Map();
|
||||||
|
|
||||||
blocks.forEach(block => {
|
blocks.forEach(block => {
|
||||||
const color = getBlockColor(block.name);
|
const appearance = getBlockAppearance(block.name);
|
||||||
if (!instances.has(color)) {
|
const key = `${appearance.color}-${appearance.pattern}`;
|
||||||
instances.set(color, []);
|
|
||||||
|
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]);
|
}, [blocks]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group>
|
<group>
|
||||||
{Array.from(meshes.entries()).map(([color, blockList]) => (
|
{blockGroups.map((group, groupIdx) => (
|
||||||
<group key={color}>
|
<group key={groupIdx}>
|
||||||
{blockList.map((block, idx) => (
|
{group.blocks.map((block) => {
|
||||||
<mesh
|
const appearance = group.appearance;
|
||||||
key={`${block.x},${block.y},${block.z}`}
|
const blockKey = `${block.x},${block.y},${block.z}`;
|
||||||
position={[block.x, block.y, block.z]}
|
const isHovered = hoveredBlock === blockKey;
|
||||||
>
|
|
||||||
<boxGeometry args={[0.9, 0.9, 0.9]} />
|
return (
|
||||||
<meshStandardMaterial
|
<group key={blockKey}>
|
||||||
color={color}
|
<mesh
|
||||||
transparent
|
position={[block.x, block.y, block.z]}
|
||||||
opacity={0.6}
|
onPointerOver={(e) => {
|
||||||
roughness={0.8}
|
e.stopPropagation();
|
||||||
/>
|
setHoveredBlock(blockKey);
|
||||||
</mesh>
|
}}
|
||||||
))}
|
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>
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
Reference in New Issue
Block a user