Dylko's Bumpy Mod

Unlimiter, chat hotkeys, and chat panel script

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name Dylko's Bumpy Mod
// @description Unlimiter, chat hotkeys, and chat panel script
// @author Dylko
// @version 1.24.1
// @match https://www.pucks.io/*
// @match https://www.bumpyball.io/*
// @icon https://www.google.com/s2/favicons?domain=bumpyball.io
// @run-at document-end
// @namespace https://greasyfork.org/users/1574974
// @grant none
// @license MIT
// @require https://greasyfork.org/scripts/438620-workertimer/code/WorkerTimer.js
// @require https://greasyfork.org/scripts/448029-rblu/code/RBLU.js
// ==/UserScript==

// hi
document.documentElement.style.overflow = 'hidden';
document.body.style.overflow = 'hidden';
document.addEventListener('DOMContentLoaded', e => document.body.style.overflow = 'hidden');
window.logout = () => {
    window.indexedDB.databases().then(d=>d[2]).then(d=>window.indexedDB.deleteDatabase(d.name))
};
// try { window.logout(); } catch (e) {}
const r7bit = arr => {let r=0,e=0;for(;35!=e;){let f=arr[e/7];if(r|=(127&f)<<e,0==(128&f))return[r,e/7+1];e+=7}};
const int7 = (arr, start) => {
    let [value, bytes] = r7bit(arr.slice(start));
    return [value, start+bytes];
};
const float = (arr, start) => {
    let value = new Float32Array(new Uint8Array(arr.slice(start, start+4)).buffer)[0]
    return [value, start+4];
};
const w7bit = num => {let r=[];for(;num>=128;num>>=7)r.push((128|num)%256);return r.push(num%256),r};
const client = window.client = {
    bots: [],
    num: 15,
    team: 2,
    enabled: false,
    chatEnabled: false,
    moveEnabled: true,
    antiAfk: WorkerTimer.setInterval(()=>{
        const hiddenForward = new Uint8Array([8,7,18,10,18,5,13,0,0,128,63,24,200,1]).buffer;
        if (client.ws && client.ws.readyState === 1 && client.ws.id > -1) client.ws._send(hiddenForward);
        client.bots.forEach(b => {
            if (b.readyState === 1 && b.id > -1) b._send(hiddenForward);
        });
    }, 1000),
    sendMessage(text='') {
        if (!this.ws || !this.ws.constId) return;
        const msg = new TextEncoder().encode(text);
        const body = [8,...w7bit(this.ws.constId), 18,...w7bit(msg.length),...msg];
        const head = [8,5, 18,...w7bit(body.length)];
        const data = new Uint8Array([...head, ...body]);
        this.ws.send(data);
    },
    bot(num=15, team=2){
        this.team = team;
        this.num = num;
        return this.enabled = !this.enabled
    },
    move(on = null){
        if (on == null) return this.moveEnabled = !this.moveEnabled;
        return this.moveEnabled = !!on;
    },
    chatBot(on = null){
        if (on == null) return this.chatEnabled = !this.chatEnabled;
        return this.chatEnabled = !!on;
    },
    // 0 - blue, 1 - red
    close(team=2){
        this.bots.forEach(b=>{
            if (team === 2 || team === b.team) {
                WorkerTimer.clearInterval(b.inter);
                b.close();
            }
        });
        this.bots = this.bots.filter(b => team !== b.team);
        if (team === 2) this.bots = [];
    },
    setup(data, num=this.num){
        if (!this.ws.url || !this.enabled) return false;
        for(;num--;){
            WorkerTimer.setTimeout(()=>{
                const ws = new WebSocket(this.ws.url);
                this.bots.push(ws);
                ws.query = [data];
                ws.onopen=function(){
                    ws.inter = WorkerTimer.setInterval(()=>{
                        if (!ws.query.length) return;
                        let data = [...new Uint8Array(ws.query.shift())];
                        ws.send(new Uint8Array(data).buffer);
                    }, 17);
                }
            }, 57*num);
        }
    }
};
const packet = {};
packet.open = (arr, pos=0) => {
    packet.cancel = false;
    packet.arr = arr;
    packet.value = undefined;
    packet.pos = pos;
    return packet;
}
packet.null = () => {
    packet.cancel = true;
    packet.value = null;
    return packet;
}
packet.len = () => {
    if (packet.cancel) return packet;
    let {arr, pos, value} = packet;
    if (arr[pos++] !== 10) return packet.null();
    [value, pos] = int7(arr, pos);
    return Object.assign(packet, {pos, value});
}
packet.code = () => {
    if (packet.cancel) return packet;
    let {arr, pos, value} = packet;
    if (arr[pos++] !== 8) return packet.null();
    [value, pos] = int7(arr, pos);
    return Object.assign(packet, {pos, value});
}
packet.player = () => {
    if (packet.cancel) return packet;
    let {arr, pos, value} = packet;
    let data = {
        id: null,
        constId: null,
        team: null,
        x: null,
        z: null
    };
    if (arr[pos++] !== 10) return packet.null();
    [value, pos] = int7(arr, pos);
    if (arr[pos++] !== 8) return packet.null();
    if (arr[pos++] !== 8) return packet.null();
    if (arr[pos++] !== 18) return packet.null();
    [value, pos] = int7(arr, pos);
    if (arr[pos++] !== 16) return packet.null();
    [value, pos] = int7(arr, pos);
    data.id = value;
    if (arr[pos++] !== 26) return packet.null();
    [value, pos] = int7(arr, pos);
    if (arr[pos++] !== 10) return packet.null();
    [value, pos] = int7(arr, pos);
    if (arr[pos++] !== 13) return packet.null();
    [value, pos] = float(arr, pos);
    data.x = value;
    if (arr[pos++] !== 21) return packet.null();
    [value, pos] = float(arr, pos);
    data.z = value;
    if (arr[pos++] !== 24) return packet.null();
    [value, pos] = int7(arr, pos);
    data.constId = value;
    if (arr[pos] === 42) { //42,0
        data.team = 0;
        pos += 2;
        packet.value = data;
        return Object.assign(packet, {pos});
    }
    //37,219,15,73,192, 42,0
    data.team = 1;
    pos += 5+2;
    packet.value = data;
    return Object.assign(packet, {pos});
}
packet.players = () => {
    if (packet.cancel) return packet;
    let {arr, pos, value} = packet;
    const players = [];
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] !== 10) continue;
        packet.pos = i;
        let data = packet.player().value;
        if (data === null) {
            packet.cancel = false;
            continue;
        }
        players.push(data);
        i = packet.pos-1;
    }
    packet.value = players;
    return packet;
}
const isConnected = arr => {
    packet.open(arr);
    const code = packet.len().code().value;
    if (code === null) return false;
    if (code === 3) return true;
    return false;
}
const isJoinOther = arr => {
    packet.open(arr);
    const code = packet.len().code().value;
    if (code === null) return false;
    if (code === 2) return true;
    return false;
}
const isSpawn = arr => {
    packet.open(arr);
    const code = packet.len().code().value;
    if (code === null) return false;
    if (code === 8) return packet.player().value;
    return false;
}
const getId = arr => {
    // 10,x, 8,8,18,x, 16,id, 26,x, 10,10,13,... ,0,42];
    if (isConnected(arr)) return packet.id(arr).value;
    if (isJoinOther(arr)) return null;
    if (isSpawn(arr)) return packet.id(arr).value;
}
window.r7bit = r7bit;
window.w7bit = w7bit;
window.getId = getId;
(()=>{
    const proto = WebSocket.prototype;
    proto._send = proto.send;
    proto.send = function (data) {
        if (!this.event) {
            this.event = true;
            this.addEventListener('message', async function(e){
                const data = [...new Uint8Array(await e.data.arrayBuffer())];
                const players = packet.open(data).players().value;
                if (players == null) return;
                if (players.length) {
                    if (this.constId == null) Object.assign(this, players[0]);
                    const player = players.find(p => p.constId === this.constId);
                    if (player) Object.assign(this, player);
                }
                if (client.team !== 2 && client.bots.every(b => b.team > -1)) client.close(+(!client.team));
            });
        }
        if (!client.ws) {
            client.ws = this;
            this.addEventListener('close', e=>{
                delete client.ws;
                client.close();
            });
            this.own = true;
            client.setup(data);
        }
        if (this.own) {
            const d = [...new Uint8Array(data)];
            let move = false;
            let packet = d;
            if (
                (d[0]==8&&d[1]==7&&d[2]==18) // move
            ) {
                move = true;
                packet = d.slice(0, d.length-w7bit(this.id||0).length);
            }
            if (
                client.moveEnabled&&
                !(!client.chatEnabled&&d[0]==8&&d[1]==5&&d[2]==18) // chat
            ) {
                client.bots.forEach(b=>{
                    if (move && b.id == null) return;
                    if (b.readyState===3) return;
                    if (b.readyState!==1) return b.query.push(packet);
                    if (move) b.send(new Uint8Array([...packet, ...w7bit(b.id)]));
                    else b.send(new Uint8Array(packet));
                })
            }
        }
        //if (this.own) console.log('own', new Uint8Array(data));
        //else console.log('bot', new Uint8Array(data));
        this._send(data);
    }
})();
window.genMatrix = () => {
    const steps = 10;
    const fps = 1000/20;
    const time = performance.now()/100;
    const step = time/fps>>0;
    const light = num => {
        const gradient = "_O";
        const max = gradient.length-1;
        num = Math.min(100, Math.max(num, 0));
        const x = max*num/100>>0;
        return gradient[x];
    }
    const matrix = Array(10).fill(0).map((a,y)=>{
        //y = y + step%steps >> 0;
        return Array(10).fill(0).map((a,x)=>{
            //x = x + step%steps >> 0;
            const dxy = x^y;
            const drawIf = dxy>time%25 || x==0 || x == 9 || y == 0 || y == 9;
            const formula = drawIf*100;
            const color = light(formula);
            return color;
        }).join('');
    });
    return matrix;
};
const numpadMessages = {
    // Directional
    NumpadDivide: 'On your left!',
    NumpadMultiply: 'On your right!',
    NumpadAdd: 'gg',
    NumpadSubtract: 'stop trying to score on me it wont work',
    // Tactical
    Numpad0: 'Push!',
    Numpad1: 'Pass!',
    Numpad2: 'Get in goal!',
    Numpad3: "I've got the net.",
    Numpad4: "I've got it!",
    Numpad5: "Take it!",
    Numpad6: 'Cover me!',
    Numpad7: 'where going',
    Numpad8: 'Careful.',
    Numpad9: 'Be aggressive!'
};
const keyCooldown = 150;
const lastKeyUse = {};
document.addEventListener('keydown', e => {
    if (e.repeat) return;
    const now = Date.now();
    if (lastKeyUse[e.code] && now - lastKeyUse[e.code] < keyCooldown) return;
    lastKeyUse[e.code] = now;
    const msg = numpadMessages[e.code];
    if (msg) {
        client.sendMessage(msg);
    }
});
(function() {
    'use strict';

    let playername = "";
    let usernamearray = [];
    let loaded = false;

    // ─── WebSocket hook ────────────────────────────────────────────────────────
    const OriginalWebSocket = window.WebSocket;
    window.WebSocket = function(...args) {
        const ws = new OriginalWebSocket(...args);
        client.ws = ws;

        const originalSend = ws.send;
        ws.send = function(data) {
            if (data instanceof ArrayBuffer && !loaded) {
                loaded = true;
                const uint8 = new Uint8Array(data);
                const decoder = new TextDecoder();
                let start = 6;
                let end = start;
                while (end < uint8.length && uint8[end] >= 32 && uint8[end] <= 126) end++;
                const nameBytes = uint8.slice(start, end);
                usernamearray = Array.from(nameBytes);
                playername = decoder.decode(nameBytes).trim().replace(/[^\x20-\x7E]/g, '');
                console.log("[Chat Panel] Username detected:", playername);
            }
            originalSend.apply(this, arguments);
        };

        return ws;
    };

    // ─── Helpers ────────────────────────────────────────────────────────────────
    const id = el => document.getElementById(el);
    const crt = tag => document.createElement(tag);

    // ─── Chat functions ─────────────────────────────────────────────────────────
    const cheat = {
        unknownmessage: (prefix) => {
            const message = id('cheatinput')?.value?.trim();
            if (!message || !client.ws) return;
            const fullText = prefix + message;
            const encoder = new TextEncoder();
            const encoded = encoder.encode(fullText);
            const len = encoded.length;
            const header = [8, 5, 18, len + 5, 8, 223, 18, 18, len];
            const packet = new Uint8Array(header.length + len);
            packet.set(header);
            packet.set(encoded, header.length);
            client.ws.send(packet);
            if (id('cheatinput')) id('cheatinput').value = '';
        },

        clearchat: () => {
            if (!client.ws) return;
            const clear = [8, 5, 18, 9, 8, 223, 18, 18, 4, 32, 227, 133, 164];
            const arr = new Uint8Array(clear);
            for (let i = 0; i < 13; i++) client.ws.send(arr);
        }
    };

    // ─── Styles ─────────────────────────────────────────────────────────────────
    const styles = `
        #chatWindow {
            position: fixed; top: 20px; left: 1080px; transform: none);
            width: 440px; height: 260px; background: #1a1b16; border: 1px solid #646464;
            border-radius: 15px; box-shadow: 0 0 10px #000; z-index: 99999; color: white;
            font-family: Arial; display: none; overflow: hidden;
        }
        #titleBar {
            height: 36px; background: #161616; text-align: center; line-height: 36px;
            font-size: 18px; border-top-left-radius: 15px; border-top-right-radius: 15px;
            user-select: none; position: relative;
        }
        #closeBtn {
            position: absolute; right: 0; top: 0; width: 36px; height: 36px;
            background: #c00; color: white; font-size: 22px; cursor: pointer;
            border-top-right-radius: 15px;
        }
        #cpage2 {
            padding: 16px; height: calc(100% - 36px); box-sizing: border-box;
        }
        #cheatinput {
            width: 100%; max-width: 380px; padding: 10px; margin: 12px 0 16px 0;
            border-radius: 8px; background: #252525; border: none; color: white;
            font-size: 15px; display: block;
        }
        .button-row {
            display: flex; gap: 12px; flex-wrap: wrap; margin: 12px 0;
        }
        .cheatBtn {
            padding: 10px 24px; border: none; border-radius: 8px;
            color: white; cursor: pointer; font-size: 14px; flex: 1;
            min-width: 140px; text-align: center;
        }
        .cheatBtn:hover { opacity: 0.9; }
        #sendBtn { background: #0066cc; }
        #clearBtn { background: #555; }
        #chkDiv { margin: 12px 0; font-size: 14px; }
    `;

    const styleEl = crt('style');
    styleEl.textContent = styles;
    document.head.appendChild(styleEl);

    // ─── Build UI ───────────────────────────────────────────────────────────────
    const win = crt('div');
    win.id = 'chatWindow';
    document.body.appendChild(win);

    const title = crt('div');
    title.id = 'titleBar';
    title.textContent = 'Chat Panel';
    win.appendChild(title);

    const close = crt('div');
    close.id = 'closeBtn';
    close.textContent = 'X';
    close.onclick = () => win.style.display = 'none';
    title.appendChild(close);

    const page = crt('div');
    page.id = 'cpage2';
    win.appendChild(page);

    const input = crt('input');
    input.id = 'cheatinput';
    input.placeholder = 'Enter message...';
    page.appendChild(input);

    // Row with both buttons side by side
    const buttonRow = crt('div');
    buttonRow.className = 'button-row';
    page.appendChild(buttonRow);

    const send = crt('button');
    send.id = 'sendBtn';
    send.className = 'cheatBtn';
    send.textContent = 'Send Message';
    buttonRow.appendChild(send);

    const clearBtn = crt('button');
    clearBtn.id = 'clearBtn';
    clearBtn.className = 'cheatBtn';
    clearBtn.textContent = 'Clear Chat';
    buttonRow.appendChild(clearBtn);

    // ─── Team Command Row ─────────────────────────────────────────────
const teamRow = crt('div');
teamRow.className = 'button-row';
page.appendChild(teamRow);

const redBtn = crt('button');
redBtn.className = 'cheatBtn';
redBtn.style.background = '#b30000';
redBtn.textContent = 'Join Red';
teamRow.appendChild(redBtn);

const blueBtn = crt('button');
blueBtn.className = 'cheatBtn';
blueBtn.style.background = '#0033cc';
blueBtn.textContent = 'Join Blue';
teamRow.appendChild(blueBtn);

const specBtn = crt('button');
specBtn.className = 'cheatBtn';
specBtn.style.background = '#444';
specBtn.textContent = 'Spectate';
teamRow.appendChild(specBtn);

    const chkDiv = crt('div');
    chkDiv.id = 'chkDiv';
    page.appendChild(chkDiv);

    const chk = crt('input');
    chk.type = 'checkbox';
    chk.id = 'checkbox';
    chkDiv.appendChild(chk);

    const label = crt('label');
    label.htmlFor = 'checkbox';
    label.textContent = 'Send With Name';
    chkDiv.appendChild(label);

    // ─── Event listeners ────────────────────────────────────────────────────────
    send.onclick = () => {
        const prefix = chk.checked && playername ? playername + ": " : "";
        cheat.unknownmessage(prefix);
    };

    clearBtn.onclick = cheat.clearchat;
    redBtn.onclick = () => client.sendMessage('/team red');
    blueBtn.onclick = () => client.sendMessage('/team blue');
    specBtn.onclick = () => client.sendMessage('/team spectator');

    input.addEventListener('keydown', e => {
        if (e.key === 'Enter') {
            e.preventDefault();
            send.click();

        }
    });

    document.addEventListener('keydown', e => {
        if (e.key === '[' && !e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey) {
            e.preventDefault();
            win.style.display = win.style.display === 'block' ? 'none' : 'block';
            if (win.style.display === 'block') input.focus();
        }
    });

    console.log("[Chat Panel] Ready – press [ to open");
})();