Memesense V2

Advanced Krunker.io cheat - Aimbot, ESP, Chams, FOV Changer, Keystrokes

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Memesense V2
// @namespace    http://tampermonkey.net/
// @version      2.9.4
// @description  Advanced Krunker.io cheat - Aimbot, ESP, Chams, FOV Changer, Keystrokes
// @license      N1ko
// @author       N1ko
// @match        *://krunker.io/*
// @match        *://browserfps.com/*
// @exclude      *://krunker.io/social*
// @exclude      *://krunker.io/editor*
// @icon         https://www.google.com/s2/favicons?domain=krunker.io
// @run-at       document-start
// @require      https://unpkg.com/[email protected]/build/three.min.js
// @grant        none
// ==/UserScript==

const THREE = window.THREE;
delete window.THREE;

const CheatSettings = {
    aimbotEnabled: false,
    aimbotFOV: 180,
    aimSmooth: 50,
    hitbox: 'head',          // 'head', 'torso', 'legs'
    teamCheck: false,
    wallCheck: true,
    espEnabled: false,
    espBox: true,
    espName: true,
    espClass: true,
    espDistance: true,
    espTracers: true,
    espChams: false,
    keystrokesEnabled: false,
    fovChanger: 0,
    wireframe: false
};

const keyToSetting = {
    KeyV: 'aimbotEnabled',
    KeyN: 'espEnabled',
    KeyT: 'teamCheck',
    KeyC: 'espChams',
    KeyK: 'keystrokesEnabled',
    KeyL: 'wireframe'
};

let scene, myPlayerObject = null, rainbowHue = 0;
let playerInputs = null;
let listeningForKey = null, listeningKeyEl = null;
let frameCount = 0, wallCache = null;

// Speedometer
let lastSpeedPos = null, lastSpeedTime = null, lastPlayerObject = null;
let speedDisplayEl = null, speedValueEl = null;

// Chams
const originalMaterials = new Map();
const chamsMaterial = new THREE.MeshBasicMaterial({
    color: 0xff0000,
    depthTest: false,
    depthWrite: false,
    transparent: true,
    opacity: 0.8
});

// Preallocated vectors
const _v1 = new THREE.Vector3();
const _v2 = new THREE.Vector3();
const _v3 = new THREE.Vector3();
const _proj = new THREE.Vector3();
const _aimPos = new THREE.Vector3();
const _myHead = new THREE.Vector3();

// Keystrokes UI
let keystrokesContainer = null;
const pressedKeys = new Set();
let isDraggingKeystrokes = false;
let dragOffsetX = 0, dragOffsetY = 0;

const x = {
    window, document, querySelector: document.querySelector, consoleLog: console.log,
    ArrayPrototype: Array.prototype, ArrayPush: Array.prototype.push,
    setTimeout: window.setTimeout, requestAnimationFrame: window.requestAnimationFrame
};
x.consoleLog('Memesense V2 - Waiting for access...');

const proxied = function (object) {
    try {
        if (typeof object === 'object' && typeof object.parent === 'object' &&
            object.parent.type === 'Scene' && object.parent.name === 'Main') {
            x.consoleLog('Found Scene!');
            scene = object.parent;
            x.ArrayPrototype.push = x.ArrayPush;
        }
    } catch (error) {}
    return x.ArrayPush.apply(this, arguments);
};

const tempVector = new THREE.Vector3();
const tempVector2 = new THREE.Vector3();
const tempObject = new THREE.Object3D();
tempObject.rotation.order = 'YXZ';
const raycaster = new THREE.Raycaster();

const geometry = new THREE.EdgesGeometry(new THREE.BoxGeometry(5, 15, 5).translate(0, 7.5, 0));
const rainbowMaterial = new THREE.RawShaderMaterial({
    vertexShader: `
        attribute vec3 position;
        uniform mat4 projectionMatrix;
        uniform mat4 modelViewMatrix;
        uniform vec3 uColor;
        void main() {
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            gl_Position.z = 1.0;
        }`,
    fragmentShader: `
        precision mediump float;
        uniform vec3 uColor;
        void main() { gl_FragColor = vec4(uColor, 1.0); }`,
    uniforms: { uColor: { value: new THREE.Vector3(1, 0, 0) } }
});

let injectTimer = null, canvas2d = null, ctx2d = null;

function hslToRgb(h, s, l) {
    let r, g, b;
    if (s === 0) { r = g = b = l; } else {
        const hue2rgb = (p, q, t) => {
            if (t < 0) t += 1; if (t > 1) t -= 1;
            if (t < 1/6) return p + (q - p) * 6 * t;
            if (t < 1/2) return q;
            if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        };
        const q = l < 0.5 ? l * (1 + s) : l + s - l * s, p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3);
    }
    return [r, g, b];
}

function isCrouched(player) {
    try { return player.children?.[0]?.position?.y < 0; } catch(e) { return false; }
}

function isInFOV(targetPos, myPlayer, fov) {
    tempVector2.copy(targetPos).sub(myPlayer.position);
    const angle = myPlayer.children[0].rotation.x;
    const targetAngle = Math.atan2(tempVector2.y, tempVector2.length());
    return Math.abs(targetAngle - angle) < (fov / 2) * (Math.PI / 180);
}

function buildWallCache() {
    if (wallCache) return;
    wallCache = [];
    const stack = [scene];
    while (stack.length > 0) {
        const obj = stack.pop();
        if (obj.type === 'Mesh' && obj.material && !obj.material.transparent) wallCache.push(obj);
        if (obj.children) {
            for (let i = 0; i < obj.children.length; i++) {
                const c = obj.children[i];
                if (c.type !== 'Object3D' || !c.children?.[0]?.children?.[0]?.type?.includes('Camera')) stack.push(c);
            }
        }
    }
}

function isWallBetween(from, to) {
    if (!wallCache || wallCache.length === 0) return false;
    tempVector2.copy(to).sub(from);
    const dist = tempVector2.length();
    if (dist < 0.5) return false;
    tempVector2.normalize();
    raycaster.set(from, tempVector2);
    raycaster.far = dist;
    return raycaster.intersectObjects(wallCache, false).length > 0;
}

function getClassName(player) {
    try {
        const n = (player.children?.[0]?.children?.[2]?.name || '').toLowerCase();
        const m = { weapon:'Triggerman', smg:'Run N Gun', sniper:'Hunter', shotgun:'Vince',
            pistol:'Detective', revolver:'Detective', rocket:'Rocketeer', crossbow:'Archer',
            knife:'Knifeman', sword:'Knifeman', bat:'Knifeman', hammer:'Knifeman' };
        for (const [k, v] of Object.entries(m)) { if (n.includes(k)) return v; }
    } catch(e) {}
    return 'Unknown';
}

function getPlayerName(player) {
    try { if (player.name && player.name.length > 0) return player.name; } catch(e) {}
    return 'Enemy';
}

function isTeammate(myPlayer, target) {
    const myTeam = myPlayer?.userData?.team ?? myPlayer?.team ?? myPlayer?.children?.[0]?.userData?.team ?? myPlayer?.children?.[0]?.children?.[0]?.userData?.team;
    const tTeam = target?.userData?.team ?? target?.team ?? target?.children?.[0]?.userData?.team ?? target?.children?.[0]?.children?.[0]?.userData?.team;
    if (myTeam !== undefined && tTeam !== undefined) return myTeam === tTeam;
    if (target?.isYou) return true;
    return false;
}

function findInputs() {
    if (playerInputs) return true;
    if (!myPlayerObject) return false;
    try {
        const cam = myPlayerObject.children?.[0]?.children?.[0];
        if (cam?.userData?.inputs) { playerInputs = cam.userData.inputs; return true; }
        if (cam?.userData?.world?.inputs) { playerInputs = cam.userData.world.inputs; return true; }
        const ctrl = myPlayerObject.children?.[0];
        if (ctrl?.userData?.inputs) { playerInputs = ctrl.userData.inputs; return true; }
    } catch(e) {}
    return false;
}

// Robust getAimPos with try-catch
function getAimPos(player, out) {
    const hitbox = CheatSettings.hitbox;
    try {
        if (hitbox === 'head') {
            if (player.children?.[0]?.children?.[0]) {
                out.setScalar(0);
                player.children[0].children[0].localToWorld(out);
                return out;
            }
            out.set(player.position.x, player.position.y + (isCrouched(player) ? 8 : 13), player.position.z);
            return out;
        } else if (hitbox === 'torso') {
            out.set(player.position.x, player.position.y + (isCrouched(player) ? 5 : 10), player.position.z);
            return out;
        } else { // legs
            out.set(player.position.x, player.position.y + (isCrouched(player) ? 2 : 5), player.position.z);
            return out;
        }
    } catch(e) {
        // Fallback to feet position
        out.set(player.position.x, player.position.y, player.position.z);
        return out;
    }
}

function setup2DCanvas() {
    if (canvas2d) return;
    canvas2d = document.createElement('canvas');
    canvas2d.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9998;';
    canvas2d.width = window.innerWidth;
    canvas2d.height = window.innerHeight;
    document.body.appendChild(canvas2d);
    ctx2d = canvas2d.getContext('2d');
    window.addEventListener('resize', () => {
        canvas2d.width = window.innerWidth;
        canvas2d.height = window.innerHeight;
    });
}

function worldToScreen(pos, camera, target) {
    target = target || new THREE.Vector3();
    target.copy(pos).project(camera);
    return {
        x: (target.x * 0.5 + 0.5) * canvas2d.width,
        y: (-target.y * 0.5 + 0.5) * canvas2d.height,
        z: target.z
    };
}

function drawESP2D(players, myPlayer, camera) {
    if (!ctx2d || !CheatSettings.espEnabled) return;
    ctx2d.clearRect(0, 0, canvas2d.width, canvas2d.height);
    const screenCenterX = canvas2d.width / 2;
    const screenCenterY = canvas2d.height / 2;

    for (let i = 0; i < players.length; i++) {
        const p = players[i];
        if (p.position.x === myPlayer.position.x && p.position.z === myPlayer.position.z) continue;
        const h = isCrouched(p) ? 8 : 15;
        _v1.set(p.position.x, p.position.y + h, p.position.z);
        _v2.set(p.position.x, p.position.y, p.position.z);
        const top = worldToScreen(_v1, camera, _v3);
        const bot = worldToScreen(_v2, camera, null);
        if (top.z > 1 || bot.z > 1) continue;
        const sH = Math.abs(top.y - bot.y), sW = sH * 0.5;
        const [r, g, b] = hslToRgb((rainbowHue + i * 0.15) % 1, 1, 0.5);
        const clr = `rgb(${Math.floor(r*255)},${Math.floor(g*255)},${Math.floor(b*255)})`;

        if (CheatSettings.espBox) {
            ctx2d.strokeStyle = clr;
            ctx2d.lineWidth = 2;
            ctx2d.strokeRect(top.x - sW/2, top.y, sW, sH);
        }
        let ty = top.y - 5;
        if (CheatSettings.espName) {
            ctx2d.fillStyle = clr;
            ctx2d.font = 'bold 12px "Orbitron", sans-serif';
            ctx2d.textAlign = 'center';
            ctx2d.fillText(getPlayerName(p), top.x, ty);
            ty -= 14;
        }
        if (CheatSettings.espClass) {
            ctx2d.fillStyle = 'rgba(255,255,255,0.8)';
            ctx2d.font = '10px "Orbitron", sans-serif';
            ctx2d.textAlign = 'center';
            ctx2d.fillText(getClassName(p), top.x, ty);
            ty -= 12;
        }
        if (CheatSettings.espDistance) {
            const dx = p.position.x - myPlayer.position.x, dz = p.position.z - myPlayer.position.z;
            const dy = p.position.y - myPlayer.position.y;
            const dist = Math.sqrt(dx*dx + dy*dy + dz*dz);
            ctx2d.fillStyle = 'rgba(255,255,255,0.6)';
            ctx2d.font = '10px "Orbitron", sans-serif';
            ctx2d.fillText(Math.floor(dist) + 'm', top.x, bot.y + 26);
        }
        if (CheatSettings.espTracers) {
            ctx2d.beginPath();
            ctx2d.moveTo(screenCenterX, screenCenterY);
            ctx2d.lineTo(top.x, top.y);
            ctx2d.strokeStyle = clr;
            ctx2d.lineWidth = 1;
            ctx2d.stroke();
        }
        if (CheatSettings.teamCheck && isTeammate(myPlayer, p)) {
            ctx2d.strokeStyle = 'rgba(0,255,0,0.5)';
            ctx2d.lineWidth = 1;
            ctx2d.strokeRect(top.x - sW/2 - 2, top.y - 2, sW + 4, sH + 4);
        }
    }

    // Watermark (dark red, only when ESP is fully on)
    ctx2d.fillStyle = '#8B0000';
    ctx2d.font = 'bold 16px "Orbitron", sans-serif';
    ctx2d.textAlign = 'left';
    ctx2d.fillText('MemesenseV2', 10, canvas2d.height - 10);
}

function applyChams(players, myPlayer) {
    if (!CheatSettings.espChams) {
        for (const [player, mats] of originalMaterials.entries()) {
            for (const { mesh, material } of mats) {
                mesh.material = material;
            }
        }
        originalMaterials.clear();
        return;
    }
    for (const p of players) {
        if (p.position.x === myPlayer.position.x && p.position.z === myPlayer.position.z) continue;
        if (CheatSettings.teamCheck && isTeammate(myPlayer, p)) continue;
        if (!originalMaterials.has(p)) {
            const mats = [];
            p.traverse(obj => {
                if (obj.isMesh && obj.material) {
                    mats.push({ mesh: obj, material: obj.material });
                    obj.material = chamsMaterial;
                }
            });
            originalMaterials.set(p, mats);
        }
    }
    for (const [player, mats] of originalMaterials.entries()) {
        if (!players.includes(player) || (CheatSettings.teamCheck && isTeammate(myPlayer, player))) {
            for (const { mesh, material } of mats) {
                mesh.material = material;
            }
            originalMaterials.delete(player);
        }
    }
}

function createSpeedometer() {
    if (speedDisplayEl) return;
    speedDisplayEl = document.createElement('div');
    speedDisplayEl.style.cssText = 'position:fixed;top:10px;left:10px;z-index:9999;font-family:"Orbitron",sans-serif;font-size:14px;color:#fff;background:rgba(0,0,0,0.7);padding:8px 12px;border-radius:6px;border:1px solid #ff0000;pointer-events:none;';
    speedDisplayEl.innerHTML = 'Speed: <span style="font-weight:bold;color:#00ff00;">0.00</span> m/s';
    speedValueEl = speedDisplayEl.querySelector('span');
    document.body.appendChild(speedDisplayEl);
}

function createWatermark() {
    const wm = document.createElement('div');
    wm.style.cssText = 'position:fixed;bottom:10px;left:10px;z-index:10000;font-family:"Orbitron",sans-serif;font-size:16px;color:#8B0000;background:rgba(0,0,0,0.5);padding:8px 16px;border-radius:6px;border:1px solid #ff0000;pointer-events:none;';
    wm.textContent = 'MemesenseV2';
    wm.classList.add('memesense-watermark');
    document.body.appendChild(wm);
}

function createKeystrokes() {
    if (keystrokesContainer) return;
    keystrokesContainer = document.createElement('div');
    keystrokesContainer.style.cssText = 'position:fixed;bottom:10px;right:10px;z-index:9999;display:flex;flex-direction:column;align-items:center;gap:5px;font-family:"Orbitron",sans-serif;cursor:grab;user-select:none;';

    const row1 = document.createElement('div');
    row1.style.cssText = 'display:flex;gap:5px;';
    row1.appendChild(createKeyElement('W', 'KeyW'));
    keystrokesContainer.appendChild(row1);

    const row2 = document.createElement('div');
    row2.style.cssText = 'display:flex;gap:5px;';
    row2.appendChild(createKeyElement('A', 'KeyA'));
    row2.appendChild(createKeyElement('S', 'KeyS'));
    row2.appendChild(createKeyElement('D', 'KeyD'));
    keystrokesContainer.appendChild(row2);

    const row3 = document.createElement('div');
    row3.style.cssText = 'display:flex;justify-content:center;gap:5px;';
    const keySpace = createKeyElement('Space', 'Space');
    keySpace.style.width = '70px';
    row3.appendChild(keySpace);
    keystrokesContainer.appendChild(row3);

    keystrokesContainer.addEventListener('mousedown', (e) => {
        isDraggingKeystrokes = true;
        const rect = keystrokesContainer.getBoundingClientRect();
        dragOffsetX = e.clientX - rect.left;
        dragOffsetY = e.clientY - rect.top;
        keystrokesContainer.style.cursor = 'grabbing';
        e.preventDefault();
    });

    document.addEventListener('mousemove', (e) => {
        if (isDraggingKeystrokes) {
            keystrokesContainer.style.left = (e.clientX - dragOffsetX) + 'px';
            keystrokesContainer.style.top = (e.clientY - dragOffsetY) + 'px';
            keystrokesContainer.style.bottom = 'auto';
            keystrokesContainer.style.right = 'auto';
        }
    });

    document.addEventListener('mouseup', () => {
        isDraggingKeystrokes = false;
        keystrokesContainer.style.cursor = 'grab';
    });

    document.body.appendChild(keystrokesContainer);
}

function createKeyElement(label, code) {
    const el = document.createElement('div');
    el.className = 'key-' + code.toLowerCase();
    el.textContent = label;
    el.style.cssText = 'width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.5);border:1px solid #fff;border-radius:5px;font-size:14px;font-weight:bold;color:#fff;transition:background 0.1s;';
    return el;
}

function updateKeystrokes() {
    if (!keystrokesContainer) return;
    const keyMap = {
        'KeyW': '.key-keyw',
        'KeyA': '.key-keya',
        'KeyS': '.key-keys',
        'KeyD': '.key-keyd',
        'Space': '.key-space'
    };
    for (const [code, selector] of Object.entries(keyMap)) {
        const el = keystrokesContainer.querySelector(selector);
        if (el) {
            if (pressedKeys.has(code)) {
                el.style.background = 'rgba(255,0,0,0.8)';
            } else {
                el.style.background = 'rgba(0,0,0,0.5)';
            }
        }
    }
}

function applyFOV(camera) {
    if (CheatSettings.fovChanger > 0 && camera) {
        camera.fov = CheatSettings.fovChanger;
        camera.updateProjectionMatrix();
    }
}

function animate() {
    x.requestAnimationFrame.call(x.window, animate);
    frameCount++;

    if (document.body) {
        if (!speedDisplayEl) createSpeedometer();
        if (!document.querySelector('.memesense-watermark')) createWatermark();
        if (CheatSettings.keystrokesEnabled && !keystrokesContainer) createKeystrokes();
        if (!CheatSettings.keystrokesEnabled && keystrokesContainer) {
            keystrokesContainer.remove();
            keystrokesContainer = null;
        }
    }

    if (frameCount % 3 === 0) {
        rainbowHue = (rainbowHue + 0.005) % 1;
        const [r, g, b] = hslToRgb(rainbowHue, 1, 0.5);
        rainbowMaterial.uniforms.uColor.value.set(r, g, b);
    }

    if (!scene && !injectTimer) {
        const el = x.querySelector.call(x.document, '#loadingBg');
        if (el && el.style.display === 'none') {
            injectTimer = x.setTimeout.call(x.window, () => {
                x.consoleLog('Memesense V2 Injected!');
                x.ArrayPrototype.push = proxied;
            }, 2e3);
        }
    }

    const players = [];
    let myPlayer, camera;
    if (!scene) return;

    const children = scene.children;
    for (let i = 0, len = children.length; i < len; i++) {
        const child = children[i];
        if (child.type === 'Object3D') {
            try {
                if (child.children[0].children[0].type === 'PerspectiveCamera') {
                    myPlayer = child;
                    camera = child.children[0].children[0];
                    myPlayerObject = child;
                } else {
                    players.push(child);
                }
            } catch (err) {}
        } else if (child.material) {
            child.material.wireframe = CheatSettings.wireframe;
        }
    }

    if (!myPlayer) {
        playerInputs = null;
        wallCache = null;
        lastSpeedPos = null;
        lastSpeedTime = null;
        lastPlayerObject = null;
        x.ArrayPrototype.push = proxied;
        return;
    }

    // Speed
    const now = performance.now();
    if (lastSpeedPos && lastSpeedTime && lastPlayerObject === myPlayer) {
        const dx = myPlayer.position.x - lastSpeedPos.x;
        const dz = myPlayer.position.z - lastSpeedPos.z;
        const dist = Math.sqrt(dx*dx + dz*dz);
        const dt = (now - lastSpeedTime) / 1000;
        const speed = dt > 0 ? dist / dt : 0;
        if (speedValueEl) speedValueEl.textContent = speed.toFixed(2);
    }
    if (!lastSpeedPos) lastSpeedPos = new THREE.Vector3();
    lastSpeedPos.copy(myPlayer.position);
    lastSpeedTime = now;
    lastPlayerObject = myPlayer;

    // FOV
    applyFOV(camera);

    // ESP / Chams
    if (CheatSettings.espEnabled || CheatSettings.espChams) {
        for (const p of players) {
            if (!p.box) {
                const box = new THREE.LineSegments(geometry, rainbowMaterial);
                box.frustumCulled = false;
                p.add(box);
                p.box = box;
            }
            if (p.position.x === myPlayer.position.x && p.position.z === myPlayer.position.z) {
                p.box.visible = false;
                continue;
            }
            p.box.visible = CheatSettings.espEnabled;
            if (CheatSettings.espEnabled) {
                if (isCrouched(p)) {
                    p.box.scale.y = 0.5;
                    p.box.position.y = -3;
                } else {
                    p.box.scale.y = 1;
                    p.box.position.y = 0;
                }
            }
        }
        if (CheatSettings.espEnabled && camera) {
            if (!canvas2d) setup2DCanvas();
            drawESP2D(players, myPlayer, camera);
        }
        applyChams(players, myPlayer);
    } else {
        for (const p of players) {
            if (p.box) p.box.visible = false;
        }
        if (ctx2d) ctx2d.clearRect(0, 0, canvas2d.width, canvas2d.height);
        applyChams([], myPlayer);
    }

    // Keystrokes
    if (CheatSettings.keystrokesEnabled) {
        updateKeystrokes();
    }

    // ===== AIMBOT (v1 logic, robust) =====
    if (!CheatSettings.aimbotEnabled) return;

    if (CheatSettings.wallCheck && !wallCache && frameCount % 60 === 0) buildWallCache();

    let targetPlayer = null;
    let minCrossDist = Infinity;

    for (let i = 0; i < players.length; i++) {
        const p = players[i];
        if (p.position.x === myPlayer.position.x && p.position.z === myPlayer.position.z) continue;
        if (CheatSettings.teamCheck && isTeammate(myPlayer, p)) continue;

        getAimPos(p, _aimPos);
        if (CheatSettings.aimbotFOV < 180 && !isInFOV(_aimPos, myPlayer, CheatSettings.aimbotFOV)) continue;

        _proj.copy(_aimPos).project(camera);
        if (_proj.z > 1) continue;
        const crossDist = _proj.x * _proj.x + _proj.y * _proj.y;
        if (crossDist < minCrossDist) {
            targetPlayer = p;
            minCrossDist = crossDist;
        }
    }

    if (!targetPlayer) return;

    if (CheatSettings.wallCheck && wallCache) {
        getAimPos(targetPlayer, _aimPos);
        _myHead.set(myPlayer.position.x, myPlayer.position.y + 13, myPlayer.position.z);
        if (isWallBetween(_myHead, _aimPos)) return;
    }

    getAimPos(targetPlayer, _aimPos);
    if (!myPlayer?.position) return;

    tempObject.position.copy(myPlayer.position);
    tempObject.lookAt(_aimPos);

    if (CheatSettings.aimSmooth > 0) {
        const s = CheatSettings.aimSmooth / 100;
        if (myPlayer.children?.[0]?.rotation) {
            const tPitch = -tempObject.rotation.x;
            const tYaw = tempObject.rotation.y + Math.PI;
            myPlayer.children[0].rotation.x += (tPitch - myPlayer.children[0].rotation.x) * s;
            myPlayer.rotation.y += (tYaw - myPlayer.rotation.y) * s;
        }
    } else {
        if (myPlayer.children?.[0]?.rotation) {
            myPlayer.children[0].rotation.x = -tempObject.rotation.x;
            myPlayer.rotation.y = tempObject.rotation.y + Math.PI;
        }
    }

    if (findInputs() && playerInputs?.keys) {
        playerInputs.keys[0] = true;
    }
    // ===== END AIMBOT =====
}

// --- UI Setup ---
const style = document.createElement('style');
style.textContent = `
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');

:root { --on-color: #00ff00; --off-color: #ff4757; --bg-dark: rgba(0,0,0,0.9); --bg-item: rgba(0,0,0,0.4); }
.msg { position:absolute;left:10px;bottom:10px;color:#fff;background:rgba(0,0,0,0.85);font-weight:500;padding:12px 20px;border-radius:6px;box-shadow:0 4px 15px rgba(0,0,0,0.7);animation:msg-in .3s forwards,msg-out .3s forwards 3s;z-index:999999;pointer-events:none;font-family:'Orbitron',sans-serif;border:2px solid #ff0000; }
@keyframes msg-in { from{transform:translateX(-120%);opacity:0} to{transform:translateX(0);opacity:1} }
@keyframes msg-out { from{transform:translateX(0);opacity:1} to{transform:translateX(-120%);opacity:0} }

/* Centered vertical menu with tabs */
.zui {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 9999;
    display: flex;
    flex-direction: column;
    font-family: 'Orbitron', sans-serif;
    font-size: 14px;
    color: #fff;
    width: 320px;
    max-height: 80vh;
    overflow: hidden;
    user-select: none;
    border-radius: 12px;
    background: var(--bg-dark);
    backdrop-filter: blur(8px);
    box-shadow: 0 8px 32px rgba(0,0,0,0.4);
    border: 2px solid #ff0000;
}
.zui-tabs {
    display: flex;
    justify-content: space-around;
    background: linear-gradient(180deg, #ff0000, #000000);
    border-bottom: 2px solid #ff0000;
    padding: 0;
}
.zui-tab {
    padding: 10px 0;
    cursor: pointer;
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 1px;
    color: #fff;
    text-align: center;
    flex: 1;
    transition: background 0.2s;
}
.zui-tab:hover {
    background: rgba(255,0,0,0.2);
}
.zui-tab.active {
    background: rgba(255,0,0,0.3);
    border-bottom: 2px solid #ff0000;
}
.zui-content {
    overflow-y: auto;
    max-height: calc(80vh - 60px);
}
.zui::-webkit-scrollbar { width: 4px; }
.zui::-webkit-scrollbar-thumb { background: #ff0000; border-radius: 2px; }
.zui-section { padding: 6px 15px; font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #ff0000; background: rgba(255,0,0,0.1); border-bottom: 1px solid rgba(255,0,0,0.3); }
.zui-item { padding: 10px 15px; display: flex; justify-content: space-between; align-items: center; background: var(--bg-item); border-bottom: 1px solid rgba(255,255,255,0.1); transition: background .2s; cursor: pointer; color: #fff; }
.zui-item:hover { background: rgba(255,0,0,0.15); }
.zui-item-value { font-weight: bold; transition: color .2s; }
.zui-keybind { font-size: 11px; padding: 2px 6px; border-radius: 3px; background: rgba(255,255,255,0.15); color: #ff0000; cursor: pointer; margin-left: 6px; border: 1px solid rgba(255,0,0,0.3); transition: all .2s; }
.zui-keybind:hover { background: rgba(255,0,0,0.3); }
.zui-keybind.listening { background: rgba(255,0,0,0.4); color: #fff; border-color: #ff0000; animation: pulse .5s ease infinite alternate; }
@keyframes pulse { from{opacity:0.6} to{opacity:1} }
.zui-footer { padding: 8px; text-align: center; font-size: 11px; color: rgba(255,255,255,0.4); border-top: 1px solid rgba(255,0,0,0.3); background: rgba(0,0,0,0.5); }
`;
document.head.appendChild(style);

const msgEl = document.createElement('div');
msgEl.className = 'msg';
msgEl.style.display = 'none';

const gui = createGUI();

window.addEventListener('DOMContentLoaded', function () {
    document.body.appendChild(msgEl);
    document.body.appendChild(gui);
});

window.addEventListener('keydown', function (event) {
    if (CheatSettings.keystrokesEnabled) {
        pressedKeys.add(event.code);
        updateKeystrokes();
    }
    if (listeningForKey && listeningKeyEl) {
        event.preventDefault(); event.stopPropagation();
        const newCode = event.code;
        const oldCode = listeningForKey;
        const settingName = keyToSetting[oldCode];
        delete keyToSetting[oldCode];
        keyToSetting[newCode] = settingName;
        listeningKeyEl.textContent = formatKey(newCode);
        listeningKeyEl.classList.remove('listening');
        listeningForKey = null; listeningKeyEl = null;
        return;
    }
    if (document.activeElement && document.activeElement.value !== undefined) return;
    if (keyToSetting[event.code]) { event.preventDefault(); toggleSetting(keyToSetting[event.code]); }
    if (event.code === 'Slash') gui.style.display = gui.style.display === 'none' ? '' : 'none';
}, true);

window.addEventListener('keyup', function (event) {
    if (CheatSettings.keystrokesEnabled) {
        pressedKeys.delete(event.code);
        updateKeystrokes();
    }
    if (listeningForKey) { event.preventDefault(); return; }
}, true);

function formatKey(code) {
    if (code.startsWith('Key')) return code.slice(3);
    if (code.startsWith('Digit')) return code.slice(5);
    if (code === 'Space') return 'Space';
    if (code.startsWith('Shift')) return 'Shift';
    if (code.startsWith('Control')) return 'Ctrl';
    if (code.startsWith('Alt')) return 'Alt';
    if (code === 'Tab') return 'Tab';
    if (code === 'Enter') return 'Enter';
    if (code === 'Backspace') return 'Bksp';
    if (code.startsWith('Arrow')) return code.slice(5);
    return code;
}

function showMsg(name, bool) {
    msgEl.innerText = name + ': ' + (bool ? 'ON' : 'OFF');
    msgEl.style.display = 'none';
    void msgEl.offsetWidth;
    msgEl.style.display = '';
}

animate();

function createGUI() {
    const guiEl = fromHtml(`<div class="zui">
        <div class="zui-tabs" id="zui-tabs">
            <div class="zui-tab active" data-tab="Aimbot">Aimbot</div>
            <div class="zui-tab" data-tab="ESP">ESP</div>
            <div class="zui-tab" data-tab="Visual">Visual</div>
        </div>
        <div class="zui-content" id="zui-content"></div>
        <div class="zui-footer">Made By N1ko</div>
    </div>`);
    const contentEl = guiEl.querySelector('#zui-content');
    const tabsContainer = guiEl.querySelector('#zui-tabs');

    const sections = {
        Aimbot: ['aimbotEnabled', 'aimbotFOV', 'aimSmooth', 'hitbox', 'teamCheck', 'wallCheck'],
        ESP: ['espEnabled', 'espBox', 'espName', 'espClass', 'espDistance', 'espTracers', 'espChams'],
        Visual: ['fovChanger', 'keystrokesEnabled', 'wireframe']
    };

    const settingToKey = {};
    for (const k in keyToSetting) settingToKey[keyToSetting[k]] = k;

    // Create content for each tab
    const tabContents = {};
    for (const [tabName, props] of Object.entries(sections)) {
        const tabDiv = document.createElement('div');
        tabDiv.className = 'tab-content';
        tabDiv.dataset.tab = tabName;
        tabDiv.style.display = tabName === 'Aimbot' ? 'block' : 'none';
        for (const prop of props) {
            let name = fromCamel(prop);
            const hasBind = settingToKey[prop] !== undefined;
            const currentKey = settingToKey[prop] || '';

            if (prop === 'aimbotFOV') {
                const itemEl = fromHtml(`<div class="zui-item"><span>${name}</span><span class="zui-item-value"></span></div>`);
                const valEl = itemEl.querySelector('.zui-item-value');
                const upd = () => { valEl.innerText = CheatSettings[prop] + '\u00B0'; valEl.style.color = '#fff'; };
                itemEl.onclick = () => { CheatSettings[prop] = (CheatSettings[prop] + 15) % 195; if (!CheatSettings[prop]) CheatSettings[prop] = 15; };
                upd(); tabDiv.appendChild(itemEl); watchProp(prop, upd);
            } else if (prop === 'aimSmooth') {
                const itemEl = fromHtml(`<div class="zui-item"><span>${name}</span><span class="zui-item-value"></span></div>`);
                const valEl = itemEl.querySelector('.zui-item-value');
                const upd = () => { valEl.innerText = CheatSettings[prop] + '%'; valEl.style.color = CheatSettings[prop] > 0 ? '#ffff00' : '#fff'; };
                itemEl.onclick = () => { CheatSettings[prop] = (CheatSettings[prop] + 10) % 110; };
                upd(); tabDiv.appendChild(itemEl); watchProp(prop, upd);
            } else if (prop === 'hitbox') {
                const itemEl = fromHtml(`<div class="zui-item"><span>${name}</span><span class="zui-item-value"></span></div>`);
                const valEl = itemEl.querySelector('.zui-item-value');
                const options = ['head', 'torso', 'legs'];
                let idx = options.indexOf(CheatSettings.hitbox);
                const upd = () => { valEl.innerText = CheatSettings.hitbox.charAt(0).toUpperCase() + CheatSettings.hitbox.slice(1); valEl.style.color = '#fff'; };
                itemEl.onclick = () => { idx = (idx + 1) % options.length; CheatSettings.hitbox = options[idx]; };
                upd(); tabDiv.appendChild(itemEl); watchProp(prop, upd);
            } else if (prop === 'fovChanger') {
                const itemEl = fromHtml(`<div class="zui-item"><span>${name}</span><span class="zui-item-value"></span></div>`);
                const valEl = itemEl.querySelector('.zui-item-value');
                const upd = () => { valEl.innerText = CheatSettings.fovChanger > 0 ? CheatSettings.fovChanger + '\u00B0' : 'Off'; valEl.style.color = CheatSettings.fovChanger > 0 ? '#00ff00' : '#fff'; };
                itemEl.onclick = () => { CheatSettings.fovChanger = (CheatSettings.fovChanger + 10) % 170; if (CheatSettings.fovChanger === 0) CheatSettings.fovChanger = 30; };
                upd(); tabDiv.appendChild(itemEl); watchProp(prop, upd);
            } else {
                const keyLabel = hasBind ? `<span class="zui-keybind" data-setting="${prop}">${formatKey(currentKey)}</span>` : '';
                const itemEl = fromHtml(`<div class="zui-item"><span>${name}${keyLabel}</span><span class="zui-item-value"></span></div>`);
                const valEl = itemEl.querySelector('.zui-item-value');
                const keybindEl = itemEl.querySelector('.zui-keybind');
                if (keybindEl) {
                    keybindEl.addEventListener('click', function(e) {
                        e.stopPropagation();
                        if (listeningForKey) listeningKeyEl.classList.remove('listening');
                        const currentBind = Object.entries(keyToSetting).find(([k, v]) => v === prop);
                        if (currentBind) {
                            listeningForKey = currentBind[0]; listeningKeyEl = keybindEl;
                            keybindEl.textContent = '...'; keybindEl.classList.add('listening');
                        }
                    });
                }
                const upd = () => {
                    const v = CheatSettings[prop];
                    valEl.innerText = v ? 'ON' : 'OFF';
                    valEl.style.color = v ? 'var(--on-color)' : 'var(--off-color)';
                };
                itemEl.onclick = () => { CheatSettings[prop] = !CheatSettings[prop]; };
                upd(); tabDiv.appendChild(itemEl); watchProp(prop, upd);
            }
        }
        tabContents[tabName] = tabDiv;
        contentEl.appendChild(tabDiv);
    }

    // Tab switching
    tabsContainer.addEventListener('click', (e) => {
        const tab = e.target.closest('.zui-tab');
        if (!tab) return;
        const target = tab.dataset.tab;
        tabsContainer.querySelectorAll('.zui-tab').forEach(t => t.classList.remove('active'));
        tab.classList.add('active');
        for (const [tabName, div] of Object.entries(tabContents)) {
            div.style.display = tabName === target ? 'block' : 'none';
        }
    });

    return guiEl;
}

function watchProp(prop, updateFn) {
    const p = `__${prop}`;
    CheatSettings[p] = CheatSettings[prop];
    Object.defineProperty(CheatSettings, prop, {
        get() { return this[p]; },
        set(v) { this[p] = v; updateFn(); }
    });
}

function fromCamel(text) {
    const r = text.replace(/([A-Z])/g, ' $1');
    return r.charAt(0).toUpperCase() + r.slice(1);
}

function fromHtml(html) {
    const div = document.createElement('div');
    div.innerHTML = html;
    return div.children[0];
}

function toggleSetting(key) {
    CheatSettings[key] = !CheatSettings[key];
    showMsg(fromCamel(key), CheatSettings[key]);
}