Greasy Fork

Ultra Mobs Alert

Show spawn timer, sharing another players. Work In Progress https://discord.gg/4nPjXjVf4t

当前为 2023-05-04 提交的版本,查看 最新版本

// ==UserScript==
// @name         Ultra Mobs Alert
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  Show spawn timer, sharing another players. Work In Progress https://discord.gg/4nPjXjVf4t
// @author       @jmatg1
// @license MIT
// @match        https://florr.io
// @icon         https://www.google.com/s2/favicons?sz=64&domain=florr.io
// @grant        none
// ==/UserScript==

function createInput() {
    var array = ["NA", "EU", "AS"];
    var selectList = document.createElement("select");
    selectList.style.pointerEvents = "auto";
    selectList.id = "serverIdSelect";
    for (var i = 0; i < array.length; i++) {
        var option = document.createElement("option");
        option.value = array[i];
        option.text = array[i];
        selectList.appendChild(option);
    }
    return selectList;
}

class GUI {
    constructor(serv) {
        this.data = {};
        this.bosses = [];
        const div = document.createElement('div');
        div.appendChild(createInput());
        this.menu = document.body.appendChild(document.createElement('div'));
        this.menu.appendChild(div);
        this.menu.style.padding = '15px';
        this.menu.style.background = '#ffffff3f';
        this.menu.style['border-radius'] = '10px';
        this.menu.style.display = 'block';
        this.menu.style.position = 'absolute';
        this.menu.style['pointer-events'] = 'none';
        this.menu.style.bottom = '5px';
        this.menu.style.right = '5px';

        this.table = this.menu.appendChild(document.createElement('table'));
        this.table.style['font-family'] = 'Ubuntu';
        this.table.style['border-collapse'] = 'collapse';
        this.table.style.width = `100%`;
        setInterval(() => {
            this.updateTable();
        }, 60 * 1000)
    }

    updateTable(bosses = this.bosses) {
        console.log(bosses);
        this.bosses = bosses;
        while (this.table.rows.length > 0) {
            this.table.deleteRow(0);
        }
        bosses.sort((a, b) => {
            return new Date(a.date).getTime() - new Date(b.date).getTime();
        });

        bosses = bosses.filter((x) => {
            const minutes = Math.floor((Date.now() - new Date(x.date).getTime()) / 1000 / 60);
            if (minutes > 240) {
                return false
            }
            return true;
        });
        bosses.forEach((x, i) => {
            const tr = this.table.insertRow();

            // Mob
            const td1 = tr.insertCell();
            if (i !== 0) {
                td1.style['padding-top'] = '5px';
            }
            if (i !== bosses.length - 1) {
                td1.style['padding-bottom'] = '5px';
            }
            td1.style['padding-right'] = '20px';

            td1.appendChild(document.createTextNode(x.name));

            // minutes ago
            const td2 = tr.insertCell();
            if (i !== 0) {
                td2.style['padding-top'] = '5px';
            }
            if (i !== bosses.length - 1) {
                td2.style['padding-bottom'] = '5px';
            }
            td2.style['pointer-events'] = 'auto';
            td2.style.cursor = 'pointer';
            td2.appendChild(document.createTextNode(this.toTimeSpanString(x.date)));
        });
    }

    toTimeSpanString(timestamp) {
        if (timestamp == null) {
            return 'N/A';
        }

        let minutes = Math.floor((Date.now() - new Date(timestamp).getTime()) / 1000 / 60);
        let h = Math.floor(minutes / 60);
        minutes = minutes % 60;
        return `${String(h).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
    }
    changeServer(id) {
        this.updateTable(this.data[id]);
    }
}

class ServerId {
    constructor() {
        this.servers = [];
        this.url;
        const nativeWebSocket = window.WebSocket;
        var totalServers = 17 - 1;
        var regionName, allServers = [];
        var _this = this;
        window.WebSocket = function (...args) {
            const socket = new nativeWebSocket(...args);
            _this.url = socket.url
            return socket;
        };
        const urls = [];
        for (let i = 0; i <= totalServers; i++) {
            urls.push(`https://api.n.m28.io/endpoint/florrio-map-${i}-green/findEach/`);
        }
        Promise.all(urls.map(url =>
            fetch(url).then(resp => resp.text())
        )).then(texts => {
            if (texts.length === 17) {
                texts.forEach(el => {
                    const data = JSON.parse(el)
                    this.servers.push(`${data.servers["vultr-miami"].id} ${data.servers["vultr-frankfurt"].id} ${data.servers["vultr-tokyo"].id}`);
                })
            }
        })
    }


    getId() {
        var wssUrl = this.url.slice(6, 9)
        var codeA = [];
        var regionName = '';
        this.servers.forEach(function callback(x, index) {
            if (x.includes(wssUrl)) {
                codeA = x.split(" ")
                if (wssUrl == codeA[0]) regionName = "NA"
                else if (wssUrl == codeA[1]) regionName = "EU"
                else if (wssUrl == codeA[2]) regionName = "AS"
            }
        });
        return regionName;
    }
}

(function () {
    'use strict';

    const serv = new ServerId();

    const gui = new GUI(serv);
    let socket = new WebSocket("wss://cyber-glorious-ferry.glitch.me");
    document.getElementById('serverIdSelect').onchange = ev => {
        gui.changeServer(ev.target.value);
        console.log(ev.target.value)
    }
    setTimeout(() => {
        document.getElementById('serverIdSelect').value = serv.getId();
        gui.changeServer(serv.getId());
    }, 15000)
    socket.onopen = function (e) {
        console.log("[open] Соединение установлено");
        setInterval(() => {
            socket.send(JSON.stringify({message: "PING", serverName: 'EU'}));
        }, 60 * 1000)
    };

    socket.onmessage = function (event, isBinary) {
        const message = JSON.parse(event.data);
        if (message.message === "PONG") {
            return
        }
        gui.data = message;
        gui.updateTable(message[document.getElementById('serverIdSelect').value]);

    };

    socket.onclose = function (event) {
        if (event.wasClean) {
            console.log(`[close] Соединение закрыто чисто, код=${event.code} причина=${event.reason}`);
        } else {
            console.log('[close] Соединение прервано');
        }
    };

    socket.onerror = function (error) {
        console.log(`[error]`);
    };

    var flag = false;

    function parseText(text, _this) {
        if (flag) {
            return
        }
        if (text && text.search(/((An Ultra)|(A Super)) (.*) has spawned!?( somewhere!?)?/i) !== -1) {
            socket.send(JSON.stringify({message: text, serverName: serv.getId()}));
            console.warn(JSON.stringify({message: text, serverName: serv.getId()}));
            flag = true;
            setTimeout(() => {
                flag = false;
            }, 10 * 60 * 1000)
        }
        //console.log(text, x, y, a)
    }

    function getCompatibleCanvas() {
        if (typeof (OffscreenCanvasRenderingContext2D) == 'undefined') {
            return [CanvasRenderingContext2D]
        }
        return [OffscreenCanvasRenderingContext2D, CanvasRenderingContext2D];
    }

    for (const {prototype} of getCompatibleCanvas()) {
        if (prototype.rewriteStrokeText == undefined) {
            if (false) {
                prototype.rewriteArc = prototype.arc
            }
            prototype.rewriteStrokeText = prototype.strokeText;
            prototype.rewriteFillText = prototype.fillText;
            prototype.rewriteMeasureText = prototype.measureText;
        } else {
            break
        }
    }
    for (const {prototype} of getCompatibleCanvas()) {

        //重写字符描边函数
        prototype.strokeText = function (text, x, y) {
            parseText(text, this);
            return this.rewriteStrokeText(text, x, y);
        }

        prototype.fillText = function (text, x, y) {
            parseText(text, this);
            return this.rewriteFillText((text), x, y);
        }
        prototype.measureText = function (text) {
            parseText(text, this);
            return this.rewriteMeasureText((text));
        }
    }
})();