Drawaria Epic Autodraw bot V2

Autodraw bot with dots.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Drawaria Epic Autodraw bot V2
// @namespace    http://tampermonkey.net/
// @version      2025-05-11
// @description  Autodraw bot with dots.
// @author       YouTubeDrawaria
// @license      MIT
// @include      https://drawaria.online*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const EL = (sel) => document.querySelector(sel);
    const ELL = (sel) => document.querySelectorAll(sel);

    // Drawing Tools
    let drawing_active = false;
    let previewCanvas = document.createElement('canvas');
    let originalCanvas = document.getElementById('canvas');
    var data;

    let cw = previewCanvas.width;
    let ch = previewCanvas.height;

    let executionLine = [];
    let rainMode = true; // Режим "дождика" включен по умолчанию
    let rainColumns = []; // Массив для хранения колонок

    // Room & Socket Control
    window.myRoom = {};
    window.sockets = [];

    const originalSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (...args) {
        if (window.sockets.indexOf(this) === -1) {
            window.sockets.push(this);
            if (window.sockets.indexOf(this) === 0) {
                this.addEventListener('message', (event) => {
                    let message = String(event.data);
                    if (message.startsWith('42')) {
                        let payload = JSON.parse(message.slice(2));
                        if (payload[0] == 'bc_uc_freedrawsession_changedroom') {
                            window.myRoom.players = payload[3];
                        }
                        if (payload[0] == 'mc_roomplayerschange') {
                            window.myRoom.players = payload[3];
                        }
                    } else if (message.startsWith('41')) {
                        // this.send(40)
                    } else if (message.startsWith('430')) {
                        let configs = JSON.parse(message.slice(3))[0];
                        window.myRoom.players = configs.players;
                        window.myRoom.id = configs.roomid;

                        // Автоматически начинаем рисование при подключении
                        if (rainMode) {
                            setTimeout(() => {
                                let size = document.getElementById('engine_imagesize').value;
                                let modifier = document.getElementById('engine_pixelsize').value;
                                let thickness = document.getElementById('engine_brushsize').value;
                                let offset = {
                                    x: document.getElementById('engine_offset_x').value,
                                    y: document.getElementById('engine_offset_y').value,
                                };
                                drawImage(size, modifier, thickness, offset);
                                execute(window['___BOT'].conn.socket);
                            }, 3000);
                        }
                    }
                });
            }
        }
        return originalSend.call(this, ...args);
    };

    // Добавляем стили и интерфейс
    function addBoxIcons() {
        let boxicons = document.createElement('link');
        boxicons.href = 'https://unpkg.com/[email protected]/css/boxicons.min.css';
        boxicons.rel = 'stylesheet';
        document.head.appendChild(boxicons);
    }

    function CreateStylesheet() {
        let container = document.createElement('style');
        container.innerHTML =
            'input[type="number"] { text-align: center; -webkit-appearance: none; -moz-appearance: textfield; } ' +
            '.hidden { display: none; } ' +
            '.cheat-row { display:flex; width:100%; } ' +
            '.cheat-row > * { width:100%; } ' +
            '.cheat-border { width: 100%; text-align: center; line-height: inherit; margin: 1px; border: 1px solid coral; } ' +
            '.rain-toggle { background-color: #4CAF50; color: white; }';
        document.head.appendChild(container);
    }

    function Engine() {
        let CheatContainer = document.createElement('div');
        CheatContainer.id = 'Engine-Cheatcontainer';
        CheatContainer.classList.toggle('hidden');
        document.getElementById('chatbox_messages').after(CheatContainer);

        function CreateToggleButton(Cheatcontainer) {
            let target = document.getElementById('chatbox_textinput');
            let btncontainer = document.createElement('div');
            btncontainer.id = 'togglecheats';
            btncontainer.className = 'input-group-append';

            let togglebtn = document.createElement('button');
            togglebtn.className = 'btn btn-outline-secondary';
            togglebtn.innerHTML = '<i class="bx bx-bot"></i>';
            togglebtn.addEventListener('click', (e) => {
                e.preventDefault();
                togglebtn.classList.toggle('active');
                Cheatcontainer.classList.toggle('hidden', !togglebtn.classList.contains('active'));
            });
            btncontainer.appendChild(togglebtn);
            target.after(btncontainer);
        }
        CreateToggleButton(CheatContainer);

        function ImageLoader(CheatContainer) {
            let container = document.createElement('div');
            let row = document.createElement('div');
            row.className = 'cheat-row';

            let IPutImage = document.createElement('input');
            IPutImage.type = 'file';
            IPutImage.id = 'IPutImage';
            IPutImage.className = 'cheat-border';

            function readImage() {
                if (!this.files || !this.files[0]) return;

                const FR = new FileReader();
                FR.addEventListener('load', (evt) => {
                    loadImage(evt.target.result);
                });
                FR.readAsDataURL(this.files[0]);
            }

            IPutImage.addEventListener('change', readImage);
            row.appendChild(IPutImage);
            container.appendChild(row);
            CheatContainer.appendChild(container);
        }
        ImageLoader(CheatContainer);

        function BotControl(CheatContainer) {
            let container = document.createElement('div');
            container.innerHTML =
                "<div><input type='text' id='inputName' style='width:100%' placeholder='Name of Bot'></div><div class='cheat-row'><i class='bx bx-user-plus cheat-border' id='botJoin'><span>Join</span></i><i class='bx bx-user-minus cheat-border' id='botLeave'><span>Leave</span></i><i class='bx bxs-eraser cheat-border' id='canvasClear'><span>Clear</span></i></div>";

            CheatContainer.appendChild(container);
            document.getElementById('botJoin').addEventListener('mousedown', (e) => {
                window['___BOT'].room.join(EL('#invurl').value);
            });
            document.getElementById('botLeave').addEventListener('mousedown', (e) => {
                window['___BOT'].conn.socket.close();
            });
            document.getElementById('canvasClear').addEventListener('mousedown', (e) => {
                window['___BOT'].action.DrawLine(50, 50, 50, 50, 2000);
            });
        }
        BotControl(CheatContainer);

        function DrawingControls(CheatContainer) {
            let container = document.createElement('div');
            container.innerHTML = [
                '<div class="cheat-row"><input type="number" id="engine_imagesize" min="0" max="10" value="1" title="Image Size. 1 = big. 10 = small"><input type="number" id="engine_brushsize" min="2" max="30" value="32" title="Your Brush Size"><input type="number" id="engine_pixelsize" min="2" max="30" value="25" title="Distance between Pixels\nBest use half of brushsize"><input type="number" id="engine_offset_x" min="0" max="100" value="0" title="Distance left"><input type="number" id="engine_offset_y" min="0" max="100" value="0" title="Distance top"></div>',
                '<div class="cheat-row"><i class="bx bx-play-circle cheat-border" id="botStartDrawing"><span>Start</span></i><i class="bx bx-stop-circle cheat-border" id="botStopDrawing"><span>Stop</span></i><i class="bx bx-cloud-rain cheat-border rain-toggle" id="toggleRainMode"><span>Rain Mode</span></i></div>',
            ].join('');
            CheatContainer.appendChild(container);

            document.getElementById('botStopDrawing').addEventListener('mousedown', (e) => {
                drawing_active = false;
            });

            document.getElementById('botStartDrawing').addEventListener('mousedown', (e) => {
                let size = document.getElementById('engine_imagesize').value;
                let modifier = document.getElementById('engine_pixelsize').value;
                let thickness = document.getElementById('engine_brushsize').value;
                let offset = {
                    x: document.getElementById('engine_offset_x').value,
                    y: document.getElementById('engine_offset_y').value,
                };
                drawImage(size, modifier, thickness, offset);
                execute(window['___BOT'].conn.socket);
            });

            document.getElementById('toggleRainMode').addEventListener('mousedown', (e) => {
                rainMode = !rainMode;
                e.target.classList.toggle('rain-toggle', rainMode);
            });
        }
        DrawingControls(CheatContainer);
    }

    function loadImage(url) {
        var img = new Image();
        img.addEventListener('load', () => {
            previewCanvas.width = originalCanvas.width;
            previewCanvas.height = originalCanvas.height;

            cw = previewCanvas.width;
            ch = previewCanvas.height;

            var ctx = previewCanvas.getContext('2d');

            let modifier = 1;
            if (img.width > previewCanvas.width) {
                modifier = previewCanvas.width / img.width;
            } else {
                modifier = previewCanvas.height / img.height;
            }

            ctx.drawImage(img, 0, 0, img.width * modifier, img.height * modifier);

            var imgData = ctx.getImageData(0, 0, previewCanvas.width, previewCanvas.height);
            data = imgData.data;

            ctx.clearRect(0, 0, previewCanvas.width, previewCanvas.height);
            console.debug('Image loaded and ready');
        });
        img.crossOrigin = 'anonymous';
        img.src = url;
    }

    function drawImage(size, modifier = 1, thickness = 5, offset = { x: 0, y: 0 }, ignorcolors = []) {
        executionLine = [];
        rainColumns = [];

        // Сначала собираем все колонки
        for (let x = 0; x < cw; x += size * modifier) {
            let columnPixels = [];

            // Собираем все пиксели в текущем столбце
            for (let y = 0; y < ch; y += size * modifier) {
                let index = (y * cw + x) * 4;
                let a = data[index + 3];

                if (a > 20) {
                    let r = data[index + 0],
                        g = data[index + 1],
                        b = data[index + 2];
                    let color = `rgb(${r},${g},${b})`;

                    if (!ignorcolors.includes(color)) {
                        columnPixels.push({
                            x: x,
                            y: y,
                            color: color
                        });
                    }
                }
            }

            // Если в колонке есть пиксели, добавляем ее в массив
            if (columnPixels.length > 0) {
                rainColumns.push({
                    x: x,
                    pixels: columnPixels
                });
            }
        }

        // Теперь создаем executionLine в случайном порядке
        if (rainMode) {
            // Перемешиваем колонки для случайного порядка
            shuffleArray(rainColumns);

            // Обрабатываем каждую колонку
            for (let col of rainColumns) {
                let pixels = col.pixels;
                let start = pixels[0];
                let prev = start;

                // Соединяем последовательные пиксели в линии
                for (let i = 1; i < pixels.length; i++) {
                    let current = pixels[i];

                    // Если следующий пиксель не на 1 шаг ниже предыдущего или цвет другой
                    if (current.y !== prev.y + size * modifier || current.color !== prev.color) {
                        executionLine.push({
                            pos1: recalc([start.x, start.y], size, offset),
                            pos2: recalc([prev.x, prev.y], size, offset),
                            color: start.color,
                            thickness: thickness
                        });
                        start = current;
                    }
                    prev = current;
                }

                // Добавляем последнюю линию в колонке
                executionLine.push({
                    pos1: recalc([start.x, start.y], size, offset),
                    pos2: recalc([prev.x, prev.y], size, offset),
                    color: start.color,
                    thickness: thickness
                });
            }
        } else {
            // Оригинальный режим рисования (горизонтальные линии)
            for (let y = 0; y < ch; y += size * modifier) {
                let start = [0, y];

                for (let x = 0; x < ch; x += size * modifier) {
                    let end = [x, y];
                    let index = (y * cw + x) * 4;

                    let a = data[index + 3];

                    if (a > 20) {
                        end = [x, y];
                        let r = data[index + 0],
                            g = data[index + 1],
                            b = data[index + 2];

                        let color = `rgb(${r},${g},${b})`;

                        if (!ignorcolors.includes(color)) {
                            if (x < cw - 1) {
                                let n_r = data[index + size * modifier * 4 + 4],
                                    n_g = data[index + size * modifier * 4 + 5],
                                    n_b = data[index + size * modifier * 4 + 6];

                                let samecolor = true;
                                if ((r != n_r && g != n_g && b != n_b) || data[index + 7] < 20) {
                                    samecolor = false;
                                }
                                if (!samecolor) {
                                    executionLine.push({
                                        pos1: recalc(start, size, offset),
                                        pos2: recalc(end, size, offset),
                                        color: color,
                                        thickness: thickness,
                                    });
                                    start = [x, y];
                                }
                            } else {
                                executionLine.push({
                                    pos1: recalc(start, size, offset),
                                    pos2: recalc(end, size, offset),
                                    color: color,
                                    thickness: thickness,
                                });
                            }
                        }
                    } else {
                        start = [x, y];
                    }
                }
            }
        }
        console.debug('Drawing commands prepared:', executionLine.length);
    }

    // Функция для перемешивания массива (алгоритм Фишера-Йетса)
    function shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
    }

    async function execute(socket) {
        drawing_active = true;

        // Если включен режим дождика, дополнительно перемешиваем линии для более случайного эффекта
        if (rainMode) {
            shuffleArray(executionLine);
        }

        for (let i = 0; i < executionLine.length; i++) {
            if (!drawing_active) return;
            let currentLine = executionLine[i];
            let p1 = currentLine.pos1,
                p2 = currentLine.pos2,
                color = currentLine.color,
                thickness = currentLine.thickness;
            drawcmd(socket, p1, p2, color, thickness);
            await delay(10); // Задержка между линиями
        }

        function drawcmd(s, start, end, color, thickness) {
            s.send(`42["drawcmd",0,[${start[0]},${start[1]},${end[0]},${end[1]},false,${0 - thickness},"${color}",0,0,{}]]`);
        }
    }

    function delay(ms) {
        return new Promise((resolve) => setTimeout(resolve, ms));
    }

    function recalc(value, size, offset) {
        return [(value[0] / (cw * size) + offset.x / 100).toFixed(4), (value[1] / (ch * size) + offset.y / 100).toFixed(4)];
    }

    // Остальной код (Player, Connection, Room, Actions) остается без изменений
    const Player = function (name = undefined) {
        this.name = name;
        this.sid1 = null;
        this.uid = '';
        this.wt = '';

        this.conn = new Connection(this);
        this.room = new Room(this.conn);
        this.action = new Actions(this.conn);
    };
    Player.prototype.annonymize = function (name) {
        this.name = name;
        this.uid = undefined;
        this.wt = undefined;
    };

    const Connection = function (player) {
        this.player = player;
    };
    Connection.prototype.onopen = function (event) {
        this.Heartbeat(25000);
    };
    Connection.prototype.onclose = function (event) {
    };
    Connection.prototype.onerror = function (event) {
    };
    Connection.prototype.onmessage = function (event) {
        let message = String(event.data);
        if (message.startsWith('42')) {
            this.onbroadcast(message.slice(2));
        } else if (message.startsWith('40')) {
            this.onrequest();
        } else if (message.startsWith('41')) {
            this.player.room.join(this.player.room.id);
        } else if (message.startsWith('430')) {
            let configs = JSON.parse(message.slice(3))[0];
            this.player.room.players = configs.players;
            this.player.room.id = configs.roomid;
        }
    };
    Connection.prototype.onbroadcast = function (payload) {
        payload = JSON.parse(payload);
        if (payload[0] == 'bc_uc_freedrawsession_changedroom') {
            this.player.room.players = payload[3];
            this.player.room.id = payload[4];
        }
        if (payload[0] == 'mc_roomplayerschange') {
            this.player.room.players = payload[3];
        }
    };
    Connection.prototype.onrequest = function () {};
    Connection.prototype.open = function (url) {
        this.socket = new WebSocket(url);
        this.socket.onopen = this.onopen.bind(this);
        this.socket.onclose = this.onclose.bind(this);
        this.socket.onerror = this.onerror.bind(this);
        this.socket.onmessage = this.onmessage.bind(this);
    };
    Connection.prototype.close = function (code, reason) {
        this.socket.close(code, reason);
    };
    Connection.prototype.Heartbeat = function (interval) {
        let timeout = setTimeout(() => {
            if (this.socket.readyState == this.socket.OPEN) {
                this.socket.send(2);
                this.Heartbeat(interval);
            }
        }, interval);
    };
    Connection.prototype.serverconnect = function (server, room) {
        if (this.socket == undefined || this.socket.readyState != this.socket.OPEN) {
            this.open(server);
        } else {
            this.socket.send(41);
            this.socket.send(40);
        }
        this.onrequest = () => {
            this.socket.send(room);
        };
    };

    const Room = function (conn) {
        this.conn = conn;
        this.id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
        this.players = [];
    };
    Room.prototype.join = function (invitelink) {
        let gamemode = 2;
        let server = '';
        if (invitelink == null) {
            this.id = null;
            server = 'sv3.';
        } else {
            this.id = invitelink.startsWith('http') ? invitelink.split('/').pop() : invitelink;
            if (invitelink.endsWith('.3')) {
                server = 'sv3.';
                gamemode = 2;
            } else if (invitelink.endsWith('.2')) {
                server = 'sv2.';
                gamemode = 2;
            } else {
                server = '';
                gamemode = 1;
            }
        }

        let serverurl = `wss://${server}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`;

        let player = this.conn.player;
        let playerName = document.getElementById('inputName').value;
        let connectstring = `420["startplay","${playerName}",${gamemode},"en",${nullify(this.id)},null,[null,"https://drawaria.online/",1000,1000,[${nullify(player.sid1)},${nullify(player.uid)},${nullify(player.wt)}],null]]`;

        this.conn.serverconnect(serverurl, connectstring);
    };
    Room.prototype.next = function () {
        if (this.conn.socket.readyState != this.conn.socket.OPEN) {
            this.join(null);
        } else {
            this.conn.socket.send('42["pgswtichroom"]');
        }
    };

    const Actions = function (conn) {
        this.conn = conn;
    };

    Actions.prototype.DrawLine = function (bx = 50, by = 50, ex = 50, ey = 50, thickness = 50, color = '#FFFFFF', algo = 0) {
        bx = bx / 100;
        by = by / 100;
        ex = ex / 100;
        ey = ey / 100;
        this.conn.socket.send(`42["drawcmd",0,[${bx},${by},${ex},${ey},true,${0 - thickness},"${color}",0,0,{"2":${algo},"3":0.5,"4":0.5}]]`);
        this.conn.socket.send(`42["drawcmd",0,[${bx},${by},${ex},${ey},false,${0 - thickness},"${color}",0,0,{"2":${algo},"3":0.5,"4":0.5}]]`);
    };

    var nullify = (value = null) => {
        return value == null ? null : String().concat('"', value, '"');
    };

    if (!document.getElementById('Engine-Cheatcontainer')) {
        window['___BOT'] = new Player('rectile');
        window['___ENGINE'] = { loadImage, drawImage };
        addBoxIcons();
        CreateStylesheet();
        Engine();
    }
})();