Drawaria Canvas Clicker Menu + Server Render

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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
    });

})();