Capture Client Beta

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

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

Advertisement:

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

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