import { world, system } from "@minecraft/server";

// 플레이어별 미리보기 엔티티 관리용 맵
const previewEntities = new Map();
const CUSTOM_ENTITY_ID = "bridge:miribogi"; 

// ============================
// 🧭 1. 방향 계산 엔진
// ============================
function getAbsoluteRotation(player) {
    const dir = player.getViewDirection();
    const ax = Math.abs(dir.x);
    const az = Math.abs(dir.z);

    if (az > ax) {
        return dir.z > 0 ? { yRot: 0, dirX: 0, dirZ: 1 } : { yRot: 180, dirX: 0, dirZ: -1 };
    } else {
        return dir.x > 0 ? { yRot: 270, dirX: 1, dirZ: 0 } : { yRot: 90, dirX: -1, dirZ: 0 };
    }
}

// ============================
// 🧱 2. 미리보기 엔진
// ============================
system.runInterval(() => {
    for (const player of world.getAllPlayers()) {
        const equippable = player.getComponent("minecraft:equippable");
        if (!equippable) continue;

        const item = equippable.getEquipment("Mainhand");
        if (!item || item.typeId !== "minecraft:smooth_stone_slab") {
            removePreviewEntity(player.id);
            continue;
        }

        const ray = player.getBlockFromViewDirection({ maxDistance: 5 });
        if (!ray) {
            removePreviewEntity(player.id);
            continue;
        }

        const face = String(ray.face).toLowerCase();
        let targetPos = { ...ray.block.location };
        if (face === "up") targetPos.y += 1;
        else if (face === "down") targetPos.y -= 1;
        else if (face === "north") targetPos.z -= 1;
        else if (face === "south") targetPos.z += 1;
        else if (face === "west") targetPos.x -= 1;
        else if (face === "east") targetPos.x += 1;

        const spawnPos = { x: targetPos.x + 0.5, y: targetPos.y, z: targetPos.z + 0.5 };
        const rotInfo = getAbsoluteRotation(player);

        let entity = previewEntities.get(player.id);
        if (!entity || !entity.isValid()) {
            entity = player.dimension.spawnEntity(CUSTOM_ENTITY_ID, spawnPos);
            previewEntities.set(player.id, entity);
        }
        
        try {
            entity.teleport(spawnPos, { rotation: { x: 0, y: rotInfo.yRot } });
        } catch (e) {}
    }
}, 2);

function removePreviewEntity(playerId) {
    const entity = previewEntities.get(playerId);
    
    // 1. 엔티티가 존재하고, 유효한(isValid) 객체인지 먼저 확인
    if (entity && typeof entity.remove === 'function' && entity.isValid()) {
        try {
            entity.remove();
        } catch (e) {
            // 삭제 중 발생할 수 있는 잠재적 오류 무시
        }
    }
    
    // 2. 맵에서 안전하게 삭제
    previewEntities.delete(playerId);
}


// ============================
// 🏗️ 3. 설치 엔진
// ============================
world.afterEvents.itemUseOn.subscribe(ev => {
    const player = ev.source;
    if (ev.itemStack?.typeId !== "minecraft:smooth_stone_slab") return;

    removePreviewEntity(player.id);
    const rotInfo = getAbsoluteRotation(player);
    const pos = ev.block.location;
    const face = String(ev.blockFace).toLowerCase();
    
    let targetPos = { ...pos };
    if (face === "up") targetPos.y += 1;
    else if (face === "down") targetPos.y -= 1;
    else if (face === "north") targetPos.z -= 1;
    else if (face === "south") targetPos.z += 1;
    else if (face === "west") targetPos.x -= 1;
    else if (face === "east") targetPos.x += 1;

    player.dimension.runCommandAsync(`setblock ${targetPos.x} ${targetPos.y} ${targetPos.z} smooth_stone_slab`);
    const entity = player.dimension.spawnEntity(CUSTOM_ENTITY_ID, { x: targetPos.x + 0.5, y: targetPos.y, z: targetPos.z + 0.5 });
    entity.nameTag = `conv:${rotInfo.dirX}:${rotInfo.dirZ}`;
    entity.teleport(entity.location, { rotation: { x: 0, y: rotInfo.yRot } });
});

// ============================
// 🚀 4. 정밀 이동 엔진
// ============================
system.runInterval(() => {
    for (const player of world.getAllPlayers()) {
        const dim = player.dimension;
        for (const item of dim.getEntities({ type: "item" })) {
            if (!item.isValid()) continue;

            const nearBelts = dim.getEntities({ type: CUSTOM_ENTITY_ID, location: item.location, maxDistance: 0.6 });
            if (nearBelts.length === 0) continue;

            const tag = nearBelts[0].nameTag;
            if (!tag || !tag.startsWith("conv:")) continue;

            const [_, dx, dz] = tag.split(":");
            const dirX = parseInt(dx);
            const dirZ = parseInt(dz);

            // 물리 오류 방지: setLinearVelocity 대신 속도를 반전시켜 정지 구현
            const vel = item.getVelocity();
            if (Math.abs(vel.x) > 0.2 || Math.abs(vel.z) > 0.2) {
                item.applyImpulse({ x: -vel.x * 0.8, y: 0, z: -vel.z * 0.8 });
            } else {
                item.applyImpulse({ x: dirX * 0.08, y: 0, z: dirZ * 0.08 });
            }
        }
    }
}, 2);

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: