Capture Client Beta

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

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

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

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

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();
    }
})();