Capture Client Beta

Access local variables and more fun features. Shift + L (VM), Shift + Y (Tweaks). Hook by ginger

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Advertisement:

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

Advertisement:

// ==UserScript==
// @name         Capture Client Beta
// @version      1.3
// @description  Access local variables and more fun features. Shift + L (VM), Shift + Y (Tweaks). Hook by ginger
// @author       Цветочек Кактус (timofeycacti)
// @match        https://*.bloxd.io/*
// @namespace    CaptureClient
// @license      CC-BY-2.0
// @icon         https://i.postimg.cc/XJFnxv3m/Capture-Client-v1-(3).png
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // === 1. ОРИГИНАЛЬНЫЙ СЕТЕВОЙ ХУК ===
    let packetDelayActive = false;
    const originalSend = WebSocket.prototype.send;

    WebSocket.prototype.send = function(data) {
        if (packetDelayActive) {
            let isPing = false;
            if (typeof data === 'string') {
                if (data === '{}' || data.includes('ping') || data.length < 15) {
                    isPing = true;
                }
            } else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
                let buffer = data.buffer || data;
                if (buffer.byteLength <= 8) {
                    isPing = true;
                }
            }
            if (!isPing) return;
        }
        return originalSend.apply(this, arguments);
    };

    function initClient() {
        let font = document.createElement('link');
        font.href = 'https://fonts.googleapis.com/css2?family=Lobster&display=swap';
        font.rel = 'stylesheet';
        document.head.appendChild(font);

        let style = document.createElement('style');
        style.textContent = `
        @font-face { font-family: 'Lobster'; }
        @keyframes spin{to{transform:rotate(360deg)}}
        .Crosshair{display:inline-block;animation:spin 1s linear infinite}
        @keyframes hudRotate { from { background-position: 0% 50%; } to { background-position: 100% 50%; } }
        @keyframes flash { 0%, 100% { color:#FFF176 } 50% { color:#660000 } }
        .changed { animation: flash 0.4s ease }
        .vm-item { padding:3px 4px; cursor:pointer; color:#FFF176; white-space:pre-wrap; word-break:break-word; user-select: none; }
        .vm-item:hover { color:#FFFFFF; background:rgba(255,255,255,0.08); }
        .btn { background: rgba(255, 241, 118, 0.15); color: #FFF176; border: 1px solid #FFF176; padding: 5px; margin: 5px 0; text-align: center; cursor: pointer; font-family: monospace; font-weight: bold; user-select: none; transition: background 0.2s, color 0.2s; }
        .btn:hover { background: #FFF176; color: #330000; }
        .btn.active { background: rgba(76, 175, 80, 0.3); color: #4CAF50; border-color: #4CAF50; }
        .btn.active:hover { background: #4CAF50; color: #fff; border-color: #4CAF50; }
        .vm-search-box { display: flex; padding: 4px; background: rgba(0,0,0,0.4); border-bottom: 1px solid rgba(255, 241, 118, 0.3); gap: 4px; }
        .vm-input { flex: 1; background: rgba(0,0,0,0.6); border: 1px solid #FFF176; color: #FFF176; font-family: monospace; font-size: 12px; padding: 2px 4px; outline: none; }
        .vm-checkbox-label { color: #FFF176; font-family: monospace; font-size: 11px; display: flex; align-items: center; gap: 3px; cursor: pointer; user-select: none; }
        .vm-checkbox-label input { cursor: pointer; accent-color: #FFF176; margin: 0; }
        `;
        document.head.appendChild(style);

        let vmOpen = false, vmBox, vmPath = [], vmCurrent;
        let tweaksOpen = false, tweaksBox;
        let vmSearchQuery = '', vmDeepSearchEnabled = false;
        let tracked = JSON.parse(localStorage.getItem('capture_tracked') || '{}');
        let lastValues = {};

        function saveTracked() {
            localStorage.setItem('capture_tracked', JSON.stringify(tracked));
        }

        function makeDraggable(header, box) {
            let isDown = false, ox = 0, oy = 0;
            header.addEventListener('mousedown', e => {
                isDown = true;
                ox = e.clientX - box.offsetLeft;
                oy = e.clientY - box.offsetTop;
            });
            document.addEventListener('mousemove', e => {
                if (isDown) {
                    box.style.left = (e.clientX - ox) + 'px';
                    box.style.top = (e.clientY - oy) + 'px';
                }
            });
            document.addEventListener('mouseup', () => { isDown = false; });
        }

        let trackerBox = document.createElement('div');
        Object.assign(trackerBox.style, {
            position: 'fixed', right: '10px', bottom: '10px', color: '#FFF176',
            fontFamily: 'monospace', fontSize: '12px', zIndex: 99999,
            textAlign: 'right', pointerEvents: 'none', maxWidth: '300px', wordBreak: 'break-word'
        });
        document.body.appendChild(trackerBox);

        function getSafeValue(obj, key) {
            try { return (obj && typeof obj === 'object') ? obj[key] : undefined; } catch { return undefined; }
        }

        function findBloxdCaptured() {
            try {
                let crosshair = document.querySelector(".Crosshair");
                if (!crosshair) return null;

                let reactKey = Object.keys(crosshair).find(key => key.startsWith('__reactFiber$'));
                if (!reactKey) return null;

                let searchFiber = f => f?.memoizedState?.bloxd || searchFiber(f?.next);
                let noa = Object.values(searchFiber(crosshair[reactKey].return.memoizedState))[2];

                return noa;
            } catch (e) {
                return null;
            }
        }

        setInterval(() => {
            if (!window.Captured) return;
            trackerBox.innerHTML = '';
            let entries = Object.entries(tracked);
            for (let i = 0; i < entries.length; i++) {
                let [pathStr, path] = entries[i];
                try {
                    let val = window.Captured;
                    for (let j = 0; j < path.length; j++) {
                        val = getSafeValue(val, path[j]);
                    }
                    let line = document.createElement('div');
                    line.textContent = `${pathStr}: ${val}`;
                    if (lastValues[pathStr] !== undefined && lastValues[pathStr] !== val) {
                        line.className = 'changed';
                    }
                    lastValues[pathStr] = val;
                    trackerBox.appendChild(line);
                } catch {}
            }
        }, 200);

        function setValue(path, val) {
            try {
                let obj = window.Captured;
                for (let i = 0; i < path.length - 1; i++) {
                    obj = getSafeValue(obj, path[i]);
                }
                let key = path[path.length - 1];
                obj[key] = val;
                if (obj[key] !== val) {
                    Object.defineProperty(obj, key, { value: val, writable: true, configurable: true, enumerable: true });
                }
            } catch {}
        }

        function createVmItem(displayKey, value, itemPath) {
            let item = document.createElement('div');
            item.className = 'vm-item';
            let pathStr = itemPath.join('.');

            item.textContent = value === null ? `${displayKey} : null` : typeof value === 'object' ? `${displayKey} >` : `${displayKey} : ${value}`;

            let handleTrack = (e) => {
                e.preventDefault(); e.stopPropagation();
                tracked[pathStr] ? delete tracked[pathStr] : tracked[pathStr] = itemPath;
                saveTracked();
            };

            item.onclick = (e) => {
                if (e.shiftKey) return handleTrack(e);
                e.preventDefault(); e.stopPropagation();

                if (value && typeof value === 'object') {
                    vmPath = [...itemPath];
                    vmUpdate();
                } else if (typeof value === 'boolean') {
                    setValue(itemPath, !value);
                    vmUpdate();
                } else {
                    let input = prompt(`Set ${pathStr}`, value);
                    if (input !== null) {
                        setValue(itemPath, typeof value === 'number' ? Number(input) : input);
                        vmUpdate();
                    }
                }
            };

            item.oncontextmenu = e => { if (e.shiftKey) handleTrack(e); };
            return item;
        }

        function vmRender() {
            let box = vmBox._content;
            box.innerHTML = '';

            if (vmPath.length) {
                let back = document.createElement('div');
                back.textContent = '[..]';
                back.className = 'vm-item';
                back.onclick = (e) => { e.preventDefault(); e.stopPropagation(); vmPath.pop(); vmUpdate(); };
                box.appendChild(back);
            }

            let query = vmSearchQuery.toLowerCase().trim();

            if (query) {
                if (vmDeepSearchEnabled) {
                    let results = [], visited = new Set();
                    let stack = [{ obj: vmCurrent, path: [...vmPath], depth: 0 }];

                    while (stack.length > 0) {
                        let { obj, path, depth } = stack.pop();
                        if (depth > 4 || !obj || typeof obj !== 'object' || visited.has(obj)) continue;
                        visited.add(obj);

                        try {
                            let keys = Object.keys(obj);
                            for (let i = 0; i < keys.length; i++) {
                                let k = keys[i];
                                let p = [...path, k];
                                let val = getSafeValue(obj, k);
                                if (k.toLowerCase().includes(query) || (val !== null && typeof val !== 'object' && String(val).toLowerCase().includes(query))) {
                                    results.push({ keyPath: p, val: val });
                                }
                                if (val && typeof val === 'object') {
                                    stack.push({ obj: val, path: p, depth: depth + 1 });
                                }
                            }
                        } catch {}
                    }

                    if (!results.length) {
                        let empty = document.createElement('div');
                        Object.assign(empty, { className: 'vm-item', textContent: 'No results found...' });
                        empty.style.color = '#660000'; box.appendChild(empty);
                    } else {
                        results.forEach(res => box.appendChild(createVmItem(res.keyPath.slice(vmPath.length).join('.'), res.val, res.keyPath)));
                    }
                } else {
                    Object.keys(vmCurrent || {}).forEach(k => {
                        let val = getSafeValue(vmCurrent, k);
                        if (k.toLowerCase().includes(query) || (val !== null && typeof val !== 'object' && String(val).toLowerCase().includes(query))) {
                            box.appendChild(createVmItem(k, val, [...vmPath, k]));
                        }
                    });
                }
            } else {
                Object.keys(vmCurrent || {}).forEach(k => {
                    box.appendChild(createVmItem(k, getSafeValue(vmCurrent, k), [...vmPath, k]));
                });
            }
        }

        function vmUpdate() {
            try {
                let val = window.Captured;
                for (let i = 0; i < vmPath.length; i++) {
                    val = getSafeValue(val, vmPath[i]);
                }
                vmCurrent = val;
            } catch { vmPath = []; vmCurrent = window.Captured; }
            vmRender();
        }

        function setupUiIsolation(el) {
            ['mousedown', 'mouseup', 'click', 'contextmenu'].forEach(evt => {
                el.addEventListener(evt, e => {
                    if (!e.target.closest('[style*="cursor: move"]') && !e.shiftKey) e.stopPropagation();
                });
            });
        }

        function vmToggle() {
            vmOpen = !vmOpen;
            if (vmOpen) {
                vmBox = document.createElement('div');
                Object.assign(vmBox.style, {
                    position: 'fixed', top: '20px', left: '20px', width: '320px', color: '#FFF176', zIndex: 99999,
                    border: '2px solid #FFF176', background: 'linear-gradient(270deg,#330000,#000,#330000)',
                    backgroundSize: '400% 400%', animation: 'hudRotate 8s linear infinite', display: 'flex', flexDirection: 'column'
                });

                let header = document.createElement('div');
                header.textContent = 'Capture Client';
                Object.assign(header.style, { background: '#FFF176', color: '#330000', padding: '5px', cursor: 'move', textAlign: 'center', fontFamily: 'Lobster' });

                let searchBar = document.createElement('div');
                searchBar.className = 'vm-search-box';

                let input = document.createElement('input');
                Object.assign(input, { type: 'text', className: 'vm-input', placeholder: 'Search keys or values...', value: vmSearchQuery });
                ['keydown', 'keyup', 'keypress'].forEach(evt => input.addEventListener(evt, e => e.stopPropagation()));
                input.addEventListener('input', e => { vmSearchQuery = e.target.value; vmRender(); });

                let label = document.createElement('label');
                label.className = 'vm-checkbox-label';
                let checkbox = document.createElement('input');
                Object.assign(checkbox, { type: 'checkbox', checked: vmDeepSearchEnabled });
                checkbox.addEventListener('change', e => { vmDeepSearchEnabled = e.target.checked; vmRender(); });
                label.append(checkbox, "Deep");
                searchBar.append(input, label);

                let content = document.createElement('div');
                Object.assign(content.style, { padding: '5px', overflow: 'auto', maxHeight: '320px', fontFamily: 'monospace' });

                vmBox.append(header, searchBar, content);
                document.body.appendChild(vmBox);
                vmBox._content = content;
                vmPath = []; vmUpdate();
                makeDraggable(header, vmBox);
                setupUiIsolation(vmBox);
            } else vmBox.remove();
        }

        function getExportGeometry() {
            let targetScene = null;
            let visited = new Set();
            let stack = [{ obj: window, depth: 0 }];

            while (stack.length > 0) {
                let { obj, depth } = stack.pop();
                if (depth > 5 || !obj || typeof obj !== 'object' || visited.has(obj)) continue;
                visited.add(obj);

                if (obj._isScene && obj.meshes) {
                    targetScene = obj;
                    break;
                }
                try {
                    let keys = Object.keys(obj);
                    for (let i = 0; i < keys.length; i++) {
                        stack.push({ obj: obj[keys[i]], depth: depth + 1 });
                    }
                } catch {}
            }

            if (!targetScene && window.Captured) {
                targetScene = window.Captured.scene || window.Captured.engine?.scenes?.[0];
            }
            if (!targetScene) return null;

            let meshes = targetScene.meshes || [];
            let allVertices = [], allFaces = [], vertexOffset = 0;

            meshes.forEach((mesh) => {
                if (!mesh || typeof mesh.isEnabled !== 'function' || !mesh.isEnabled()) return;
                let meshName = (mesh.name || "").toLowerCase();
                if (!meshName.includes("chunk") && !meshName.includes("render") && !meshName.includes("terrain")) return;
                if (['sky', 'shadow', 'ui', 'menu', 'atmosphere'].some(w => meshName.includes(w))) return;

                let geom = mesh._geometry || mesh.geometry;
                if (!geom) return;

                let positions = geom._positions || geom.positions || (mesh.getVerticesData ? mesh.getVerticesData("position") : null);
                let indices = geom._indices || geom.indices || (mesh.getIndices ? mesh.getIndices() : null);
                if (!positions || !indices || positions.length < 12) return;

                let dx = 0, dy = 0, dz = 0, useMatrix = false;
                let m = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
                let wm = mesh.getWorldMatrix ? mesh.getWorldMatrix() : mesh._worldMatrix;
                if (wm) {
                    let raw = typeof wm.asArray === 'function' ? wm.asArray() : (wm._m || wm);
                    if (raw && !isNaN(raw[12])) { m = raw; useMatrix = true; }
                }
                if (!useMatrix) {
                    dx = mesh.position?.x || mesh.chunkX || 0;
                    dy = mesh.position?.y || mesh.chunkY || 0;
                    dz = mesh.position?.z || mesh.chunkZ || 0;
                }

                let cx = mesh.chunkX || dx || 0, cz = mesh.chunkZ || dz || 0;
                let r = Math.abs(Math.sin(cx * 0.05)) * 0.6 + 0.2;
                let g = Math.abs(Math.cos(cz * 0.05)) * 0.6 + 0.3;
                let b = Math.abs(Math.sin((cx + cz) * 0.03)) * 0.5 + 0.5;

                for (let i = 0; i < indices.length; i += 3) {
                    let i1 = indices[i], i2 = indices[i+1], i3 = indices[i+2];
                    [i1, i2, i3].forEach(idx => {
                        let x = positions[idx * 3], y = positions[idx * 3 + 1], z = positions[idx * 3 + 2];
                        let rx, ry, rz;
                        if (useMatrix) {
                            rx = x * m[0] + y * m[4] + z * m[8] + m[12];
                            ry = x * m[1] + y * m[5] + z * m[9] + m[13];
                            rz = x * m[2] + y * m[6] + z * m[10] + m[14];
                        } else {
                            rx = x + dx; ry = y + dy; rz = z + dz;
                        }
                        allVertices.push({x: rx, y: ry, z: rz, r: Math.floor(r*255), g: Math.floor(g*255), b: Math.floor(b*255)});
                    });
                    allFaces.push([vertexOffset, vertexOffset + 1, vertexOffset + 2]);
                    vertexOffset += 3;
                }
            });
            return { vertices: allVertices, faces: allFaces };
        }

        const tweaksConfig = {
            forceInject: {
                name: 'Force Inject',
                type: 'action',
                callback: () => {
                    let cap = findBloxdCaptured();
                    if (cap) {
                        window.Captured = cap;
                        if (vmOpen) vmUpdate();
                    }
                }
            },
            toggleLag: {
                name: 'Packet Lag: OFF',
                type: 'action',
                callback: function() {
                    packetDelayActive = !packetDelayActive;
                    this.name = `Packet Lag: ${packetDelayActive ? 'ON' : 'OFF'}`;
                    let buttons = document.querySelectorAll('.btn');
                    buttons.forEach(btn => {
                        if (btn.textContent.includes('Packet Lag')) {
                            btn.textContent = this.name;
                            btn.classList.toggle('active', packetDelayActive);
                        }
                    });
                }
            },
            exportObj: {
                name: 'Export OBJ',
                type: 'action',
                callback: () => {
                    let geomData = getExportGeometry();
                    if (!geomData || geomData.vertices.length === 0) return;

                    let objLines = ["# Bloxd.io Wireframe\n# Format: OBJ XYZRGB\n"];
                    geomData.vertices.forEach(v => {
                        objLines.push(`v ${v.x.toFixed(4)} ${v.y.toFixed(4)} ${v.z.toFixed(4)} ${(v.r / 255).toFixed(4)} ${(v.g / 255).toFixed(4)} ${(v.b / 255).toFixed(4)}`);
                    });
                    objLines.push("g map_mesh");
                    geomData.faces.forEach(f => {
                        objLines.push(`f ${f[0]+1} ${f[1]+1} ${f[2]+1}`);
                    });

                    let blob = new Blob([objLines.join("\n")], { type: "text/plain" });
                    let url = URL.createObjectURL(blob);
                    let a = document.createElement("a");
                    a.href = url;
                    a.download = "bloxd_wireframe_colors.obj";
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                }
            },
            allCraft: {
                name: 'All Craft',
                type: 'action',
                callback: () => {
                    try {
                        Object.values(window.Captured.bloxd.craftingManager.playerRecipes[1] || {}).forEach(arr => {
                            if (Array.isArray(arr)) arr.forEach(o => { if (o) delete o.station; });
                        });
                    } catch {}
                }
            },
            defineAll: {
                name: 'Define All',
                type: 'action',
                callback: () => {
                    try {
                        let visited = new Set();
                        let stack = [{ obj: window.Captured, depth: 0 }];
                        let found = null;

                        while (stack.length > 0) {
                            let { obj, depth } = stack.pop();
                            if (depth > 4 || !obj || typeof obj !== 'object' || visited.has(obj)) continue;
                            visited.add(obj);

                            if (obj.hasOwnProperty('playerZoom')) {
                                found = obj;
                                break;
                            }
                            let keys = Object.keys(obj);
                            for (let i = 0; i < keys.length; i++) {
                                stack.push({ obj: obj[keys[i]], depth: depth + 1 });
                            }
                        }
                        if (found) {
                            window.Captured.cBloxdStats = found;
                            if (vmOpen) vmUpdate();
                        }
                    } catch {}
                }
            },
            resetAcc: {
                name: 'Reset Acc',
                type: 'action',
                callback: () => {
                    try {
                        [".bloxd.io", location.hostname, ""].forEach(d => {
                            document.cookie = `__Secure-3PSIDMC=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;${d ? ` domain=${d};` : ''} Secure; SameSite=None`;
                        });
                        location.reload();
                    } catch {}
                }
            }
        };

        function renderTweaks() {
            let content = tweaksBox._content;
            content.innerHTML = '';
            Object.keys(tweaksConfig).forEach(key => {
                let tweak = tweaksConfig[key];
                let btn = document.createElement('div');
                btn.className = 'btn';
                if (key === 'toggleLag' && packetDelayActive) {
                    btn.className = 'btn active';
                    btn.textContent = `Packet Lag: ON`;
                } else {
                    btn.textContent = tweak.name;
                }
                btn.onclick = (e) => { e.preventDefault(); e.stopPropagation(); tweak.callback.call(tweak); };
                content.appendChild(btn);
            });
        }

        function tweaksToggle() {
            tweaksOpen = !tweaksOpen;
            if (tweaksOpen) {
                tweaksBox = document.createElement('div');
                Object.assign(tweaksBox.style, {
                    position: 'fixed', top: '20px', right: '20px', width: '220px', color: '#FFF176', zIndex: 99999,
                    border: '2px solid #FFF176', background: 'linear-gradient(270deg,#330000,#000,#330000)',
                    backgroundSize: '400% 400%', animation: 'hudRotate 8s linear infinite', display: 'flex', flexDirection: 'column'
                });

                let header = document.createElement('div');
                header.textContent = 'Tweaks';
                Object.assign(header.style, { background: '#FFF176', color: '#330000', padding: '5px', cursor: 'move', textAlign: 'center', fontFamily: 'Lobster' });

                let content = document.createElement('div');
                content.style.padding = '5px';
                tweaksBox._content = content;
                tweaksBox.append(header, content);
                document.body.appendChild(tweaksBox);
                renderTweaks();
                makeDraggable(header, tweaksBox);
                setupUiIsolation(tweaksBox);
            } else tweaksBox.remove();
        }

        document.addEventListener('keydown', e => {
            if (e.target.tagName !== 'INPUT' && e.shiftKey) {
                if (e.code === 'KeyL') vmToggle();
                if (e.code === 'KeyY') tweaksToggle();
            }
        });

        let checker = setInterval(() => {
            let cap = findBloxdCaptured();
            if (cap) {
                window.Captured = cap;
                clearInterval(checker);
                let crosshair = document.querySelector(".Crosshair");
                if (crosshair) crosshair.innerText = "x";
                if (vmOpen) vmUpdate();
            }
        }, 1000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initClient);
    } else {
        initClient();
    }
})();