import React, { useRef, useMemo, useEffect, useState } from 'react';
import { Canvas, useFrame, useLoader } from '@react-three/fiber';
import { OrbitControls, Grid, Text, Line } from '@react-three/drei';
import * as THREE from 'three';
import { useTurtleStore } from '../store/turtleStore';
// Texture mapping for Minecraft blocks
const TEXTURE_MAP = {
// Basic blocks
'minecraft:stone': 'stone',
'minecraft:cobblestone': 'cobblestone',
'minecraft:dirt': 'dirt',
'minecraft:grass_block': 'grass_block_side',
'minecraft:sand': 'sand',
'minecraft:red_sand': 'red_sand',
'minecraft:gravel': 'gravel',
'minecraft:bedrock': 'bedrock',
'minecraft:oak_log': 'oak_log',
'minecraft:oak_planks': 'oak_planks',
'minecraft:glass': 'glass',
// Stone variants
'minecraft:granite': 'granite',
'minecraft:diorite': 'diorite',
'minecraft:andesite': 'andesite',
'minecraft:deepslate': 'deepslate',
'minecraft:tuff': 'tuff',
'minecraft:calcite': 'calcite',
'minecraft:dripstone_block': 'dripstone_block',
// Ores (overworld)
'minecraft:coal_ore': 'coal_ore',
'minecraft:iron_ore': 'iron_ore',
'minecraft:gold_ore': 'gold_ore',
'minecraft:diamond_ore': 'diamond_ore',
'minecraft:emerald_ore': 'emerald_ore',
'minecraft:redstone_ore': 'redstone_ore',
'minecraft:lapis_ore': 'lapis_ore',
'minecraft:copper_ore': 'copper_ore',
// Deepslate ores
'minecraft:deepslate_coal_ore': 'deepslate_coal_ore',
'minecraft:deepslate_iron_ore': 'deepslate_iron_ore',
'minecraft:deepslate_gold_ore': 'deepslate_gold_ore',
'minecraft:deepslate_diamond_ore': 'deepslate_diamond_ore',
'minecraft:deepslate_emerald_ore': 'deepslate_emerald_ore',
'minecraft:deepslate_redstone_ore': 'deepslate_redstone_ore',
'minecraft:deepslate_lapis_ore': 'deepslate_lapis_ore',
'minecraft:deepslate_copper_ore': 'deepslate_copper_ore',
// Special blocks
'minecraft:obsidian': 'obsidian',
'minecraft:netherrack': 'netherrack',
'minecraft:soul_sand': 'soul_sand',
'minecraft:glowstone': 'glowstone',
'minecraft:end_stone': 'end_stone',
'minecraft:water': 'water_still',
'minecraft:lava': 'lava_still',
// Building blocks
'minecraft:bricks': 'bricks',
'minecraft:stone_bricks': 'stone_bricks',
'minecraft:mossy_cobblestone': 'mossy_cobblestone',
'minecraft:mossy_stone_bricks': 'mossy_stone_bricks',
'minecraft:prismarine': 'prismarine',
'minecraft:dark_prismarine': 'dark_prismarine',
};
// Function to get texture URL from a Minecraft texture service
function getTextureURL(blockName) {
const textureName = TEXTURE_MAP[blockName] || 'stone';
// Using a public Minecraft texture API
return `https://raw.githubusercontent.com/InventivetalentDev/minecraft-assets/1.20.4/assets/minecraft/textures/block/${textureName}.png`;
}
// Custom hook to load multiple textures
function useMinecraftTextures(blocks) {
const [textures, setTextures] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => {
const textureLoader = new THREE.TextureLoader();
const uniqueBlocks = [...new Set(blocks.map(b => b.name))];
const loadedTextures = {};
let loadedCount = 0;
if (uniqueBlocks.length === 0) {
setLoading(false);
return;
}
uniqueBlocks.forEach(blockName => {
const url = getTextureURL(blockName);
textureLoader.load(
url,
(texture) => {
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
loadedTextures[blockName] = texture;
loadedCount++;
if (loadedCount === uniqueBlocks.length) {
setTextures(loadedTextures);
setLoading(false);
}
},
undefined,
(error) => {
console.warn(`Failed to load texture for ${blockName}, using color fallback`);
loadedCount++;
if (loadedCount === uniqueBlocks.length) {
setTextures(loadedTextures);
setLoading(false);
}
}
);
});
}, [blocks]);
return { textures, loading };
}
// Minecraft-style turtle model
function TurtleModel({ turtle, isSelected, onClick }) {
const groupRef = useRef();
const { position, facing, mode } = turtle;
useFrame((state) => {
if (groupRef.current && isSelected) {
groupRef.current.children[0].position.y = Math.sin(state.clock.elapsedTime * 2) * 0.05;
}
});
if (!position) return null;
// Calculate rotation based on facing (0=North(-Z), 1=East(+X), 2=South(+Z), 3=West(-X))
// 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' :
mode === 'returning' ? '#f59e0b' :
'#9ca3af';
return (