Drawaria Canvas Clicker Menu + Server Render

Simula clicks en el canvas y renderiza también los comandos de dibujo del servidor en drawaria.online

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Drawaria Canvas Clicker Menu + Server Render
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Simula clicks en el canvas y renderiza también los comandos de dibujo del servidor en drawaria.online
// @author       YouTubeDrawaria + Modificado
// @match        https://drawaria.online/*
// @grant        none
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// ==/UserScript==

(function () {
    'use strict';

    const canvas = document.querySelector('#canvas.canvas-drawer') || document.getElementById('canvas');
    if (!canvas) {
        console.warn('Canvas not found.');
        return;
    }
    const ctx = canvas.getContext('2d');

    // === Socket handling ===
    let socket;
    const originalSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (...args) {
        if (!socket) {
            socket = this;
            console.log('WebSocket hooked.');

            // intercept incoming messages to render server drawings
            socket.addEventListener('message', (event) => {
                handleIncomingMessage(event.data);
            });
        }
        return originalSend.apply(this, args);
    };

    // === Variables ===
    let positions = [
        { x: 100, y: 100 },
        { x: 200, y: 150 },
        { x: 300, y: 200 },
    ];
    let repeatInterval = 1000; // milliseconds
    let repeat = false;
    let clickIntervalId = null;
    let selectingPositions = false;
    let simulateRightClickFlag = false; // toggle between left/right click mode

    function clamp(value, min, max) {
        return Math.min(Math.max(value, min), max);
    }

    // === Send draw command to server ===
    function sendDrawCommand(x1, y1, x2, y2, color, thickness) {
        if (!socket) return;

        const normX1 = (x1 / canvas.width).toFixed(4);
        const normY1 = (y1 / canvas.height).toFixed(4);
        const normX2 = (x2 / canvas.width).toFixed(4);
        const normY2 = (y2 / canvas.height).toFixed(4);

        const command = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${-thickness},"${color}",0,0,{}]]`;
        socket.send(command);
    }

    // === Handle server draw commands ===
    function handleIncomingMessage(data) {
        if (typeof data !== 'string') return;
        if (!data.startsWith('42')) return;

        try {
            const parsed = JSON.parse(data.slice(2));
            if (parsed[0] === 'drawcmd') {
                const cmd = parsed[2];
                // formato: [x1,y1,x2,y2,false,-thickness,"#color",0,0,{}]
                const [nx1, ny1, nx2, ny2, , thicknessNeg, color] = cmd;
                const thickness = -thicknessNeg;

                const x1 = nx1 * canvas.width;
                const y1 = ny1 * canvas.height;
                const x2 = nx2 * canvas.width;
                const y2 = ny2 * canvas.height;

                ctx.strokeStyle = color;
                ctx.lineWidth = thickness;
                ctx.beginPath();
                ctx.moveTo(x1, y1);
                ctx.lineTo(x2, y2);
                ctx.stroke();
            }
        } catch (err) {
            console.error('Error parsing incoming message:', err);
        }
    }

    // === Local draw + server send ===
    function localAndServerDraw(x, y, color, thickness) {
        if (!ctx) return;
        const radius = thickness;

        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, 2 * Math.PI);
        ctx.fill();

        sendDrawCommand(x, y, x + 0.1, y + 0.1, color, thickness);
    }

    function simulateMouseEvent(target, type, clientX, clientY, button = 0) {
        const evt = new MouseEvent(type, {
            bubbles: true,
            cancelable: true,
            clientX: clientX,
            clientY: clientY,
            view: window,
            button: button,
        });
        target.dispatchEvent(evt);
    }

    function simulateLeftClickAt(x, y) {
        const rect = canvas.getBoundingClientRect();
        const cx = rect.left + x;
        const cy = rect.top + y;

        simulateMouseEvent(canvas, 'mousedown', cx, cy, 0);
        simulateMouseEvent(canvas, 'mouseup', cx, cy, 0);
        simulateMouseEvent(canvas, 'click', cx, cy, 0);

        localAndServerDraw(x, y, '#000000', 4);

        console.log(`Left-clicked at (${x}, ${y})`);
    }

    function simulateRightClickAt(x, y) {
        const rect = canvas.getBoundingClientRect();
        const cx = rect.left + x;
        const cy = rect.top + y;

        simulateMouseEvent(canvas, 'mousedown', cx, cy, 2);
        simulateMouseEvent(canvas, 'mouseup', cx, cy, 2);
        simulateMouseEvent(canvas, 'contextmenu', cx, cy, 2);

        localAndServerDraw(x, y, '#ff0000', 4);

        console.log(`Right-clicked at (${x}, ${y})`);
    }

    function clickAllPositions() {
        if (!canvas) {
            console.warn("Canvas not found!");
            return;
        }
        positions.forEach(pos => {
            if (simulateRightClickFlag) {
                simulateRightClickAt(pos.x, pos.y);
            } else {
                simulateLeftClickAt(pos.x, pos.y);
            }
        });
    }

    function startClicking() {
        if (repeat) {
            stopClicking();
            clickAllPositions();
            clickIntervalId = setInterval(clickAllPositions, repeatInterval);
            console.log("Started repeating clicks every", repeatInterval, "ms");
        } else {
            clickAllPositions();
            console.log("Clicked once");
        }
    }

    function stopClicking() {
        if (clickIntervalId) {
            clearInterval(clickIntervalId);
            clickIntervalId = null;
            console.log("Stopped clicking");
        }
    }

    function restartClicking() {
        stopClicking();
        startClicking();
    }

    function toggleRepeat() {
        repeat = !repeat;
        alert("Repeat is now " + (repeat ? "ON" : "OFF"));
        if (repeat && clickIntervalId) {
            restartClicking();
        }
    }

    function setRepeatInterval() {
        const input = prompt("Enter repeat interval in milliseconds:", repeatInterval);
        if (input !== null) {
            const v = parseInt(input);
            if (!isNaN(v) && v > 0) {
                repeatInterval = v;
                alert("Repeat interval set to " + repeatInterval + " ms");
                if (repeat && clickIntervalId) {
                    restartClicking();
                }
            } else {
                alert("Invalid number");
            }
        }
    }

    function enablePositionSelection() {
        selectingPositions = true;
        alert("Click on the canvas to select positions. Press ESC to stop.");
        positions = [];
        if (!canvas) return;
        const onClick = (e) => {
            if (!selectingPositions) return;
            const rect = canvas.getBoundingClientRect();
            const x = Math.floor(e.clientX - rect.left);
            const y = Math.floor(e.clientY - rect.top);
            positions.push({ x, y });
            alert(`Position added: (${x}, ${y})`);
            console.log("Current positions:", positions);
        };
        const onKeyDown = (e) => {
            if (e.key === "Escape") {
                selectingPositions = false;
                alert("Position selection ended.");
                canvas.removeEventListener('click', onClick);
                window.removeEventListener('keydown', onKeyDown);
            }
        };
        canvas.addEventListener('click', onClick);
        window.addEventListener('keydown', onKeyDown);
    }

    function toggleClickType() {
        simulateRightClickFlag = !simulateRightClickFlag;
        alert("Click type set to " + (simulateRightClickFlag ? "Right click" : "Left click"));
    }

    // === UI Menu ===
    function createUI() {
        const menu = document.createElement("div");
        menu.innerHTML = `
            <div id="canvasClickerMenu" style="
                position: fixed;
                top: 50px;
                left: 50px;
                background: #f8f8f8;
                border: 1px solid #ccc;
                padding: 10px;
                z-index: 99999;
                font-family: Arial, sans-serif;
                width: 240px;
                box-shadow: 0 0 10px rgba(0,0,0,0.2);
                cursor: move;
            ">
                <strong>🎯 Canvas Clicker</strong><br><br>
                <button id="startClicking">Start</button>
                <button id="stopClicking">Stop</button><br><br>
                <button id="restartClicking">Restart</button><br><br>
                <button id="toggleRepeat">Repeat</button><br><br>
                <button id="setInterval">Config Repeat MS</button><br><br>
                <button id="selectPositions">Select Positions</button><br><br>
                <button id="toggleClickType">Toggle Left/Right Click</button>
            </div>
        `;
        document.body.appendChild(menu);

        const el = document.getElementById("canvasClickerMenu");
        let isDragging = false;
        let offsetX, offsetY;
        el.addEventListener("mousedown", (e) => {
            isDragging = true;
            offsetX = e.clientX - el.offsetLeft;
            offsetY = e.clientY - el.offsetTop;
            e.preventDefault();
        });
        document.addEventListener("mousemove", (e) => {
            if (isDragging) {
                el.style.left = `${e.clientX - offsetX}px`;
                el.style.top = `${e.clientY - offsetY}px`;
            }
        });
        document.addEventListener("mouseup", () => {
            isDragging = false;
        });

        document.getElementById("startClicking").addEventListener("click", startClicking);
        document.getElementById("stopClicking").addEventListener("click", stopClicking);
        document.getElementById("restartClicking").addEventListener("click", restartClicking);
        document.getElementById("toggleRepeat").addEventListener("click", toggleRepeat);
        document.getElementById("setInterval").addEventListener("click", setRepeatInterval);
        document.getElementById("selectPositions").addEventListener("click", enablePositionSelection);
        document.getElementById("toggleClickType").addEventListener("click", toggleClickType);
    }

    window.addEventListener('load', () => {
        setTimeout(createUI, 1500); // delay so UI elements load
    });

})();