Drawaria Canvas Text Writer

Write text on the Drawaria canvas using WebSockets

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Drawaria Canvas Text Writer
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Write text on the Drawaria canvas using WebSockets
// @author       YouTubeDrawaria
// @include      https://drawaria.online/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Adding Text Input and Button
    function addTextInput() {
        let container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.top = '10px';
        container.style.left = '50%';
        container.style.transform = 'translateX(-50%)';
        container.style.zIndex = 1000;
        container.style.background = 'linear-gradient(135deg, #003366, #0099cc)';
        container.style.padding = '20px';
        container.style.borderRadius = '10px';
        container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
        container.style.display = 'flex';
        container.style.flexDirection = 'column';
        container.style.alignItems = 'center';
        container.style.cursor = 'move';

        let title = document.createElement('h3');
        title.textContent = 'Canvas Text Writer';
        title.style.margin = '0';
        title.style.paddingBottom = '10px';
        title.style.borderBottom = '1px solid #555';
        title.style.width = '100%';
        title.style.textAlign = 'center';
        title.style.color = 'white';
        container.appendChild(title);

        let toggleButton = document.createElement('div');
        toggleButton.innerHTML = '▼'; // Down arrow
        toggleButton.style.cursor = 'pointer';
        toggleButton.style.fontSize = '20px';
        toggleButton.style.color = 'white';
        toggleButton.style.marginBottom = '10px';
        toggleButton.addEventListener('click', () => {
            let content = container.querySelector('.content');
            if (content.style.display === 'none') {
                content.style.display = 'flex';
                toggleButton.innerHTML = '▼'; // Down arrow
            } else {
                content.style.display = 'none';
                toggleButton.innerHTML = '▲'; // Up arrow
            }
        });
        container.appendChild(toggleButton);

        let innerContainer = document.createElement('div');
        innerContainer.className = 'content';
        innerContainer.style.background = 'rgba(255, 255, 255, 0.2)';
        innerContainer.style.padding = '20px';
        innerContainer.style.borderRadius = '10px';
        innerContainer.style.width = '100%';
        innerContainer.style.display = 'flex';
        innerContainer.style.flexDirection = 'column';
        innerContainer.style.alignItems = 'center';

        let textInput = document.createElement('input');
        textInput.type = 'text';
        textInput.placeholder = 'Enter text to draw';
        textInput.style.margin = '10px 0';
        textInput.style.padding = '10px';
        textInput.style.borderRadius = '5px';
        textInput.style.border = '1px solid #ccc';
        textInput.style.width = 'calc(100% - 20px)';
        textInput.maxLength = 7;

        let charLimit = document.createElement('div');
        charLimit.textContent = 'Limit: 7 characters remaining';
        charLimit.style.margin = '10px 0';
        charLimit.style.color = 'white';

        textInput.addEventListener('input', () => {
            let remainingChars = 7 - textInput.value.length;
            charLimit.textContent = `Limit: ${remainingChars} characters remaining`;
        });

        let fontSelect = document.createElement('select');
        fontSelect.style.margin = '10px 0';
        fontSelect.style.padding = '10px';
        fontSelect.style.borderRadius = '5px';
        fontSelect.style.border = '1px solid #ccc';
        fontSelect.style.width = 'calc(100% - 20px)';
        fontSelect.innerHTML = `
            <option value="Arial">Arial</option>
            <option value="Ravie">Ravie</option>
            <option value="Courier">Courier</option>
            <option value="Magneto">Magneto</option>
            <option value="Papyrus">Papyrus</option>
            <option value="Script MT Bold">Script MT Bold</option>
            <option value="Algerian">Algerian</option>
            <option value="Segoe Print">Segoe Print</option>
        `;

        let pixelSizeLabel = document.createElement('div');
        pixelSizeLabel.textContent = 'Pixel Size: 10';
        pixelSizeLabel.style.margin = '10px 0';
        pixelSizeLabel.style.color = 'white';

        let pixelSizeSlider = document.createElement('input');
        pixelSizeSlider.type = 'range';
        pixelSizeSlider.min = '10';
        pixelSizeSlider.max = '30';
        pixelSizeSlider.value = '10';
        pixelSizeSlider.style.margin = '10px 0';
        pixelSizeSlider.style.width = 'calc(100% - 20px)';
        pixelSizeSlider.addEventListener('input', (event) => {
            pixelSizeLabel.textContent = `Pixel Size: ${event.target.value}`;
        });

        let xPositionLabel = document.createElement('div');
        xPositionLabel.textContent = 'Horizontal Position: 0';
        xPositionLabel.style.margin = '10px 0';
        xPositionLabel.style.color = 'white';

        let xPositionSlider = document.createElement('input');
        xPositionSlider.type = 'range';
        xPositionSlider.min = '0';
        xPositionSlider.max = '100';
        xPositionSlider.value = '0';
        xPositionSlider.style.margin = '10px 0';
        xPositionSlider.style.width = 'calc(100% - 20px)';
        xPositionSlider.addEventListener('input', (event) => {
            xPositionLabel.textContent = `Horizontal Position: ${event.target.value}`;
        });

        let yPositionLabel = document.createElement('div');
        yPositionLabel.textContent = 'Vertical Position: 0';
        yPositionLabel.style.margin = '10px 0';
        yPositionLabel.style.color = 'white';

        let yPositionSlider = document.createElement('input');
        yPositionSlider.type = 'range';
        yPositionSlider.min = '0';
        yPositionSlider.max = '100';
        yPositionSlider.value = '0';
        yPositionSlider.style.margin = '10px 0';
        yPositionSlider.style.width = 'calc(100% - 20px)';
        yPositionSlider.addEventListener('input', (event) => {
            yPositionLabel.textContent = `Vertical Position: ${event.target.value}`;
        });

        let sendButton = document.createElement('button');
        sendButton.textContent = 'Send Text';
        sendButton.style.padding = '10px';
        sendButton.style.borderRadius = '5px';
        sendButton.style.border = 'none';
        sendButton.style.background = 'linear-gradient(to bottom, white, #d3d3d3)';
        sendButton.style.color = '#003366';
        sendButton.style.cursor = 'pointer';
        sendButton.style.width = 'calc(100% - 20px)';
        sendButton.style.marginBottom = '10px';
        sendButton.addEventListener('click', () => {
            let text = textInput.value; // Get text
            if (text) {
                drawTextOnCanvas(text, fontSelect.value, parseInt(pixelSizeSlider.value), parseInt(xPositionSlider.value), parseInt(yPositionSlider.value));
            }
        });

        let clearCanvasButton = document.createElement('button');
        clearCanvasButton.textContent = 'Clear Canvas';
        clearCanvasButton.style.padding = '10px';
        clearCanvasButton.style.borderRadius = '5px';
        clearCanvasButton.style.border = 'none';
        clearCanvasButton.style.background = 'linear-gradient(to bottom, white, #d3d3d3)';
        clearCanvasButton.style.color = '#003366';
        clearCanvasButton.style.cursor = 'pointer';
        clearCanvasButton.style.width = 'calc(100% - 20px)';
        clearCanvasButton.style.marginBottom = '10px';
        clearCanvasButton.addEventListener('click', () => {
            let data = ["drawcmd", 0, [0.5, 0.5, 0.5, 0.5, !0, -2000, "#FFFFFF", -1, !1]];
            window.sockets.forEach(socket => {
                if (socket.readyState === WebSocket.OPEN) {
                    socket.send(`42${JSON.stringify(data)}`);
                }
            });
        });

        let joinButton = document.createElement('button');
        joinButton.textContent = 'Join';
        joinButton.style.padding = '10px';
        joinButton.style.borderRadius = '5px';
        joinButton.style.border = 'none';
        joinButton.style.background = 'linear-gradient(to bottom, white, #d3d3d3)';
        joinButton.style.color = '#003366';
        joinButton.style.cursor = 'pointer';
        joinButton.style.width = 'calc(100% - 20px)';
        joinButton.style.marginBottom = '10px';
        joinButton.addEventListener('mousedown', (e) => {
            window['___BOT'].room.join(EL('#invurl').value);
        });

        let colorInput = document.createElement('input');
        colorInput.type = 'color';
        colorInput.value = '#000000';
        colorInput.style.margin = '10px 0';

        innerContainer.appendChild(textInput);
        innerContainer.appendChild(charLimit);
        innerContainer.appendChild(fontSelect);
        innerContainer.appendChild(pixelSizeLabel);
        innerContainer.appendChild(pixelSizeSlider);
        innerContainer.appendChild(xPositionLabel);
        innerContainer.appendChild(xPositionSlider);
        innerContainer.appendChild(yPositionLabel);
        innerContainer.appendChild(yPositionSlider);
        innerContainer.appendChild(sendButton);
        innerContainer.appendChild(clearCanvasButton);
        innerContainer.appendChild(joinButton);
        innerContainer.appendChild(colorInput);

        container.appendChild(innerContainer);
        document.body.appendChild(container);

        // Make the container draggable
        let isDragging = false;
        let offsetX, offsetY;

        container.addEventListener('mousedown', (e) => {
            if (e.target === container || e.target === title) {
                isDragging = true;
                offsetX = e.clientX - container.getBoundingClientRect().left;
                offsetY = e.clientY - container.getBoundingClientRect().top;
                container.style.cursor = 'grabbing';
            }
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                container.style.left = `${e.clientX - offsetX}px`;
                container.style.top = `${e.clientY - offsetY}px`;
            }
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
            container.style.cursor = 'move';
        });
    }

    // Drawing Text on Canvas
    function drawTextOnCanvas(text, font, pixelSize, xPosition, yPosition) {
        let x = xPosition / 100; // Convert to percentage
        let y = yPosition / 100; // Convert to percentage
        let thickness = 5;
        let color = document.querySelector('input[type="color"]').value; // Get color from input

        let canvas = document.createElement('canvas');
        let ctx = canvas.getContext('2d');
        canvas.width = 500;
        canvas.height = 100;

        ctx.font = `${pixelSize}px ${font}`;
        ctx.fillStyle = color;
        ctx.fillText(text, 10, 50);

        let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
        let commands = [];

        for (let i = 0; i < imageData.length; i += 4) {
            if (imageData[i + 3] > 0) { // Alpha channel is not zero
                let px = (i / 4) % canvas.width;
                let py = Math.floor((i / 4) / canvas.width);
                let nx = x + (px / canvas.width);
                let ny = y + (py / canvas.height);
                commands.push([nx, ny, nx, ny, false, -thickness, color, 0, 0, {}]);
            }
        }

        // Send commands in batches to avoid overloading the WebSocket
        const batchSize = 50;
        for (let i = 0; i < commands.length; i += batchSize) {
            let batch = commands.slice(i, i + batchSize);
            batch.forEach(cmd => {
                sendDrawCommand(cmd[0], cmd[1], cmd[2], cmd[3], thickness, color);
            });
            // Add a small delay to avoid overloading the WebSocket
            setTimeout(() => {}, 10);
        }
    }

    // Sending Draw Command via WebSocket
    function sendDrawCommand(x1, y1, x2, y2, thickness, color) {
        let message = `42["drawcmd",0,[${x1},${y1},${x2},${y2},false,${0 - thickness},"${color}",0,0,{}]]`;
        window.sockets.forEach(socket => {
            if (socket.readyState === WebSocket.OPEN) {
                socket.send(message);
            }
        });
    }

    // Overriding WebSocket send method to capture sockets
    const originalSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (...args) {
        if (window.sockets.indexOf(this) === -1) {
            window.sockets.push(this);
        }
        return originalSend.call(this, ...args);
    };

    // Initializing
    window.sockets = [];
    addTextInput();

    // Adding the bot functionality
    const EL = (sel) => document.querySelector(sel);

    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 connectstring = `420["startplay","${player.name}",${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('Text Writer');
    }
})();