Code viewer for World: Lego (clone by przemek biel)

// Cloned by przemek biel on 1 Dec 2022 from World "Lego" by Michael Walsh 
// Please leave this clone trail here.
 
AB.loadCSS("/uploads/threeport/main.css");
import * as THREE from "/api/threemodule/libs/three.module.js";
let camera, scene, renderer, controls, plane, pointer, raycaster, rollOverMesh, rollOverMaterial, cubeGeo, isShiftDown = !1;
const realColors = ["#f0f8ff", "#00ffff", "#7fffd4", "#f0ffff", "#f5f5dc", "#ffe4c4", "#ffebcd", "#0000ff", "#8a2be2", "#a52a2a", "#deb887", "#5f9ea0", "#7fff00", "#d2691e", "#ff7f50", "#6495ed", "#fff8dc", "#dc143c", "#00ffff", "#00008b", "#008b8b", "#b8860b", "#006400", "#bdb76b", "#8b008b", "#556b2f", "#ff8c00", "#9932cc", "#8b0000", "#e9967a", "#8fbc8f", "#483d8b", "#00ced1", "#9400d3", "#ff1493", "#00bfff", "#1e90ff", "#b22222", "#228b22", "#ff00ff", "#dcdcdc", "#ffd700", "#daa520", "#008000", "#adff2f", "#f0fff0", "#ff69b4", "#cd5c5c", "#4b0082", "#fffff0", "#f0e68c", "#e6e6fa", "#fff0f5", "#7cfc00", "#fffacd", "#add8e6", "#f08080", "#e0ffff", "#fafad2", "#90ee90", "#ffb6c1", "#ffa07a", "#20b2aa", "#87cefa", "#b0c4de", "#ffffe0", "#00ff00", "#32cd32", "#faf0e6", "#ff00ff", "#800000", "#66cdaa", "#0000cd", "#ba55d3", "#9370db", "#3cb371", "#7b68ee", "#00fa9a", "#48d1cc", "#c71585", "#191970", "#f5fffa", "#ffe4e1", "#ffe4b5", "#000080", "#fdf5e6", "#808000", "#6b8e23", "#ffa500", "#ff4500", "#da70d6", "#eee8aa", "#98fb98", "#afeeee", "#db7093", "#ffefd5", "#ffdab9", "#cd853f", "#ffc0cb", "#dda0dd", "#b0e0e6", "#800080", "#663399", "#ff0000", "#bc8f8f", "#4169e1", "#8b4513", "#fa8072", "#f4a460", "#2e8b57", "#fff5ee", "#a0522d", "#c0c0c0", "#87ceeb", "#6a5acd", "#fffafa", "#00ff7f", "#4682b4", "#d2b48c", "#008080", "#d8bfd8", "#ff6347", "#40e0d0", "#ee82ee", "#f5deb3", "#ffff00", "#9acd32"],
    objects = {};
let worldId, theta, iota, worldHasStarted = !1;
AB.socketStart(), init(), render();
let horizontal_dist = 1392;

function yaw(e) {
    theta += e;
    let o = horizontal_dist * Math.sin(theta),
        t = horizontal_dist * Math.cos(theta),
        n = camera.position.y;
    camera.position.set(o, n, t), camera.lookAt(0, 0, 0), render()
}

function roll(e) {
    Math.abs(iota + e) > 1 || (console.log(iota + e), iota += e, horizontal_dist = 1526 * Math.cos(iota), camera.position.y = 1526 * Math.sin(iota), yaw(0))
}

function init() {
    AB.runReady = !1, AB.msg('Choose building colour: <input id="user_colour" type="color" value="' + AB.randomElementOfArray(realColors) + '" class=ab-largenormbutton><br>Rotate view using arrow keys'), (camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1e4)).position.set(500, 800, 1300), camera.lookAt(0, 0, 0), theta = Math.atan(camera.position.x / camera.position.z), iota = Math.atan(camera.position.y / camera.position.z), console.log("start", iota), (scene = new THREE.Scene).background = new THREE.Color(15790320);
    const e = new THREE.BoxGeometry(50, 50, 50);
    rollOverMaterial = new THREE.MeshBasicMaterial({
        color: 16711680,
        opacity: .5,
        transparent: !0
    }), (rollOverMesh = new THREE.Mesh(e, rollOverMaterial)).visible = !1, scene.add(rollOverMesh), cubeGeo = new THREE.BoxGeometry(50, 50, 50);
    const o = new THREE.GridHelper(1e3, 20);
    scene.add(o), raycaster = new THREE.Raycaster, pointer = new THREE.Vector2;
    const t = new THREE.PlaneGeometry(1e3, 1e3);
    t.rotateX(-Math.PI / 2), plane = new THREE.Mesh(t, new THREE.MeshBasicMaterial({
        visible: !1
    })), scene.add(plane), objects[0] = plane;
    const n = new THREE.AmbientLight(6316128);
    scene.add(n);
    const a = new THREE.DirectionalLight(16777215);
    a.position.set(1, .75, .5).normalize(), scene.add(a), (renderer = new THREE.WebGLRenderer({
        antialias: !0
    })).setPixelRatio(window.devicePixelRatio), renderer.setSize(window.innerWidth, window.innerHeight), document.body.appendChild(renderer.domElement), document.addEventListener("pointermove", onPointerMove), document.addEventListener("pointerdown", onPointerDown), document.addEventListener("keydown", onDocumentKeyDown), document.addEventListener("keyup", onDocumentKeyUp), window.addEventListener("resize", onWindowResize), AB.runReady = !0, Object.defineProperty(AB, "socket", {
        configurable: !0,
        set(e) {
            Object.defineProperty(AB, "socket", {
                value: e
            }), AB.socketOut({
                action: "send_world"
            })
        }
    })
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight, camera.updateProjectionMatrix(), renderer.setSize(window.innerWidth, window.innerHeight)
}

function getFirstIntersectedObject() {
    let e = raycaster.intersectObjects(Object.values(objects), !1);
    return e.length > 0 ? e[0] : null
}

function onPointerMove(e) {
    pointer.set(e.clientX / window.innerWidth * 2 - 1, -e.clientY / window.innerHeight * 2 + 1), raycaster.setFromCamera(pointer, camera);
    const o = getFirstIntersectedObject();
    o ? (rollOverMesh.visible = !0, rollOverMesh.position.copy(o.point).add(o.face.normal), rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25)) : rollOverMesh.visible = !1, render()
}

function onPointerDown(e) {
    pointer.set(e.clientX / window.innerWidth * 2 - 1, -e.clientY / window.innerHeight * 2 + 1), raycaster.setFromCamera(pointer, camera);
    const o = getFirstIntersectedObject();
    if (o) {
        if (isShiftDown) o.object !== plane && (scene.remove(o.object), delete objects[o.object.position.toArray().join("-")], AB.socketOut({
            action: "remove",
            worldId: worldId,
            position: o.object.position
        }));
        else {
            let e = document.getElementById("user_colour").value,
                t = new THREE.Vector3;
            t.copy(o.point).add(o.face.normal), t.divideScalar(50).floor().multiplyScalar(50).addScalar(25), worldHasStarted || (worldId = Math.floor(1e16 * Math.random()), worldHasStarted = !0), addBox(t, e), AB.socketOut({
                action: "add",
                worldId: worldId,
                position: t,
                color: e
            })
        }
        render()
    }
}

function onDocumentKeyDown(e) {
    switch (e.keyCode) {
        case 16:
            isShiftDown = !0;
            break;
        case 37:
            yaw(.1);
            break;
        case 39:
            yaw(-.1);
            break;
        case 38:
            roll(.1);
            break;
        case 40:
            roll(-.1)
    }
}

function onDocumentKeyUp(e) {
    switch (e.keyCode) {
        case 16:
            isShiftDown = !1
    }
}

function render() {
    renderer.render(scene, camera)
}

function addBox(e, o) {
    if (e.y < 0) return;
    let t = new THREE.MeshLambertMaterial({
        color: o,
        opacity: 0,
        transparent: !1
    });
    const n = new THREE.Mesh(cubeGeo, t);
    n.position.copy(e), scene.add(n), objects[n.position.toArray().join("-")] = n
}

function removeBox(e) {
    let o = e.toArray().join("-"),
        t = objects[o];
    t ? (scene.remove(t), delete objects[o]) : console.log("Can't remove box")
}
AB.socketIn = function(e) {
    if (AB.runReady) switch (e.action) {
        case "add":
            worldId == e.worldId && (addBox(e.position, e.color), render());
            break;
        case "remove":
            worldId == e.worldId && (removeBox(e.position), render());
            break;
        case "send_world":
            console.log("Received send world"); {
                let e = Object.values(objects),
                    o = [];
                for (let t = 0; t < e.length; t++) e[t] !== plane && o.push([e[t].position, e[t].material.color]);
                AB.socketOut({
                    action: "rec_world",
                    id: worldId,
                    boxes: o
                })
            }
            break;
        case "rec_world":
            if (console.log("Received get world"), !worldHasStarted) {
                worldId = e.id, worldHasStarted = !0;
                for (let o = 0; o < e.boxes.length; o++) addBox(e.boxes[o][0], e.boxes[o][1])
            }
            render()
    }
};