Florr.io Chat with other Players

Simple in-game chat application. Not as advantageous as using discord, a voice chat or playing in the same room, but still you can talk with your friends, you may talk with strangers, and it doesn't add lag to the game. When someone also have this extension, you will recognize them because of their blue name. You can speak with your teammates in the squad panel, in game, and they will receive your message even if you are out of their range or dead. Useful if you want to encourage them!

当前为 2022-08-31 提交的版本,查看 最新版本

// ==UserScript==
// @name		Florr.io Chat with other Players
// @description Simple in-game chat application. Not as advantageous as using discord, a voice chat or playing in the same room, but still you can talk with your friends, you may talk with strangers, and it doesn't add lag to the game. When someone also have this extension, you will recognize them because of their blue name. You can speak with your teammates in the squad panel, in game, and they will receive your message even if you are out of their range or dead. Useful if you want to encourage them!
// @author		Hirosoiko
// @version		1.0
// @match		*://florr.io/*
// @run-at      document-start
// @require     https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.js
// @grant		unsafeWindow
// @namespace	none
// ==/UserScript==

let socket = io("https://florr-chat.glitch.me", {
    transports: ["websocket"]
});

if (localStorage.florrio_nickname == "") {
    localStorage.florrio_nickname = "Chat User " + Math.floor(Math.random()*(999 - 100 + 1) + 100);
}

const latency = 100;
const maxNameLength = 13;
const namesColor = "#00ffff";
const msgRectColor = "#00000080";
const msgStrokeStyle = "#000000";
const msgFillStyle = "#ffffff";
const msgFadeMs = 125;
const flowerMsgWidth = 300;
const menuMsgWidth = 129;
const delimiterChar = "-";
const inGameMsgOffset = 20;
const inGameMsgFontSize = 20;
const proxyId = 1234567890;
let usualFlowerScale;
let canvas;
let inMenu = true;
let alive = false;
let aliveTO;
let name = localStorage.florrio_nickname = localStorage.florrio_nickname.trim();
let currentPlayers = [];
let pCurrentPlayers = currentPlayers;
let notPlayers = [];
let chatPlayers = [];
let update = true;
let wave = 0;
let squad = "";
let squadTO;
let messages = {};
let hideYou = false;
let hideReady = [];
let textInput;

document.addEventListener("DOMContentLoaded", function() {
    canvas = document.getElementById("canvas");
    textInput = document.createElement("input");
    textInput.style = `display: none; position: absolute; left: 0; right: 0; top: ${unsafeWindow.innerHeight*5/8}px; margin-left: auto; margin-right: auto; width: 200px; height: 20px; border-radius: 25px; background-color: rgba(0, 0, 0, 0.1); outline: none; font-family: 'Ubuntu'; color: white;`;
    textInput.maxLength = 100;
    document.body.appendChild(textInput);
    textInput.addEventListener("blur", function() {
        this.style.display = "none";
    });
});

const proxy = new Proxy(EventTarget.prototype.addEventListener, {
    set: (target, key, value) => {
        return true;
    },
    get: (target, key) => {
        if (key !== "__isProxy") {
            return target[key];
        }

        return true;
    },

    apply(target, thisArg, args) {
        if (args[0] === 'noProxy') {
            if (target.__isProxy) {
                return Reflect.apply(target, thisArg, args);
            } else {
                return Reflect.apply(target, thisArg, args.slice(1));
            }
        }
        if (args[2] == 0) {
            if (args[0] == "keydown" || args[0] == "keypress") {
                const temp = args[1];
                args[1] = function (d) {
                    if (d.target != textInput) {
                        if (d.keyCode == 13 && args[0] != "keypress" && chatPlayers.length != 0) {
                            if (textInput.style.display == "none") {
                                textInput.style.display = "block";
                                setTimeout(() => textInput.focus(), 0);
                            }
                        } else {
                            temp(d);
                        }
                    } else {
                        if (args[0] != "keypress") {
                            if (d.keyCode == 65 && (d.metaKey || d.ctrlKey)) {
                                textInput.select();
                            }
                            if (d.keyCode == 13) {
                                if (textInput.style.display != "none") {
                                    textInput.style.display = "none";
                                    if (!!textInput.value) {
                                        socket.emit("message", textInput.value);
                                        textInput.value = "";
                                    }
                                }
                            }
                        }
                    }
                };
            }
        }

        return Reflect.apply(...arguments);
    }
});
EventTarget.prototype.addEventListener = proxy;

function arraysEqual(a, b) {
    if (a === b) return true;
    if (a == null || b == null) return false;
    if (a.length !== b.length) return false;
    for (let i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false;
    }
    return true;
}

socket.on("notPlayers", (arr) => {
    notPlayers = [arr[0], new RegExp(arr[1])];
    socket.emit("name", name);
    socket.emit("partyPlayers", currentPlayers);
    socket.emit("wave", wave);
    socket.emit("squad", squad);
});

socket.on("chatPlayers", (arr) => {
    chatPlayers = arr;
});

function msgPendingTime(message) {
    return Math.max(message.length*200, 2000);
}

function timeNowMs() {
    return new Date().getTime();
}

socket.on("message", (arr) => {
    if (!!messages[arr[0]]) {
        clearTimeout(messages[arr[0]][2]);
    }
    if (arr[0] == name && hideYou) {
        hideYou = false;
    }
    messages[arr[0]] = [
        arr[1],
        timeNowMs(),
        setTimeout(function() {
            if (arr[0] == name && hideYou) {
                hideYou = false;
            }
            delete messages[arr[0]];
        }, msgPendingTime(arr[1])),
        true
    ];
});

socket.on("duplicate", (n) => {
    if (inMenu) {
        alert(`The name "${n}" already exists, you may change your name to enable the chat`);
    }
});

socket.on("unnamed", () => {
    alert(`You need to have a name to enable the chat`);
});

socket.on("invalid", (n) => {
    alert(`The name "${n}" isn't accepted by the script, you may change your name to enable the chat`);
});

function updateInfo() {
    setTimeout(function() {
        update = false;
        if (!arraysEqual(currentPlayers, pCurrentPlayers)) {
            socket.emit("partyPlayers", currentPlayers);
        }
        pCurrentPlayers = currentPlayers;
        currentPlayers = [];
        setTimeout(function() {
            update = true;
            if (name != localStorage.florrio_nickname) {
                name = localStorage.florrio_nickname = localStorage.florrio_nickname.trim();
                socket.emit("name", name);
            }
            updateInfo();
        }, 1000);
    }, latency);
}
updateInfo();

function maxOcc(array) {
    if (array.length == 0) {
        return null;
    }
    let modeMap = {};
    let maxEl = array[0];
    let maxCount = 1;
    for(let i = 0; i < array.length; i++) {
        const el = array[i];
        if (modeMap[el] == null) {
            modeMap[el] = 1;
        } else {
            modeMap[el]++;
        }
        if (modeMap[el] > maxCount) {
            maxEl = el;
            maxCount = modeMap[el];
        } else if (modeMap[el] == maxCount && maxEl > el) {
            maxEl = el;
        }
    }
    return maxEl;
}

var flowerScales = [];
function updateFlowerScale(scale) {
    flowerScales.push(scale);
    if (flowerScales.length > 6) {
        flowerScales.shift();
    }
    return maxOcc(flowerScales);
}

function roundRect(ctx, x, y, width, height, radius = 5, fill = false, stroke = true) {
    if (typeof radius === 'number') {
        radius = {tl: radius, tr: radius, br: radius, bl: radius};
    } else {
        radius = {...{tl: 0, tr: 0, br: 0, bl: 0}, ...radius};
    }
    ctx.beginPath();
    ctx.moveTo(x + radius.tl, y);
    ctx.lineTo(x + width - radius.tr, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
    ctx.lineTo(x + width, y + height - radius.br);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
    ctx.lineTo(x + radius.bl, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
    ctx.lineTo(x, y + radius.tl);
    ctx.quadraticCurveTo(x, y, x + radius.tl, y);
    ctx.closePath();
    if (fill) {
        ctx.fill();
    }
    if (stroke) {
        ctx.stroke();
    }
}

const canvasCtx = !!unsafeWindow.OffscreenCanvasRenderingContext2D ? "OffscreenCanvasRenderingContext2D" : !!unsafeWindow.CanvasRenderingContext2D ? "CanvasRenderingContext2D" : "";

if (!!canvasCtx) {
    const fillTextProxy = new Proxy(unsafeWindow[canvasCtx].prototype.fillText, {
        get: (target, key) => {
            if (key !== "__isProxy") {
                return target[key];
            }

            return true;
        },
        set: (target, key, value) => {
            return true;
        },
        apply(target, ctx, args) {
            const text = args[0];
            if (text === 'noProxy') {
                if (target.__isProxy) {
                    return Reflect.apply(target, ctx, args);
                } else {
                    return Reflect.apply(target, ctx, args.slice(1));
                }
            }
            if (args[3] != proxyId) {
                if (!inMenu && text == "A mysterious entity" && ctx.font == "24px Ubuntu") {
                    inMenu = true;
                    messages = {}
                    currentPlayers = [];
                    wave = 0;
                    socket.emit("wave", wave);
                }
                if (text == "[1]" && ctx.font == "14px Ubuntu") {
                    if (inMenu) {
                        inMenu = false;
                        if (squad != "") {
                            squad = "";
                            socket.emit("squad", squad);
                        }
                        for (let uName in messages) {
                            if (Array.isArray(messages[uName][0])) {
                                messages[uName][0] = messages[uName][0][1];
                                messages[uName][3] = true;
                                messages[uName][4] = null;
                            }
                        }
                    }
                    if (!alive) {
                        alive = true;
                    }
                    if (!!aliveTO) {
                        clearTimeout(aliveTO);
                    }
                    aliveTO = setTimeout(function() {
                        alive = false;
                    }, latency);
                }
                if (/^Wave [1-9][0-9]*$/.test(text) && ctx.font == "16px Ubuntu" && wave != Number(text.match(/[1-9][0-9]*/)[0])) {
                    wave = Number(text.match(/[1-9][0-9]*/)[0]);
                    socket.emit("wave", wave);
                }
                if (!inMenu && text.length <= maxNameLength) {
                    if (ctx.font == "18px Ubuntu" && notPlayers.length != 0 && !notPlayers[0].includes(text) && !notPlayers[1].test(text)) {
                        if (!currentPlayers.includes(text)) {
                            currentPlayers.push(text);
                        }
                        if (chatPlayers.includes(text)) {
                            ctx.fillStyle = namesColor;
                        }
                        for (let uName in messages) {
                            if (text == uName && (text != name || !inMenu && !alive) && messages[uName][3] && !messages[uName][4]) {
                                messages[uName][4] = ctx.getTransform();
                                break;
                            }
                        }
                    } else if (text == "[1]" && ctx.font == "14px Ubuntu" || !inMenu && !alive && /^Wave [1-9][0-9]*$/.test(text) && ctx.font == "16px Ubuntu") {
                        ctx.strokeText(text, 0, 0, proxyId);
                        ctx.fillText(text, 0, 0, proxyId);
                        for (let uName in messages) {
                            if (messages[uName][3] && !!messages[uName][4] && (uName != name || !inMenu && !alive) && chatPlayers.includes(uName)) {
                                ctx.save();
                                ctx.setTransform(messages[uName][4]);
                                const fontSize = inGameMsgFontSize;
                                ctx.font = fontSize + "px Ubuntu";
                                const borderSpace = fontSize;
                                const message = Array.isArray(messages[uName][0]) ? messages[uName][0][1] : messages[uName][0];
                                const width = ctx.measureText(message).width + borderSpace;
                                const height = fontSize + borderSpace;
                                const offsetX = 110;
                                const offsetY = - fontSize;
                                ctx.globalAlpha = Math.max(0, Math.min((timeNowMs() - messages[uName][1])/msgFadeMs, 1, Math.min(((msgPendingTime(message)) - (timeNowMs() - messages[uName][1])), msgFadeMs)/msgFadeMs));
                                ctx.fillStyle = msgRectColor;
                                roundRect(ctx, offsetX - borderSpace/2, - height - offsetY, width, height, 5, true, false);
                                ctx.strokeStyle = msgStrokeStyle;
                                ctx.fillStyle = msgFillStyle;
                                ctx.textAlign = "left";
                                ctx.strokeText(message, offsetX, - height - offsetY + fontSize, proxyId);
                                ctx.fillText(message, offsetX, - height - offsetY + fontSize, proxyId);
                                ctx.restore();
                            }
                        }
                        return;
                    }
                }
            }
            return Reflect.apply(...arguments);
        }
    });
    unsafeWindow[canvasCtx].prototype.fillText = fillTextProxy;
} else {
    alert(`Your browser doesn't support the script "Florr.io Chat with other Players", you may consider switching browser for browsers like Chrome, Opera or Firefox to make it work`);
}

const canvasProxy = new Proxy(unsafeWindow.HTMLCanvasElement.prototype.getContext, {
    get: (target, key) => {
        if (key !== "__isProxy") {
            return target[key];
        }

        return true;
    },
    set: (target, key, value) => {
        return true;
    },
    apply(target, thisArg, args) {
        const ctx = Reflect.apply(...arguments);

        const prototype = Object.getPrototypeOf(ctx);
        const descriptors = Object.getOwnPropertyDescriptors(prototype);

        Object.defineProperties(prototype, {
            strokeText: {
                value(text, x, y, maxWidth) {
                    if (maxWidth != proxyId) {
                        if (inMenu && text.length <= maxNameLength) {
                            if (ctx.font == "16px Ubuntu" && text == "(you)" && hideYou || ctx.font == "20px Ubuntu" && text == "Ready" && hideReady.includes(ctx.getTransform().e.toFixed(3))) {
                                return;
                            } else if (ctx.font == "16px Ubuntu" && notPlayers.length != 0 && !notPlayers[0].includes(text) && !notPlayers[1].test(text) && !/^[a-z0-9]{12}$/.test(text) && (text != "(you)" || hideYou)) {
                                text = text.trim();
                            }
                            for (let uName in messages) {
                                if (text == uName) {
                                    if (messages[uName][0][0].length >= 4) {
                                        return;
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    return descriptors.strokeText.value.call(this, text, x, y, maxWidth);
                }
            },
            fillText: {
                value(text, x, y, maxWidth) {
                    if (maxWidth != proxyId) {
                        if (inMenu && /^Code: [a-z0-9]{3}-[a-z0-9]{6}$/.test(text)) {
                            if (squad != text) {
                                squad = text;
                                socket.emit("squad", squad);
                            }
                            if (!!squadTO) {
                                clearTimeout(squadTO);
                            }
                            squadTO = setTimeout(function() {
                                squad = "";
                                socket.emit("squad",squad);
                            }, latency);
                        }
                        if (text.length <= maxNameLength) {
                            if (!inMenu) {
                                if (ctx.font == "24px Ubuntu" && notPlayers.length != 0 && !notPlayers[0].includes(text) && !notPlayers[1].test(text) && text.trim() != name) {
                                    text = text.trim();
                                    if (chatPlayers.includes(text)) {
                                        ctx.fillStyle = namesColor;
                                    }
                                    const gT = ctx.getTransform();
                                    const flowerScale = updateFlowerScale(gT.d);
                                    if (usualFlowerScale != flowerScale) {
                                        usualFlowerScale = flowerScale;
                                    }
                                    for (let uName in messages) {
                                        if (text == uName) {
                                            if (alive) {
                                                messages[uName][6] = gT;
                                                if (!!messages[uName][7]) {
                                                    clearTimeout(messages[uName][7]);
                                                }
                                                messages[uName][7] = setTimeout(function(n) {
                                                    if (!!messages[n]) {
                                                        messages[n][6] = null;
                                                    }
                                                }, latency, uName);
                                            } else {
                                                ctx.save();
                                                const fontSize = inGameMsgFontSize;
                                                ctx.font = fontSize + "px Ubuntu";
                                                let width = flowerMsgWidth;
                                                const borderSpace = fontSize;
                                                let splitText;
                                                if (!Array.isArray(messages[uName][0])) {
                                                    const message = messages[uName][0].split(/( )/);
                                                    splitText = [""];
                                                    for (let i = 0; i < message.length; i++) {
                                                        if (ctx.measureText(splitText[splitText.length - 1] + message[i]).width < width - borderSpace) {
                                                            splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i];
                                                        } else if (ctx.measureText(message[i]).width < width - borderSpace && splitText[splitText.length - 1] !== "") {
                                                            splitText.push(message[i]);
                                                        } else {
                                                            if (splitText[splitText.length - 1] !== "") {
                                                                splitText.push("");
                                                            }
                                                            for (let j = 0; j < message[i].length; j++) {
                                                                if (ctx.measureText(splitText[splitText.length - 1] + message[i][j] + delimiterChar).width < width - borderSpace) {
                                                                    splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i][j];
                                                                } else {
                                                                    splitText[splitText.length - 1] = splitText[splitText.length - 1] + delimiterChar;
                                                                    splitText.push(message[i][j]);
                                                                }
                                                            }
                                                        }
                                                    }
                                                    messages[uName][0] = [splitText, messages[uName][0]];
                                                } else {
                                                    splitText = messages[uName][0][0];
                                                }
                                                if (splitText.length == 1) {
                                                    width = ctx.measureText(splitText[0]).width + borderSpace;
                                                }
                                                const textInterSpace = fontSize/5;
                                                const height = fontSize*splitText.length + borderSpace + splitText.length*textInterSpace;
                                                const offset = inGameMsgOffset;
                                                ctx.globalAlpha = Math.max(0, Math.min((timeNowMs() - messages[uName][1])/msgFadeMs, 1, Math.min(((msgPendingTime(messages[uName][0][1])) - (timeNowMs() - messages[uName][1])), msgFadeMs)/msgFadeMs));
                                                ctx.fillStyle = msgRectColor;
                                                roundRect(ctx, - width/2, - height - offset, width, height, 5, true, false);
                                                if (!messages[uName][3] && (gT.e - (width/2 - width)*gT.a < 0 || gT.e - (width/2)*gT.a > canvas.width || gT.f - (height + offset - height)*gT.d < 0 || gT.f - (height + offset)*gT.d > canvas.height)) {
                                                    messages[uName][3] = true;
                                                } else if (messages[uName][3] && !(gT.e - (width/2 - width)*gT.a < 0 || gT.e - (width/2)*gT.a > canvas.width || gT.f - (height + offset - height)*gT.d < 0 || gT.f - (height + offset)*gT.d > canvas.height)) {
                                                    messages[uName][3] = false;
                                                    if (!!messages[uName][5]) {
                                                        clearTimeout(messages[uName][5]);
                                                    }
                                                    messages[uName][5] = setTimeout(function(n) {
                                                        if (!!messages[n]) {
                                                            messages[n][3] = true;
                                                        }
                                                    }, latency, uName);
                                                    if (!!messages[uName][4]) {
                                                        messages[uName][4] = null;
                                                    }
                                                }
                                                ctx.strokeStyle = msgStrokeStyle;
                                                ctx.fillStyle = msgFillStyle;
                                                ctx.textAlign = "center";
                                                for (let i = 0; i < splitText.length; i++) {
                                                    ctx.strokeText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1) - textInterSpace/2, proxyId);
                                                    ctx.fillText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1) - textInterSpace/2, proxyId);
                                                }
                                                ctx.restore();
                                            }
                                            break;
                                        }
                                    }
                                }
                            } else if (inMenu) {
                                const gT = ctx.getTransform();
                                if (ctx.font == "20px Ubuntu" && text == "Ready" && hideReady.includes(gT.e.toFixed(3))) {
                                    return;
                                }
                                if (ctx.font == "16px Ubuntu" && notPlayers.length != 0 && !notPlayers[0].includes(text) && !notPlayers[1].test(text) && !/^[a-z0-9]{12}$/.test(text) && (text != "(you)" || hideYou)) {
                                    if (text == "(you)" && hideYou) {
                                        return;
                                    }
                                    text = text.trim();
                                    if (!currentPlayers.includes(text)) {
                                        currentPlayers.push(text);
                                    }
                                    if (chatPlayers.includes(text)) {
                                        ctx.fillStyle = namesColor;
                                    }
                                    for (let uName in messages) {
                                        if (text == uName) {
                                            const fontSize = Number(ctx.font.match(/\d+/)[0]);
                                            let width = menuMsgWidth;
                                            const borderSpace = fontSize;
                                            let splitText;
                                            if (!Array.isArray(messages[uName][0])) {
                                                const message = messages[uName][0].split(/( )/);
                                                splitText = [""];
                                                for (let i = 0; i < message.length; i++) {
                                                    if (ctx.measureText(splitText[splitText.length - 1] + message[i]).width < width - borderSpace) {
                                                        splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i];
                                                    } else if (ctx.measureText(message[i]).width < width - borderSpace && splitText[splitText.length - 1] !== "") {
                                                        splitText.push(message[i]);
                                                    } else {
                                                        if (splitText[splitText.length - 1] !== "") {
                                                            splitText.push("");
                                                        }
                                                        for (let j = 0; j < message[i].length; j++) {
                                                            if (ctx.measureText(splitText[splitText.length - 1] + message[i][j] + delimiterChar).width < width - borderSpace) {
                                                                splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i][j];
                                                            } else {
                                                                splitText[splitText.length - 1] = splitText[splitText.length - 1] + delimiterChar;
                                                                splitText.push(message[i][j]);
                                                            }
                                                        }
                                                    }
                                                }
                                                if (splitText.length >= 4) {
                                                    splitText.unshift(text + ":");
                                                }
                                                messages[uName][0] = [splitText, messages[uName][0]];
                                            } else {
                                                splitText = messages[uName][0][0];
                                            }
                                            if (uName == name && splitText.length > 1 && !hideYou) {
                                                hideYou = true;
                                            }
                                            if (!hideReady.includes(gT.e.toFixed(3))) {
                                                hideReady.push(gT.e.toFixed(3));
                                                setTimeout(function() {
                                                    hideReady.shift();
                                                }, msgPendingTime(messages[uName][0][1]) - (timeNowMs() - messages[uName][1]));
                                            }
                                            if (splitText.length == 1) {
                                                width = ctx.measureText(splitText[0]).width + borderSpace;
                                            }
                                            const textInterSpace = fontSize/5;
                                            const height = fontSize*splitText.length + borderSpace + 3 + splitText.length*textInterSpace;
                                            const offset = Math.max(-50-height/2, -103);
                                            ctx.save();
                                            ctx.globalAlpha = Math.max(0, Math.min((timeNowMs() - messages[uName][1])/msgFadeMs, 1, Math.min(msgPendingTime(messages[uName][0][1]) - (timeNowMs() - messages[uName][1]), msgFadeMs)/msgFadeMs));
                                            ctx.fillStyle = msgRectColor;
                                            roundRect(ctx, - width/2, - height - offset, width, height, 5, true, false);
                                            ctx.strokeStyle = msgStrokeStyle;
                                            for (let i = 0; i < splitText.length; i++) {
                                                if (i == 0 && splitText.length >= 4) {
                                                    ctx.fillStyle = namesColor;
                                                } else if (ctx.fillStyle != msgFillStyle) {
                                                    ctx.fillStyle = msgFillStyle;
                                                }
                                                ctx.strokeText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1), proxyId);
                                                ctx.fillText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1), proxyId);
                                            }
                                            ctx.restore();
                                            if (splitText.length >= 4 && gT.a != 1) {
                                                return;
                                            }
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    return descriptors.fillText.value.call(this, text, x, y, maxWidth);
                }
            },
            arc: {
                value(x, y, r, s, e, c) {
                    if (alive) {
                        const gT = ctx.getTransform();
                        const radius = 25;
                        const xCenter = canvas.width/2;
                        const yCenter = canvas.height/2;
                        if (e == 2*Math.PI && gT.e > xCenter - radius/2 && gT.e < xCenter + radius/2 && gT.f > yCenter - radius/2 && gT.f < yCenter + radius/2 && r == radius && gT.b == 0 && gT.c == 0 && ctx.globalAlpha == 1) {
                            ctx.save();
                            for (let uName in messages) {
                                if (!!messages[uName][6]) {
                                    ctx.setTransform(messages[uName][6]);
                                    const gT = messages[uName][6];
                                    const fontSize = inGameMsgFontSize;
                                    ctx.font = fontSize + "px Ubuntu";
                                    let width = flowerMsgWidth;
                                    const borderSpace = fontSize;
                                    let splitText;
                                    if (!Array.isArray(messages[uName][0])) {
                                        const message = messages[uName][0].split(/( )/);
                                        splitText = [""];
                                        for (let i = 0; i < message.length; i++) {
                                            if (ctx.measureText(splitText[splitText.length - 1] + message[i]).width < width - borderSpace) {
                                                splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i];
                                            } else if (ctx.measureText(message[i]).width < width - borderSpace && splitText[splitText.length - 1] !== "") {
                                                splitText.push(message[i]);
                                            } else {
                                                if (splitText[splitText.length - 1] !== "") {
                                                    splitText.push("");
                                                }
                                                for (let j = 0; j < message[i].length; j++) {
                                                    if (ctx.measureText(splitText[splitText.length - 1] + message[i][j] + delimiterChar).width < width - borderSpace) {
                                                        splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i][j];
                                                    } else {
                                                        splitText[splitText.length - 1] = splitText[splitText.length - 1] + delimiterChar;
                                                        splitText.push(message[i][j]);
                                                    }
                                                }
                                            }
                                        }
                                        messages[uName][0] = [splitText, messages[uName][0]];
                                    } else {
                                        splitText = messages[uName][0][0];
                                    }
                                    if (splitText.length == 1) {
                                        width = ctx.measureText(splitText[0]).width + borderSpace;
                                    }
                                    const textInterSpace = fontSize/5;
                                    const height = fontSize*splitText.length + borderSpace + splitText.length*textInterSpace;
                                    const offset = inGameMsgOffset;
                                    ctx.globalAlpha = Math.max(0, Math.min((timeNowMs() - messages[uName][1])/msgFadeMs, 1, Math.min(((msgPendingTime(messages[uName][0][1])) - (timeNowMs() - messages[uName][1])), msgFadeMs)/msgFadeMs));
                                    ctx.fillStyle = msgRectColor;
                                    roundRect(ctx, - width/2, - height - offset, width, height, 5, true, false);
                                    if (!messages[uName][3] && (gT.e - (width/2 - width)*gT.a < 0 || gT.e - (width/2)*gT.a > canvas.width || gT.f - (height + offset - height)*gT.d < 0 || gT.f - (height + offset)*gT.d > canvas.height)) {
                                        messages[uName][3] = true;
                                    } else if (messages[uName][3] && !(gT.e - (width/2 - width)*gT.a < 0 || gT.e - (width/2)*gT.a > canvas.width || gT.f - (height + offset - height)*gT.d < 0 || gT.f - (height + offset)*gT.d > canvas.height)) {
                                        messages[uName][3] = false;
                                        if (!!messages[uName][5]) {
                                            clearTimeout(messages[uName][5]);
                                        }
                                        messages[uName][5] = setTimeout(function(n) {
                                            if (!!messages[n]) {
                                                messages[n][3] = true;
                                            }
                                        }, latency, uName);
                                        if (!!messages[uName][4]) {
                                            messages[uName][4] = null;
                                        }
                                    }
                                    ctx.strokeStyle = msgStrokeStyle;
                                    ctx.fillStyle = msgFillStyle;
                                    ctx.textAlign = "center";
                                    for (let i = 0; i < splitText.length; i++) {
                                        ctx.strokeText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1) + 5, proxyId);
                                        ctx.fillText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1) + 5, proxyId);
                                    }
                                }
                            }
                            ctx.restore();
                            if (!!messages[name]) {
                                ctx.save();
                                const rScaling = gT.d/unsafeWindow.devicePixelRatio;
                                ctx.setTransform(usualFlowerScale, gT.b, gT.c, usualFlowerScale, gT.e, gT.f);
                                const fontSize = inGameMsgFontSize;
                                ctx.font = fontSize + "px Ubuntu";
                                let width = flowerMsgWidth;
                                const borderSpace = fontSize;
                                let splitText;
                                if (!Array.isArray(messages[name][0])) {
                                    const message = messages[name][0].split(/( )/);
                                    splitText = [""];
                                    for (let i = 0; i < message.length; i++) {
                                        if (ctx.measureText(splitText[splitText.length - 1] + message[i]).width < width - borderSpace) {
                                            splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i];
                                        } else if (ctx.measureText(message[i]).width < width - borderSpace && splitText[splitText.length - 1] !== "") {
                                            splitText.push(message[i]);
                                        } else {
                                            if (splitText[splitText.length - 1] !== "") {
                                                splitText.push("");
                                            }
                                            for (let j = 0; j < message[i].length; j++) {
                                                if (ctx.measureText(splitText[splitText.length - 1] + message[i][j] + delimiterChar).width < width - borderSpace) {
                                                    splitText[splitText.length - 1] = splitText[splitText.length - 1] + message[i][j];
                                                } else {
                                                    splitText[splitText.length - 1] = splitText[splitText.length - 1] + delimiterChar;
                                                    splitText.push(message[i][j]);
                                                }
                                            }
                                        }
                                    }
                                    messages[name][0] = [splitText, messages[name][0]];
                                } else {
                                    splitText = messages[name][0][0];
                                }
                                if (splitText.length == 1) {
                                    width = ctx.measureText(splitText[0]).width + borderSpace;
                                }
                                const textInterSpace = fontSize/5;
                                const height = fontSize*splitText.length + borderSpace + splitText.length*textInterSpace;
                                const offset = radius*rScaling*2 + inGameMsgOffset + 10;
                                ctx.globalAlpha = Math.max(0, Math.min((timeNowMs() - messages[name][1])/msgFadeMs, 1, Math.min(((msgPendingTime(messages[name][0][1])) - (timeNowMs() - messages[name][1])), msgFadeMs)/msgFadeMs));
                                ctx.fillStyle = msgRectColor;
                                roundRect(ctx, - width/2, - height - offset, width, height, 5, true, false);
                                ctx.strokeStyle = msgStrokeStyle;
                                ctx.fillStyle = msgFillStyle;
                                ctx.textAlign = "center";
                                for (let i = 0; i < splitText.length; i++) {
                                    ctx.strokeText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1) + 5, proxyId);
                                    ctx.fillText(splitText[i], 0, - height - offset + (fontSize + textInterSpace)*(i + 1) + 5, proxyId);
                                }
                                ctx.restore();
                            }
                            ctx.beginPath();
                            ctx.closePath();
                        }
                    }
                    return descriptors.arc.value.call(this, x, y, r, s, e, c);
                }
            }
        });

        return ctx;
    }
});

unsafeWindow.HTMLCanvasElement.prototype.getContext = canvasProxy;

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址