<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML5 Minecraft 极速离线版(密码验证)</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { overflow: hidden; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; touch-action: none; }
        #gameCanvas { width: 100vw; height: 100vh; display: block; }
        #hud { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; gap: 8px; z-index: 100; }
        .hotbar-slot { width: 48px; height: 48px; border: 2px solid #666; background: rgba(0,0,0,0.5); border-radius: 4px; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; }
        .hotbar-slot.active { border-color: #fff; box-shadow: 0 0 10px #fff; }
        #crosshair { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 16px; height: 16px; border: 1px solid #fff; z-index: 100; }
        #crosshair::before { content: ''; position: absolute; top: 50%; left: -5px; right: -5px; height: 1px; background: #fff; }
        #crosshair::after { content: ''; position: absolute; left: 50%; top: -5px; bottom: -5px; width: 1px; background: #fff; }
        #loading { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: #111; display: flex; flex-direction: column; justify-content: center; align-items: center; color: #fff; z-index: 999; }
        .progress-bar { width: 300px; height: 20px; border: 1px solid #666; margin-top: 20px; border-radius: 10px; overflow: hidden; }
        .progress { height: 100%; background: #4CAF50; width: 0%; transition: width 0.3s ease; }
        #debug { position: fixed; top: 10px; left: 10px; color: #fff; background: rgba(0,0,0,0.5); padding: 5px; font-size: 12px; z-index: 100; }
        /* 移动端虚拟摇杆 */
        #joystick { display: none; position: fixed; bottom: 80px; left: 20px; width: 80px; height: 80px; border-radius: 50%; border: 2px solid rgba(255,255,255,0.5); background: rgba(0,0,0,0.3); z-index: 100; }
        #joystick-thumb { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 40px; height: 40px; border-radius: 50%; background: rgba(255,255,255,0.7); }
        #action-buttons { display: none; position: fixed; bottom: 80px; right: 20px; display: flex; gap: 15px; z-index: 100; }
        .action-btn { width: 60px; height: 60px; border-radius: 50%; background: rgba(0,0,0,0.3); border: 2px solid rgba(255,255,255,0.5); color: white; font-size: 24px; display: flex; align-items: center; justify-content: center; }
        /* 密码验证界面 */
        #password-screen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: #111; display: flex; flex-direction: column; justify-content: center; align-items: center; color: #fff; z-index: 1000; }
        #password-input { width: 280px; height: 50px; padding: 0 15px; font-size: 18px; border: 2px solid #666; border-radius: 8px; background: rgba(255,255,255,0.1); color: #fff; margin: 20px 0; outline: none; text-align: center; }
        #password-input:focus { border-color: #4CAF50; box-shadow: 0 0 10px rgba(76, 175, 80, 0.5); }
        #submit-password { width: 150px; height: 45px; font-size: 18px; border: none; border-radius: 8px; background: #4CAF50; color: white; cursor: pointer; transition: background 0.3s ease; }
        #submit-password:hover { background: #45a049; }
        #password-error { color: #ff4444; margin-top: 15px; font-size: 14px; height: 20px; }
        @media (max-width: 768px) {
            #joystick, #action-buttons { display: flex; }
            .hotbar-slot { width: 40px; height: 40px; }
            #password-input { width: 240px; height: 45px; font-size: 16px; }
            #submit-password { width: 130px; height: 40px; font-size: 16px; }
        }
    </style>
</head>
<body>
    <!-- 密码验证界面(新增) -->
    <div id="password-screen">
        <h1>HTML5 Minecraft 极速版</h1>
        <p>请输入访问密码</p>
        <input type="password" id="password-input" placeholder="输入密码">
        <button id="submit-password">确认进入</button>
        <div id="password-error"></div>
    </div>

    <div id="loading" style="display: none;">
        <h1>HTML5 Minecraft 极速版</h1>
        <p>加载中... 请稍候</p>
        <div class="progress-bar">
            <div class="progress" id="progress"></div>
        </div>
    </div>

    <canvas id="gameCanvas"></canvas>
    <div id="crosshair"></div>
    <div id="hud"></div>
    <div id="debug">位置: (0,0,0) | 方块: 草地 | 帧率: 0 | 延迟: 0ms</div>
    <!-- 移动端虚拟摇杆 -->
    <div id="joystick">
        <div id="joystick-thumb"></div>
    </div>
    <div id="action-buttons">
        <div class="action-btn" id="break-btn">✕</div>
        <div class="action-btn" id="place-btn">○</div>
        <div class="action-btn" id="jump-btn">↑</div>
    </div>

    <script>
        // 简化版Babylon.js核心API(性能优化,移除冗余)
        const BABYLON = (() => {
            const API = {
                Vector3: class {
                    constructor(x=0, y=0, z=0) { this.x=x; this.y=y; this.z=z; }
                    add(v) { this.x+=v.x; this.y+=v.y; this.z+=v.z; return this; }
                    subtract(v) { this.x-=v.x; this.y-=v.y; this.z-=v.z; return this; }
                    multiply(n) { this.x*=n; this.y*=n; this.z*=n; return this; }
                    dot(v) { return this.x*v.x + this.y*v.y + this.z*v.z; }
                    normalize() { const l = Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); l!==0 && (this.x/=l, this.y/=l, this.z/=l); return this; }
                    clone() { return new API.Vector3(this.x, this.y, this.z); }
                    set(x,y,z) { this.x=x; this.y=y; this.z=z; return this; }
                },
                Color3: class { constructor(r=0, g=0, b=0) { this.r=r; this.g=g; this.b=b; } },
                Matrix: class {
                    constructor() { this.m = new Float32Array(16); }
                    static Translation(x,y,z, mat) {
                        mat = mat || new API.Matrix();
                        mat.m.set([1,0,0,x, 0,1,0,y, 0,0,1,z, 0,0,0,1]);
                        return mat;
                    }
                    static Multiply(a,b, out) {
                        out = out || new API.Matrix();
                        const m1 = a.m, m2 = b.m;
                        out.m[0] = m1[0]*m2[0] + m1[1]*m2[4] + m1[2]*m2[8] + m1[3]*m2[12];
                        out.m[1] = m1[0]*m2[1] + m1[1]*m2[5] + m1[2]*m2[9] + m1[3]*m2[13];
                        out.m[2] = m1[0]*m2[2] + m1[1]*m2[6] + m1[2]*m2[10] + m1[3]*m2[14];
                        out.m[3] = m1[0]*m2[3] + m1[1]*m2[7] + m1[2]*m2[11] + m1[3]*m2[15];
                        out.m[4] = m1[4]*m2[0] + m1[5]*m2[4] + m1[6]*m2[8] + m1[7]*m2[12];
                        out.m[5] = m1[4]*m2[1] + m1[5]*m2[5] + m1[6]*m2[9] + m1[7]*m2[13];
                        out.m[6] = m1[4]*m2[2] + m1[5]*m2[6] + m1[6]*m2[10] + m1[7]*m2[14];
                        out.m[7] = m1[4]*m2[3] + m1[5]*m2[7] + m1[6]*m2[11] + m1[7]*m2[15];
                        out.m[8] = m1[8]*m2[0] + m1[9]*m2[4] + m1[10]*m2[8] + m1[11]*m2[12];
                        out.m[9] = m1[8]*m2[1] + m1[9]*m2[5] + m1[10]*m2[9] + m1[11]*m2[13];
                        out.m[10] = m1[8]*m2[2] + m1[9]*m2[6] + m1[10]*m2[10] + m1[11]*m2[14];
                        out.m[11] = m1[8]*m2[3] + m1[9]*m2[7] + m1[10]*m2[11] + m1[11]*m2[15];
                        out.m[12] = m1[12]*m2[0] + m1[13]*m2[4] + m1[14]*m2[8] + m1[15]*m2[12];
                        out.m[13] = m1[12]*m2[1] + m1[13]*m2[5] + m1[14]*m2[9] + m1[15]*m2[13];
                        out.m[14] = m1[12]*m2[2] + m1[13]*m2[6] + m1[14]*m2[10] + m1[15]*m2[14];
                        out.m[15] = m1[12]*m2[3] + m1[13]*m2[7] + m1[14]*m2[11] + m1[15]*m2[15];
                        return out;
                    }
                },
                Frustum: class {
                    constructor() { this.planes = new Array(6); }
                    static FromMatrix(frustum, matrix) {
                        const m = matrix.m;
                        frustum.planes[0] = { a: m[3]-m[0], b: m[7]-m[1], c: m[11]-m[2], d: m[15]-m[3] };
                        frustum.planes[1] = { a: m[3]+m[0], b: m[7]+m[1], c: m[11]+m[2], d: m[15]+m[3] };
                        frustum.planes[2] = { a: m[3]+m[4], b: m[7]+m[5], c: m[11]+m[6], d: m[15]+m[7] };
                        frustum.planes[3] = { a: m[3]-m[4], b: m[7]-m[5], c: m[11]-m[6], d: m[15]-m[7] };
                        frustum.planes[4] = { a: m[3]-m[8], b: m[7]-m[9], c: m[11]-m[10], d: m[15]-m[11] };
                        frustum.planes[5] = { a: m[3]+m[8], b: m[7]+m[9], c: m[11]+m[10], d: m[15]+m[11] };
                        frustum.planes.forEach(p => {
                            const len = Math.sqrt(p.a*p.a + p.b*p.b + p.c*p.c);
                            len!==0 && (p.a/=len, p.b/=len, p.c/=len, p.d/=len);
                        });
                        return frustum;
                    }
                    intersectsBoundingBox(bbox) {
                        for (const p of this.planes) {
                            const max = Math.max(
                                bbox.min.x*p.a, bbox.max.x*p.a,
                                bbox.min.y*p.b, bbox.max.y*p.b,
                                bbox.min.z*p.c, bbox.max.z*p.c
                            );
                            if (max + p.d < 0) return false;
                        }
                        return true;
                    }
                },
                BoundingBox: class {
                    constructor(min, max) { this.min = min; this.max = max; }
                    set(min, max) { this.min=min; this.max=max; return this; }
                },
                FreeCamera: class {
                    constructor(name, pos, scene) {
                        this.name = name;
                        this.position = pos;
                        this.scene = scene;
                        this.speed = 0.35;
                        this.angularSpeed = 0.0018;
                        this.minZ = 0.1;
                        this.maxZ = 180;
                        this.checkCollisions = true;
                        this.ellipsoid = new API.Vector3(0.5, 1.5, 0.5);
                        this.canvas = null;
                        this.rotation = new API.Vector3(0, 0, 0);
                    }
                    attachControl(canvas) { this.canvas = canvas; }
                    getProjectionMatrix(out) {
                        out = out || new API.Matrix();
                        const fov = Math.PI/4.5, aspect = this.canvas.width/this.canvas.height, near = 0.1, far = 180;
                        const tanHalfFov = Math.tan(fov/2);
                        out.m[0] = 1/(aspect*tanHalfFov);
                        out.m[1] = 0;
                        out.m[2] = 0;
                        out.m[3] = 0;
                        out.m[4] = 0;
                        out.m[5] = 1/tanHalfFov;
                        out.m[6] = 0;
                        out.m[7] = 0;
                        out.m[8] = 0;
                        out.m[9] = 0;
                        out.m[10] = -(far+near)/(far-near);
                        out.m[11] = -2*far*near/(far-near);
                        out.m[12] = 0;
                        out.m[13] = 0;
                        out.m[14] = -1;
                        out.m[15] = 0;
                        return out;
                    }
                    getViewMatrix(out) {
                        out = out || new API.Matrix();
                        const pos = this.position;
                        const rot = this.rotation;
                        const cosX = Math.cos(rot.x), sinX = Math.sin(rot.x);
                        const cosY = Math.cos(rot.y), sinY = Math.sin(rot.y);
                        const cosZ = Math.cos(rot.z), sinZ = Math.sin(rot.z);
                        out.m[0] = cosY*cosZ;
                        out.m[1] = sinX*sinY*cosZ - cosX*sinZ;
                        out.m[2] = cosX*sinY*cosZ + sinX*sinZ;
                        out.m[3] = -pos.x*out.m[0] - pos.y*out.m[1] - pos.z*out.m[2];
                        out.m[4] = cosY*sinZ;
                        out.m[5] = sinX*sinY*sinZ + cosX*cosZ;
                        out.m[6] = cosX*sinY*sinZ - sinX*cosZ;
                        out.m[7] = -pos.x*out.m[4] - pos.y*out.m[5] - pos.z*out.m[6];
                        out.m[8] = -sinY;
                        out.m[9] = sinX*cosY;
                        out.m[10] = cosX*cosY;
                        out.m[11] = -pos.x*out.m[8] - pos.y*out.m[9] - pos.z*out.m[10];
                        out.m[12] = 0; out.m[13] = 0; out.m[14] = 0; out.m[15] = 1;
                        return out;
                    }
                },
                HemisphericLight: class { constructor(name, dir, scene) { this.name=name; this.direction=dir; this.intensity=0.5; } },
                DirectionalLight: class {
                    constructor(name, dir, scene) {
                        this.name=name; this.direction=dir; this.intensity=0.7; this.position=dir.clone().multiply(150);
                        this.shadowEnabled = false;
                    }
                },
                InstancedMesh: class {
                    constructor(name, mat, scene) {
                        this.name = name;
                        this.material = mat;
                        this.scene = scene;
                        this.instanceCount = 0;
                        this.matrices = new Array(20000);
                        this.boundingBox = new API.BoundingBox(new API.Vector3(-512,0,-512), new API.Vector3(512,256,512));
                        this.isVisible = true;
                        scene.meshes.push(this);
                    }
                    setMatrixAt(index, matrix) {
                        this.matrices[index] = matrix;
                        index >= this.instanceCount && (this.instanceCount = index + 1);
                    }
                    refreshBoundingInfo() {}
                    getBoundingInfo() { return { boundingBox: this.boundingBox }; }
                },
                StandardMaterial: class {
                    constructor(name, scene) {
                        this.name = name;
                        this.diffuseColor = new API.Color3(1,1,1);
                        this.roughness = 0.8;
                        this.metalness = 0.1;
                        this.alpha = 1;
                    }
                },
                AmmoJSPlugin: class { constructor() {} },
                Scene: class {
                    constructor(engine) {
                        this.engine = engine;
                        this.clearColor = new API.Color3(0.6, 0.8, 1.0);
                        this.gravity = new API.Vector3(0, -9.8, 0);
                        this.meshes = [];
                        this.lights = [];
                    }
                    enablePhysics() {}
                    render() {}
                },
                Engine: class {
                    constructor(canvas) {
                        this.canvas = canvas;
                        this.renderWidth = canvas.width;
                        this.renderHeight = canvas.height;
                        this.loop = null;
                        this.fps = 0;
                        this.frameCount = 0;
                        this.lastFpsUpdate = performance.now();
                        this.lastFrameTime = performance.now();
                        this.inputDelay = 0;
                    }
                    runRenderLoop(cb) {
                        this.loop = requestAnimationFrame.bind(window, function loop() {
                            const now = performance.now();
                            this.frameCount++;
                            this.inputDelay = now - this.lastFrameTime;
                            if (now - this.lastFpsUpdate >= 1000) {
                                this.fps = this.frameCount;
                                this.frameCount = 0;
                                this.lastFpsUpdate = now;
                            }
                            cb(now - this.lastFrameTime);
                            this.lastFrameTime = now;
                            this.loop = requestAnimationFrame(loop.bind(this));
                        }.bind(this));
                        this.loop();
                    }
                    resize() {
                        this.renderWidth = this.canvas.width = window.innerWidth;
                        this.renderHeight = this.canvas.height = window.innerHeight;
                    }
                    stopRenderLoop() { cancelAnimationFrame(this.loop); }
                },
                UnrealBloomPass: class { constructor() { this.isEnabled = false; } },
                EffectComposer: class {
                    constructor(engine) { this.engine = engine; this.passes = []; }
                    addPass() {}
                    render() {}
                },
                RenderPass: class { constructor() {} }
            };
            // 优化版八叉树
            API.Octree = class {
                constructor(min, max, depth = 0) {
                    this.min = min;
                    this.max = max;
                    this.depth = depth;
                    this.children = null;
                    this.blocks = [];
                    this.MAX_DEPTH = 4;
                    this.MAX_BLOCKS = 12;
                }
                insert(block) {
                    if (this.children) {
                        const childIdx = this.getChildIndex(block.position);
                        this.children[childIdx] && this.children[childIdx].insert(block);
                        return;
                    }
                    this.blocks.push(block);
                    if (this.depth < this.MAX_DEPTH && this.blocks.length > this.MAX_BLOCKS) {
                        this.split();
                    }
                }
                split() {
                    const midX = (this.min.x + this.max.x) / 2;
                    const midY = (this.min.y + this.max.y) / 2;
                    const midZ = (this.min.z + this.max.z) / 2;
                    this.children = [
                        new API.Octree(this.min.clone(), new API.Vector3(midX, midY, midZ), this.depth + 1),
                        new API.Octree(new API.Vector3(midX, this.min.y, this.min.z), new API.Vector3(this.max.x, midY, midZ), this.depth + 1),
                        new API.Octree(new API.Vector3(this.min.x, midY, this.min.z), new API.Vector3(midX, this.max.y, midZ), this.depth + 1),
                        new API.Octree(new API.Vector3(midX, midY, this.min.z), new API.Vector3(this.max.x, this.max.y, midZ), this.depth + 1),
                        new API.Octree(new API.Vector3(this.min.x, this.min.y, midZ), new API.Vector3(midX, midY, this.max.z), this.depth + 1),
                        new API.Octree(new API.Vector3(midX, this.min.y, midZ), new API.Vector3(this.max.x, midY, this.max.z), this.depth + 1),
                        new API.Octree(new API.Vector3(this.min.x, midY, midZ), new API.Vector3(midX, this.max.y, this.max.z), this.depth + 1),
                        new API.Octree(new API.Vector3(midX, midY, midZ), new API.Vector3(this.max.x, this.max.y, this.max.z), this.depth + 1)
                    ];
                    this.blocks.forEach(block => this.insert(block));
                    this.blocks = [];
                }
                query(min, max, result = []) {
                    if (!this.intersects(min, max)) return result;
                    if (this.children) {
                        this.children.forEach(child => child.query(min, max, result));
                    } else {
                        result.push(...this.blocks);
                    }
                    return result;
                }
                intersects(min, max) {
                    return this.min.x <= max.x && this.max.x >= min.x &&
                           this.min.y <= max.y && this.max.y >= min.y &&
                           this.min.z <= max.z && this.max.z >= min.z;
                }
                getChildIndex(pos) {
                    const midX = (this.min.x + this.max.x) / 2;
                    const midY = (this.min.y + this.max.y) / 2;
                    const midZ = (this.min.z + this.max.z) / 2;
                    let idx = 0;
                    pos.x >= midX && (idx |= 1);
                    pos.y >= midY && (idx |= 2);
                    pos.z >= midZ && (idx |= 4);
                    return idx;
                }
            };
            return API;
        })();

        // 全局核心变量
        let engine, scene, camera;
        let world = {
            chunks: new Map(),
            loadedChunks: new Set(),
            chunkSize: 16,
            renderDistance: 2,
            maxRenderDistance: 3
        };
        let player = {
            position: new BABYLON.Vector3(0, 64, 0),
            velocity: new BABYLON.Vector3(0, 0, 0),
            onGround: false,
            moveDir: new BABYLON.Vector3(0, 0, 0)
        };
        let currentBlockType = 0;
        let isMouseLocked = false;
        let keys = new Set();
        const BLOCK_TYPES = [
            { name: 'grass', color: new BABYLON.Color3(0.3, 0.7, 0.2), roughness: 0.8, metalness: 0.1 },
            { name: 'dirt', color: new BABYLON.Color3(0.6, 0.4, 0.2), roughness: 0.9, metalness: 0.05 },
            { name: 'stone', color: new BABYLON.Color3(0.5, 0.5, 0.5), roughness: 0.85, metalness: 0.1 },
            { name: 'wood', color: new BABYLON.Color3(0.8, 0.5, 0.2), roughness: 0.7, metalness: 0.05 },
            { name: 'leaves', color: new BABYLON.Color3(0.2, 0.6, 0.1), roughness: 0.9, metalness: 0.05, alpha: 0.8 }
        ];

        // 性能优化池
        const materialPool = new Map();
        const instancedMeshes = new Map();
        const vectorPool = [new BABYLON.Vector3(), new BABYLON.Vector3(), new BABYLON.Vector3(), new BABYLON.Vector3(), new BABYLON.Vector3()];
        const matrixPool = [new BABYLON.Matrix(), new BABYLON.Matrix(), new BABYLON.Matrix()];
        const frustum = new BABYLON.Frustum();
        let worldOctree;
        let chunkWorker;
        let chunkQueue = [];
        let isProcessingChunkQueue = false;

        // 移动端控制变量
        let joystickActive = false;
        let joystickStart = new BABYLON.Vector3();
        let touchIds = new Map();

        // 密码验证核心逻辑(新增)
        const CORRECT_PASSWORD = '123456';
        const passwordScreen = document.getElementById('password-screen');
        const passwordInput = document.getElementById('password-input');
        const submitPasswordBtn = document.getElementById('submit-password');
        const passwordError = document.getElementById('password-error');
        const loadingScreen = document.getElementById('loading');

        // 密码提交事件(新增)
        submitPasswordBtn.addEventListener('click', verifyPassword);
        passwordInput.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') verifyPassword();
        });

        // 密码验证函数(新增)
        function verifyPassword() {
            const input = passwordInput.value.trim();
            if (input === CORRECT_PASSWORD) {
                // 密码正确,隐藏密码界面,显示加载界面并启动游戏
                passwordScreen.style.opacity = 0;
                setTimeout(() => {
                    passwordScreen.style.display = 'none';
                    loadingScreen.style.display = 'flex';
                    initGame(); // 密码验证通过后才初始化游戏
                }, 300);
            } else {
                // 密码错误,显示提示
                passwordError.textContent = '密码错误,请输入正确密码(123456)';
                passwordInput.value = '';
                passwordInput.focus();
                // 3秒后清除错误提示
                setTimeout(() => passwordError.textContent = '', 3000);
            }
        }

        // 加载进度更新
        function updateProgress(percent) {
            const progressEl = document.getElementById('progress');
            progressEl.style.width = `${percent}%`;
            document.querySelector('#loading p').textContent = `加载中... ${percent}%`;
        }

        // 初始化游戏(原逻辑不变,仅修改启动时机)
        async function initGame() {
            const initStart = performance.now();
            updateProgress(10);
            
            // 1. 初始化画布和引擎
            const canvas = document.getElementById('gameCanvas');
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            engine = new BABYLON.Engine(canvas);
            
            // 2. 初始化场景
            scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0.6, 0.8, 1.0);
            scene.gravity = new BABYLON.Vector3(0, -9.8, 0);
            updateProgress(25);

            // 3. 初始化优化组件
            initOptimizationComponents();
            updateProgress(40);

            // 4. 创建相机和光源
            createCamera();
            createLights();
            updateProgress(55);

            // 5. 启动Web Worker
            startChunkWorker();
            updateProgress(65);

            // 6. 初始化世界
            await initWorld();
            updateProgress(85);

            // 7. 初始化UI和事件
            setupUI();
            registerEvents();
            updateProgress(95);

            // 8. 异步初始化离线存储
            initOfflineStorage().catch(() => {});

            // 启动完成
            const initDuration = Math.round(performance.now() - initStart);
            updateProgress(100);
            setTimeout(() => {
                document.getElementById('loading').style.opacity = 0;
                setTimeout(() => document.getElementById('loading').style.display = 'none', 200);
            }, 100);

            // 渲染循环
            engine.runRenderLoop((deltaTime) => {
                scene.render();
                updatePlayerMovement(deltaTime);
                updatePlayerPosition();
                processChunkQueue();
                updateFrustumCulling();
                updateDebugInfo();
                adjustRenderDistance();
            });

            // 窗口resize处理
            window.addEventListener('resize', () => engine.resize());

            // 启动后提升渲染距离
            setTimeout(() => {
                if (engine.fps >= 45) world.renderDistance = 3;
            }, 2000);
        }

        // 初始化优化组件
        function initOptimizationComponents() {
            // 材质池
            BLOCK_TYPES.forEach((blockType, index) => {
                const material = new BABYLON.StandardMaterial(`blockMat_${index}`, scene);
                material.diffuseColor = blockType.color;
                material.roughness = blockType.roughness;
                material.metalness = blockType.metalness;
                material.alpha = blockType.alpha || 1;
                materialPool.set(index, material);
            });

            // 实例化网格池
            BLOCK_TYPES.forEach((_, index) => {
                const material = materialPool.get(index);
                const instancedMesh = new BABYLON.InstancedMesh(`blockInst_${index}`, material, scene);
                instancedMeshes.set(index, { mesh: instancedMesh, count: 0 });
            });

            // 八叉树
            worldOctree = new BABYLON.Octree(new BABYLON.Vector3(-512, 0, -512), new BABYLON.Vector3(512, 256, 512));
        }

        // 启动Web Worker
        function startChunkWorker() {
            const workerCode = `
                const PerlinNoise = {
                    perm: new Uint8Array([151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,44,109,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]),
                    fade(t) { return t * t * t * (t * (t * 6 - 15) + 10); },
                    lerp(a, b, t) { return a + t * (b - a); },
                    grad(hash, x, y, z) {
                        const h = hash & 15;
                        const u = h < 8 ? x : y;
                        const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
                        return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
                    },
                    noise3d(x, y, z) {
                        const p = new Uint8Array(512);
                        for (let i = 0; i < 512; i++) p[i] = this.perm[i & 255];
                        const X = Math.floor(x) & 255;
                        const Y = Math.floor(y) & 255;
                        const Z = Math.floor(z) & 255;
                        x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
                        const u = this.fade(x); const v = this.fade(y); const w = this.fade(z);
                        const A = p[X] + Y; const AA = p[A] + Z; const AB = p[A + 1] + Z;
                        const B = p[X + 1] + Y; const BA = p[B] + Z; const BB = p[B + 1] + Z;
                        return this.lerp(w,
                            this.lerp(v,
                                this.lerp(u, this.grad(p[AA], x, y, z), this.grad(p[BA], x - 1, y, z)),
                                this.lerp(u, this.grad(p[AB], x, y - 1, z), this.grad(p[BB], x - 1, y - 1, z))
                            ),
                            this.lerp(v,
                                this.lerp(u, this.grad(p[AA + 1], x, y, z - 1), this.grad(p[BA + 1], x - 1, y, z - 1)),
                                this.lerp(u, this.grad(p[AB + 1], x, y - 1, z - 1), this.grad(p[BB + 1], x - 1, y - 1, z - 1))
                            )
                        );
                    }
                };

                function generateChunkBlocks(chunkX, chunkZ, chunkSize) {
                    const blocks = [];
                    const noiseScale = 0.018;
                    const octaves = 3;
                    const persistence = 0.5;
                    const lacunarity = 2.0;

                    for (let x = 0; x < chunkSize; x++) {
                        for (let z = 0; z < chunkSize; z++) {
                            let height = 0;
                            let amplitude = 1;
                            let frequency = 1;
                            let noiseValue = 0;

                            for (let o = 0; o < octaves; o++) {
                                const worldX = chunkX * chunkSize + x;
                                const worldZ = chunkZ * chunkSize + z;
                                noiseValue += PerlinNoise.noise3d(worldX * noiseScale * frequency, 0, worldZ * noiseScale * frequency) * amplitude;
                                amplitude *= persistence;
                                frequency *= lacunarity;
                            }
                            height = Math.floor(64 + noiseValue * 18);

                            for (let y = 0; y < height; y++) {
                                const blockType = y === height - 1 ? 0 : (y < height - 4 ? 2 : 1);
                                const caveNoise = PerlinNoise.noise3d(
                                    (chunkX * chunkSize + x) * 0.09,
                                    y * 0.09,
                                    (chunkZ * chunkSize + z) * 0.09
                                );
                                if (caveNoise > 0.22 && y > 10) continue;
                                blocks.push({ x: chunkX * chunkSize + x, y, z: chunkZ * chunkSize + z, type: blockType });
                            }

                            if (Math.random() < 0.015 && height > 65) {
                                const treeX = chunkX * chunkSize + x;
                                const treeZ = chunkZ * chunkSize + z;
                                const treeY = height;
                                for (let y = 0; y < 3; y++) blocks.push({ x: treeX, y: treeY + y, z: treeZ, type: 3 });
                                for (let dx = -1; dx <= 1; dx++) {
                                    for (let dz = -1; dz <= 1; dz++) {
                                        for (let dy = 0; dy <= 2; dy++) {
                                            if (Math.abs(dx) + Math.abs(dz) + Math.abs(dy) < 3) {
                                                blocks.push({ x: treeX + dx, y: treeY + 2 + dy, z: treeZ + dz, type: 4 });
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    return blocks;
                }

                self.onmessage = (e) => {
                    const { chunkX, chunkZ, chunkSize } = e.data;
                    const blocks = generateChunkBlocks(chunkX, chunkZ, chunkSize);
                    self.postMessage({ chunkX, chunkZ, blocks });
                };
            `;

            const blob = new Blob([workerCode], { type: 'application/javascript' });
            chunkWorker = new Worker(URL.createObjectURL(blob));

            chunkWorker.onmessage = (e) => {
                const { chunkX, chunkZ, blocks } = e.data;
                const chunkKey = `${chunkX},${chunkZ}`;
                if (world.chunks.has(chunkKey)) return;

                world.chunks.set(chunkKey, blocks);
                spawnChunkBlocks(chunkX, chunkZ, blocks);
                world.loadedChunks.add(chunkKey);
                chunkQueue = chunkQueue.filter(item => item.key !== chunkKey);
            };
        }

        // 添加区块到队列
        function addToChunkQueue(chunkX, chunkZ) {
            const chunkKey = `${chunkX},${chunkZ}`;
            if (world.chunks.has(chunkKey) || chunkQueue.some(item => item.key === chunkKey)) return;

            const playerChunkX = Math.floor(player.position.x / world.chunkSize);
            const playerChunkZ = Math.floor(player.position.z / world.chunkSize);
            const distance = Math.sqrt(Math.pow(chunkX - playerChunkX, 2) + Math.pow(chunkZ - playerChunkZ, 2));

            chunkQueue.push({ chunkX, chunkZ, key: chunkKey, distance });
            chunkQueue.sort((a, b) => a.distance - b.distance);
        }

        // 处理区块队列
        function processChunkQueue() {
            if (isProcessingChunkQueue || chunkQueue.length === 0 || !chunkWorker) return;

            isProcessingChunkQueue = true;
            const { chunkX, chunkZ } = chunkQueue[0];
            chunkWorker.postMessage({ chunkX, chunkZ, chunkSize: world.chunkSize });

            setTimeout(() => {
                isProcessingChunkQueue = false;
            }, 100);
        }

        // 生成区块方块
        function spawnChunkBlocks(chunkX, chunkZ, blocks) {
            const typeGroups = new Map();
            blocks.forEach(block => {
                if (!typeGroups.has(block.type)) typeGroups.set(block.type, []);
                typeGroups.get(block.type).push(block);
            });

            const matrix = matrixPool[0];
            typeGroups.forEach((blocksOfType, type) => {
                const { mesh, count } = instancedMeshes.get(type);
                let batchCount = 0;

                blocksOfType.forEach((block, idx) => {
                    BABYLON.Matrix.Translation(block.x, block.y, block.z, matrix);
                    mesh.setMatrixAt(count + idx, matrix);
                    batchCount++;

                    worldOctree.insert({
                        position: new BABYLON.Vector3(block.x, block.y, block.z),
                        size: 1,
                        blockData: block
                    });
                });

                if (batchCount >= 100) {
                    mesh.refreshBoundingInfo();
                    batchCount = 0;
                }

                instancedMeshes.set(type, { mesh, count: count + blocksOfType.length });
            });
        }

        // 初始化世界
        function initWorld() {
            return new Promise(resolve => {
                const startChunkX = Math.floor(player.position.x / world.chunkSize);
                const startChunkZ = Math.floor(player.position.z / world.chunkSize);

                generateCenterChunk(startChunkX, startChunkZ);

                for (let x = -world.renderDistance; x <= world.renderDistance; x++) {
                    for (let z = -world.renderDistance; z <= world.renderDistance; z++) {
                        if (x === 0 && z === 0) continue;
                        addToChunkQueue(startChunkX + x, startChunkZ + z);
                    }
                }

                resolve();
            });
        }

        // 生成中心区块
        function generateCenterChunk(chunkX, chunkZ) {
            const chunkKey = `${chunkX},${chunkZ}`;
            const blocks = [];
            const chunkSize = world.chunkSize;

            for (let x = 0; x < chunkSize; x++) {
                for (let z = 0; z < chunkSize; z++) {
                    const worldX = chunkX * chunkSize + x;
                    const worldZ = chunkZ * chunkSize + z;
                    const height = 64 + Math.floor(Math.sin(worldX * 0.1) * 3 + Math.cos(worldZ * 0.1) * 3);

                    for (let y = 0; y < height; y++) {
                        const blockType = y === height - 1 ? 0 : (y < height - 4 ? 2 : 1);
                        blocks.push({ x: worldX, y, z: worldZ, type: blockType });
                    }
                }
            }

            world.chunks.set(chunkKey, blocks);
            spawnChunkBlocks(chunkX, chunkZ, blocks);
            world.loadedChunks.add(chunkKey);
        }

        // 加载周围区块
        function loadNearbyChunks() {
            const currentChunkX = Math.floor(player.position.x / world.chunkSize);
            const currentChunkZ = Math.floor(player.position.z / world.chunkSize);

            for (let x = -world.renderDistance; x <= world.renderDistance; x++) {
                for (let z = -world.renderDistance; z <= world.renderDistance; z++) {
                    addToChunkQueue(currentChunkX + x, currentChunkZ + z);
                }
            }

            world.loadedChunks.forEach(chunkKey => {
                const [chunkX, chunkZ] = chunkKey.split(',').map(Number);
                if (Math.abs(chunkX - currentChunkX) > world.renderDistance + 1 ||
                    Math.abs(chunkZ - currentChunkZ) > world.renderDistance + 1) {
                    unloadChunk(chunkX, chunkZ);
                }
            });
        }

        // 卸载区块
        function unloadChunk(chunkX, chunkZ) {
            const chunkKey = `${chunkX},${chunkZ}`;
            world.loadedChunks.delete(chunkKey);
            world.chunks.delete(chunkKey);
            chunkQueue = chunkQueue.filter(item => item.key !== chunkKey);
        }

        // 创建相机
        function createCamera() {
            camera = new BABYLON.FreeCamera("camera", player.position.clone(), scene);
            camera.attachControl(document.getElementById('gameCanvas'));
        }

        // 创建光源
        function createLights() {
            const ambientLight = new BABYLON.HemisphericLight("ambient", new BABYLON.Vector3(0, 1, 0), scene);
            scene.lights.push(ambientLight);

            const directionalLight = new BABYLON.DirectionalLight("sun", new BABYLON.Vector3(-1, -2, -1), scene);
            scene.lights.push(directionalLight);

            const bloom = new BABYLON.UnrealBloomPass();
            const composer = new BABYLON.EffectComposer(engine);
            composer.addPass(new BABYLON.RenderPass());
            composer.addPass(bloom);
        }

        // 更新玩家移动
        function updatePlayerMovement(deltaTime) {
            const moveSpeed = camera.speed * (deltaTime / 16);
            const moveDir = player.moveDir.set(0, 0, 0);
            const gravity = scene.gravity;

            // 输入处理
            if (keys.has('w') || keys.has('ArrowUp') || (joystickActive && joystickStart.y < -10)) moveDir.z -= 1;
            if (keys.has('s') || keys.has('ArrowDown') || (joystickActive && joystickStart.y > 10)) moveDir.z += 1;
            if (keys.has('a') || keys.has('ArrowLeft') || (joystickActive && joystickStart.x < -10)) moveDir.x -= 1;
            if (keys.has('d') || keys.has('ArrowRight') || (joystickActive && joystickStart.x > 10)) moveDir.x += 1;

            // 跳跃
            if ((keys.has(' ') || keys.has('jump')) && player.onGround) {
                player.velocity.y = 5;
                player.onGround = false;
                keys.delete('jump');
            }

            // 重力
            player.velocity.y += gravity.y * (deltaTime / 16);

            // 移动方向归一化
            if (moveDir.x !== 0 || moveDir.z !== 0) moveDir.normalize();

            // 旋转移动方向
            const yRot = camera.rotation.y;
            const tempX = moveDir.x;
            moveDir.x = moveDir.x * Math.cos(yRot) - moveDir.z * Math.sin(yRot);
            moveDir.z = tempX * Math.sin(yRot) + moveDir.z * Math.cos(yRot);

            // 应用移动
            player.position.x += moveDir.x * moveSpeed;
            player.position.z += moveDir.z * moveSpeed;
            player.position.y += player.velocity.y * (deltaTime / 16);

            // 碰撞检测
            const playerMin = vectorPool[0].set(
                player.position.x - camera.ellipsoid.x,
                player.position.y - camera.ellipsoid.y,
                player.position.z - camera.ellipsoid.z
            );
            const playerMax = vectorPool[1].set(
                player.position.x + camera.ellipsoid.x,
                player.position.y + camera.ellipsoid.y,
                player.position.z + camera.ellipsoid.z
            );
            const nearbyBlocks = worldOctree.query(playerMin, playerMax, []);

            const playerSize = camera.ellipsoid;
            player.onGround = false;
            nearbyBlocks.forEach(block => {
                const blockPos = block.position;
                const blockHalf = 0.5;

                const dx = Math.abs(player.position.x - blockPos.x);
                const dy = Math.abs(player.position.y - blockPos.y);
                const dz = Math.abs(player.position.z - blockPos.z);

                if (dx < playerSize.x + blockHalf && dy < playerSize.y + blockHalf && dz < playerSize.z + blockHalf) {
                    if (dx > dy && dx > dz) {
                        player.position.x = blockPos.x + (player.position.x < blockPos.x ? -1 : 1) * (playerSize.x + blockHalf);
                        player.velocity.x = 0;
                    } else if (dz > dx && dz > dy) {
                        player.position.z = blockPos.z + (player.position.z < blockPos.z ? -1 : 1) * (playerSize.z + blockHalf);
                        player.velocity.z = 0;
                    } else if (dy > 0 && player.velocity.y < 0) {
                        player.position.y = blockPos.y + playerSize.y + blockHalf;
                        player.velocity.y = 0;
                        player.onGround = true;
                    }
                }
            });

            // 最低高度限制
            if (player.position.y < 1) {
                player.position.y = 1;
                player.velocity.y = 0;
                player.onGround = true;
            }

            // 定期加载区块
            if (engine.frameCount % 10 === 0) loadNearbyChunks();
        }

        // 更新玩家位置
        function updatePlayerPosition() {
            camera.position.set(player.position.x, player.position.y, player.position.z);
        }

        // 视锥体裁剪
        function updateFrustumCulling() {
            const projectionMatrix = camera.getProjectionMatrix(matrixPool[1]);
            const viewMatrix = camera.getViewMatrix(matrixPool[2]);
            BABYLON.Matrix.Multiply(projectionMatrix, viewMatrix, matrixPool[0]);
            BABYLON.Frustum.FromMatrix(frustum, matrixPool[0]);

            instancedMeshes.forEach(({ mesh }) => {
                mesh.isVisible = frustum.intersectsBoundingBox(mesh.getBoundingInfo().boundingBox);
            });
        }

        // 动态调整渲染距离
        function adjustRenderDistance() {
            if (engine.fps < 30 && world.renderDistance > 2) {
                world.renderDistance = 2;
            } else if (engine.fps > 50 && world.renderDistance < world.maxRenderDistance) {
                world.renderDistance = world.maxRenderDistance;
            }
        }

        // 设置UI
        function setupUI() {
            const hud = document.getElementById('hud');
            BLOCK_TYPES.forEach((block, index) => {
                const slot = document.createElement('div');
                slot.className = `hotbar-slot ${index === currentBlockType ? 'active' : ''}`;
                slot.dataset.type = index;
                slot.style.backgroundColor = `rgb(${block.color.r*255}, ${block.color.g*255}, ${block.color.b*255})`;
                hud.appendChild(slot);
            });
        }

        // 更新快捷栏
        function updateHotbar() {
            document.querySelectorAll('.hotbar-slot').forEach((slot, index) => {
                slot.classList.toggle('active', index === currentBlockType);
            });
        }

        // 放置方块
        function placeBlock() {
            const rayDir = vectorPool[0].set(
                -Math.sin(camera.rotation.y) * Math.cos(camera.rotation.x),
                -Math.sin(camera.rotation.x),
                Math.cos(camera.rotation.y) * Math.cos(camera.rotation.x)
            ).normalize();

            let hitBlock = null;
            let hitPosition = vectorPool[1];

            for (let t = 0; t < 10; t += 0.2) {
                const checkPos = vectorPool[2].set(
                    camera.position.x + rayDir.x * t,
                    camera.position.y + rayDir.y * t,
                    camera.position.z + rayDir.z * t
                );

                const nearbyBlocks = worldOctree.query(
                    checkPos.clone().subtract(vectorPool[3].set(0.5, 0.5, 0.5)),
                    checkPos.clone().add(vectorPool[3].set(0.5, 0.5, 0.5)),
                    []
                );

                for (let block of nearbyBlocks) {
                    const blockPos = block.position;
                    if (Math.abs(checkPos.x - blockPos.x) < 0.5 &&
                        Math.abs(checkPos.y - blockPos.y) < 0.5 &&
                        Math.abs(checkPos.z - blockPos.z) < 0.5) {
                        hitBlock = block;
                        hitPosition.set(
                            blockPos.x + Math.sign(checkPos.x - blockPos.x),
                            blockPos.y + Math.sign(checkPos.y - blockPos.y),
                            blockPos.z + Math.sign(checkPos.z - blockPos.z)
                        );
                        break;
                    }
                }
                if (hitBlock) break;
            }

            if (hitBlock) {
                const isEmpty = worldOctree.query(
                    hitPosition.clone().subtract(vectorPool[3].set(0.5, 0.5, 0.5)),
                    hitPosition.clone().add(vectorPool[3].set(0.5, 0.5, 0.5)),
                    []
                ).length === 0;

                if (isEmpty) {
                    const type = currentBlockType;
                    const { mesh } = instancedMeshes.get(type);
                    BABYLON.Matrix.Translation(hitPosition.x, hitPosition.y, hitPosition.z, matrixPool[0]);
                    mesh.setMatrixAt(mesh.instanceCount, matrixPool[0]);
                    mesh.instanceCount++;

                    worldOctree.insert({
                        position: hitPosition.clone(),
                        size: 1,
                        blockData: { x: hitPosition.x, y: hitPosition.y, z: hitPosition.z, type }
                    });

                    const chunkKey = `${Math.floor(hitPosition.x / world.chunkSize)},${Math.floor(hitPosition.z / world.chunkSize)}`;
                    world.chunks.has(chunkKey) && world.chunks.get(chunkKey).push({
                        x: hitPosition.x, y: hitPosition.y, z: hitPosition.z, type
                    });
                }
            }
        }

        // 破坏方块
        function breakBlock() {
            const rayDir = vectorPool[0].set(
                -Math.sin(camera.rotation.y) * Math.cos(camera.rotation.x),
                -Math.sin(camera.rotation.x),
                Math.cos(camera.rotation.y) * Math.cos(camera.rotation.x)
            ).normalize();

            let hitBlock = null;

            for (let t = 0; t < 10; t += 0.2) {
                const checkPos = vectorPool[2].set(
                    camera.position.x + rayDir.x * t,
                    camera.position.y + rayDir.y * t,
                    camera.position.z + rayDir.z * t
                );

                const nearbyBlocks = worldOctree.query(
                    checkPos.clone().subtract(vectorPool[3].set(0.5, 0.5, 0.5)),
                    checkPos.clone().add(vectorPool[3].set(0.5, 0.5, 0.5)),
                    []
                );

                for (let block of nearbyBlocks) {
                    const blockPos = block.position;
                    if (Math.abs(checkPos.x - blockPos.x) < 0.5 &&
                        Math.abs(checkPos.y - blockPos.y) < 0.5 &&
                        Math.abs(checkPos.z - blockPos.z) < 0.5) {
                        hitBlock = block;
                        break;
                    }
                }
                if (hitBlock) break;
            }

            if (hitBlock) {
                const blockPos = hitBlock.position;
                const allBlocks = worldOctree.query(new BABYLON.Vector3(-512,0,-512), new BABYLON.Vector3(512,256,512), []);
                worldOctree = new BABYLON.Octree(new BABYLON.Vector3(-512,0,-512), new BABYLON.Vector3(512,256,512));
                allBlocks.forEach(block => {
                    if (!(Math.abs(block.position.x - blockPos.x) < 0.1 &&
                         Math.abs(block.position.y - blockPos.y) < 0.1 &&
                         Math.abs(block.position.z - blockPos.z) < 0.1)) {
                        worldOctree.insert(block);
                    }
                });

                const chunkKey = `${Math.floor(blockPos.x / world.chunkSize)},${Math.floor(blockPos.z / world.chunkSize)}`;
                if (world.chunks.has(chunkKey)) {
                    const updatedBlocks = world.chunks.get(chunkKey).filter(b =>
                        !(Math.abs(b.x - blockPos.x) < 0.1 &&
                          Math.abs(b.y - blockPos.y) < 0.1 &&
                          Math.abs(b.z - blockPos.z) < 0.1)
                    );
                    world.chunks.set(chunkKey, updatedBlocks);
                }
            }
        }

        // 注册事件
        function registerEvents() {
            const canvas = document.getElementById('gameCanvas');

            // 鼠标锁定
            canvas.addEventListener('click', () => {
                if (!isMouseLocked) {
                    canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock || canvas.webkitRequestPointerLock;
                    canvas.requestPointerLock();
                }
            });

            document.addEventListener('pointerlockchange', () => {
                isMouseLocked = document.pointerLockElement === canvas;
            });

            // 鼠标移动
            document.addEventListener('mousemove', (e) => {
                if (!isMouseLocked) return;
                const movementX = e.movementX || 0;
                const movementY = e.movementY || 0;

                camera.rotation.y -= movementX * camera.angularSpeed;
                camera.rotation.x -= movementY * camera.angularSpeed;
                camera.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, camera.rotation.x));
            });

            // 键盘控制
            document.addEventListener('keydown', (e) => {
                const key = e.key.toLowerCase();
                keys.add(key);
                if (key >= '1' && key <= '5') {
                    currentBlockType = parseInt(key) - 1;
                    updateHotbar();
                }
            });

            document.addEventListener('keyup', (e) => {
                keys.delete(e.key.toLowerCase());
            });

            // 鼠标操作
            canvas.addEventListener('mousedown', (e) => {
                if (!isMouseLocked) return;
                e.button === 0 && breakBlock();
                e.button === 2 && placeBlock();
            });

            // 鼠标滚轮
            canvas.addEventListener('wheel', (e) => {
                currentBlockType = e.deltaY > 0 ?
                    (currentBlockType + 1) % BLOCK_TYPES.length :
                    (currentBlockType - 1 + BLOCK_TYPES.length) % BLOCK_TYPES.length;
                updateHotbar();
            });

            // 右键阻止默认
            canvas.addEventListener('contextmenu', (e) => e.preventDefault());

            // 移动端触摸控制
            const joystick = document.getElementById('joystick');
            const joystickThumb = document.getElementById('joystick-thumb');
            const breakBtn = document.getElementById('break-btn');
            const placeBtn = document.getElementById('place-btn');
            const jumpBtn = document.getElementById('jump-btn');

            // 虚拟摇杆触摸开始
            joystick.addEventListener('touchstart', (e) => {
                e.preventDefault();
                joystickActive = true;
                const touch = e.touches[0];
                const joystickRect = joystick.getBoundingClientRect();
                joystickStart.set(
                    touch.clientX - joystickRect.left - joystickRect.width/2,
                    touch.clientY - joystickRect.top - joystickRect.height/2,
                    0
                );
                touchIds.set(touch.identifier, 'joystick');
                joystickThumb.style.transform = `translate(${(joystickStart.x / joystickRect.width) * 100}%, ${(joystickStart.y / joystickRect.height) * 100}%)`;
            });

            // 触摸移动
            document.addEventListener('touchmove', (e) => {
                e.preventDefault();
                if (!joystickActive) return;
                const touch = Array.from(e.touches).find(t => touchIds.get(t.identifier) === 'joystick');
                if (!touch) return;

                const joystickRect = joystick.getBoundingClientRect();
                const x = touch.clientX - joystickRect.left - joystickRect.width/2;
                const y = touch.clientY - joystickRect.top - joystickRect.height/2;
                const maxDist = joystickRect.width/2 - 10;
                const dist = Math.sqrt(x*x + y*y);
                
                if (dist > maxDist) {
                    const ratio = maxDist / dist;
                    joystickStart.set(x * ratio, y * ratio, 0);
                } else {
                    joystickStart.set(x, y, 0);
                }

                joystickThumb.style.transform = `translate(${(joystickStart.x / joystickRect.width) * 100}%, ${(joystickStart.y / joystickRect.height) * 100}%)`;
            });

            // 触摸结束
            document.addEventListener('touchend', (e) => {
                e.preventDefault();
                e.changedTouches.forEach(touch => {
                    const type = touchIds.get(touch.identifier);
                    if (type === 'joystick