Diep.io Server Selector + Restore Player Count

Select servers from different gamemodes and regions for Diep. Also restores player count for Diep.io.

目前為 2022-01-21 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Diep.io Server Selector + Restore Player Count
// @namespace    http://tampermonkey.net/
// @version      2.1.0
// @description  Select servers from different gamemodes and regions for Diep. Also restores player count for Diep.io.
// @author       Altanis + Bismuth
// @match        *://diep.io/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        unsafeWindow
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

(async function() {
    // Special credits to Diep7444 for paving the way to an effective region changer.
    const textShadow = 'text-shadow:black 0.18vh 0, black -0.18vh 0, black 0 -0.18vh, black 0 0.18vh, black 0.18vh 0.18vh, black -0.18vh 0.18vh, black 0.18vh -0.18vh, black -0.18vh -0.18vh, black 0.09vh 0.18vh, black -0.09vh 0.18vh, black 0.09vh -0.18vh, black -0.09vh -0.18vh, black 0.18vh 0.09vh, black -0.18vh 0.09vh, black 0.18vh -0.09vh, black -0.18vh -0.09vh'
    const regions = ["do-sfo","do-nyc","do-fra","do-sgp"];
    const modes = ["ffa", "survival","teams", "4teams", "dom","tag","maze","sandbox"];
    const colors = ["#E8B18A", "#E666EA", "#9566EA", "#6690EA", "#E7D063", "#EA6666", "#92EA66", "#66EAE6"];

    var PLAYER_COUNT = 0;

    var _resp = await fetch(`https://api-game.rivet.gg/v1/matchmaker/lobbies/list`);
    var lists = await _resp.json();

    if (!localStorage.lists) {
        localStorage.lists = JSON.stringify({
            timestamp: Date.now(),
            list: lists,
        });
    }

    setInterval(async function() {
        if (!localStorage.lists) {
            localStorage.lists = JSON.stringify({
                timestamp: Date.now(),
                list: lists,
            });
        }

        if (Date.now() - JSON.parse(localStorage.lists)?.timestamp > 3e5) {
            var _resp = await fetch(`https://api-game.rivet.gg/v1/matchmaker/lobbies/list`);
            var lists = await _resp.json();

            localStorage.lists = JSON.stringify({
                timestamp: Date.now(),
                list: lists,
            });

            console.log('Refreshed server list.');
        }
    }, 5000);

    const modeHTML = document.createElement("div");
    document.body.appendChild(modeHTML);
    modeHTML.innerHTML = `
<div class='parent' id='ServerSelector' style='user-select:none; position:fixed; top:25%; right:0.5%; text-align:center; width:15vw; font-family:Ubuntu; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'><div class='child' style='line-height:2vh; opacity:75%'>
        TAB to show server selector
        <br>
        <p style="font-size:12px">Created by Altanis and Bismuth</p>
        <hr>
    </div>
    <p style="font-size:10px">Game Mode</p>
    <button class='child' type='button' id='ffa' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[7]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>FFA</button>
    <button class='child' type='button' id='survival' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[6]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>SURV</button>
    <button class='child' type='button' id='teams' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[5]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>2TDM</button>
    <button class='child' type='button' id='4teams' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[4]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>4TDM</button>
    <button class='child' type='button' id='dom' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[3]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>DOM</button>
    <button class='child' type='button' id='tag' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[2]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>TAG</button>
    <button class='child' type='button' id='maze' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[1]}; color:#FFFFFF; font-style:normal; font-size:0.9vw;${textShadow}'>MAZE</button>
    <button class='child' type='button' id='sandbox' value='mode' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[0]}; color:#FFFFFF; font-style:normal; font-size:0.9vw;${textShadow}'>SBX</button>
    <p style="font-size:10px">Region</p>
    <button class='child' type='button' id='do-sfo' value='region' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[3]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>SFO</button>
    <button class='child' type='button' id='do-nyc' value='region' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[2]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>NYC</button>
    <button class='child' type='button' id='do-fra' value='region' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[6]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>FRA</button>
    <button class='child' type='button' id='do-sgp' value='region' style='width:3.5vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[5]}; color:#FFFFFF; font-style:normal; font-size:0.9vw;${textShadow}'>SGP</button>
    <div class='parent' id='choice' style='user-select:none; position:relative; top:65%; left:0.5%; text-align:center; width:15vw; font-family:Ubuntu; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'>
    <br>
</div>
</div>
`
    document.getElementById('ServerSelector').style.display = 'block';
    for (let mode of modes) {
        addButtonListener(mode);
    }
    for (let region of regions) {
        addButtonListener(region);
    }
    function refreshHTML() {
        let json = `<div class='parent' id='choice' style='user-select:none; position:relative; top:65%; left:0.5%; text-align:center; width:15vw; font-family:Ubuntu; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'><p style="font-size:12px">   </p><div class='child' style='line-height:2vh; opacity:75%'> Servers for ${choices.mode} ${choices.region}<hr></div>`;
        for (let n = 0; n < serverWithoutCSS[choices.mode][choices.region].length; n++) {
            json += `<button class='child' type='button' id='choice${n}'value='${n}'style='width:6vw; height:3vh; border-radius: 0.5vw; font-family:Ubuntu; opacity:60%; background:${colors[n % 8]}; color:#FFFFFF; font-style:normal; font-size:0.9vw; ${textShadow}'> ${currentServer.includes(serverWithoutCSS[choices.mode][choices.region][n].slice(0,8))? '>': ''}${serverWithoutCSS[choices.mode][choices.region][n].slice(0,8)}</button>`;
        }
        document.getElementById('choice').innerHTML = `${json}`;
        for (let n = 0; n < serverWithoutCSS[choices.mode][choices.region].length; n++) {
            addButtonListener('choice'+n);
        }
    }
    function buttonAction(id) {
        let button = document.getElementById(id);
        if (button.value === 'mode') {
            choices.mode = id;
            fetchServer(choices.mode, choices.region, 3);
        }
        else if (button.value === 'region') {
            choices.region = id;
            fetchServer(choices.mode, choices.region, 3);
        }
        else if (button.value === 'copy') {
            GM_setClipboard("diep.io/#" + getServerLink(currentServer.split("://")[1].split("-80.lobby")[0]).toUpperCase());
        }
        else {
            (connectTo(choices.mode, choices.region, button.value));
        }
        refreshHTML();
    }
    function addButtonListener(id) {
        document.getElementById(id).addEventListener("click", function() {buttonAction(id)});
        document.getElementById(id).addEventListener("mouseenter", function() {lightenColor(id)});
        document.getElementById(id).addEventListener("mouseleave", function() {resetColor(id)});
    }
    function lightenColor(id) {
        document.getElementById(id).style.opacity = '100%'
    }
    function resetColor(id) {
        document.getElementById(id).style.opacity = '60%'
    }
    const choices = {
        mode: 'ffa',
        region: 'do-sfo'
    }
    const serverWithoutCSS = {
        "ffa": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "survival": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "teams": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "4teams": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "dom": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "tag": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "maze": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
        "sandbox": {
            "do-sfo": [],
            "do-nyc": [],
            "do-fra": [],
            "do-sgp": []
        },
    };

    const GAMEMODES_MAP = ['survival', 'tag', '4teams', 'sandbox', 'maze', 'dom', 'ffa', 'teams'];
    const REGIONS_MAP = ['do-fra', 'do-sgp', 'do-sfo', 'do-nyc'];

    var do_connect = false;
    var currentServer = '';
    var override = false;
    async function fetchServer(mode, region) {
        const body = JSON.parse(localStorage.lists)?.list;

        if (!body.hasOwnProperty('game_modes') && !body.hasOwnProperty('message')) return alert('API of Rivet is down!');
        if (body.message === 'too many requests') return alert('Ratelimit reached! Wait 15 minutes.');

        PLAYER_COUNT = 0;
        body.game_modes.forEach(function(g) { g.regions.forEach(function(r) { r.lobbies.forEach(function(l) { PLAYER_COUNT += l.total_player_count }); }); });

        const lobbies = body.game_modes[GAMEMODES_MAP.indexOf(mode)]?.regions[REGIONS_MAP.indexOf(region)]?.lobbies;
        if (!lobbies) return alert('Very strange... no lobbies exist...');

        lobbies.forEach(function({ lobby_id }) {
            lobby_id = `${lobby_id}-80.lobby.${region}.hiss.io:443`;
            if (!serverWithoutCSS[mode][region].some(function(host) { return host === lobby_id })) {
                serverWithoutCSS[mode][region].push(lobby_id);
            }
        });

        refreshHTML();
    }
    function appendServers(mode, region) {
        fetchServer(mode, region);
    }
    function connectTo(mode, region, number) {
        if (!serverWithoutCSS[mode][region][number]) return;
        currentServer = "wss://" + serverWithoutCSS[mode][region][number];
        do_connect = true;
        unsafeWindow.input.execute('lb_reconnect');
    }
    unsafeWindow.servers = serverWithoutCSS;
    unsafeWindow.WebSocket = new Proxy(WebSocket,{
        construct(t, args) {
            if (do_connect) args[0] = currentServer;
            currentServer = args[0];
            unsafeWindow.serverURL = args[0];
            do_connect = false;
            override = true;
            return Reflect.construct(t, args)}
    });
    var _fetch = unsafeWindow.fetch;
    unsafeWindow.fetch = function(endpoint, opts) {
        return _fetch(endpoint, opts)
            .then(function(response) {
            return new Promise(function(res) {
                response.clone().json()
                    .then(function(body) {
                    if (!override) return res(response);

                    body.lobby.lobby_id = currentServer.split('wss://')[1].split('-80.lobby')[0];
                    body.lobby.region.region_id = choices.region;
                    const blob = new Blob([JSON.stringify(body)], { type: 'application/json' });
                    return res(new Response(blob));
                    override = false;
                })
                    .catch(function(er) {
                    return res(response);
                });
            });
        });
    }
    document.body.onkeydown = function(e) {
        if (String.fromCharCode(e.keyCode) === '\t') {
            if (document.getElementById('ServerSelector').style.display === "none") {
                document.getElementById('ServerSelector').style.display = "block";
                document.getElementById('choice').style.display = "block";
            } else {
                document.getElementById('ServerSelector').style.display = "none";
                document.getElementById('choice').style.display = "none";
            }
        }
    }
    function getServerLink(server) {
        let link = '';
        for (const char of server) {
            const code = char.charCodeAt(0);
            const value = (`00${code.toString(16)}`).slice(-2);
            link += value.split("").reverse().join("");
        }
        return link;
    }

    async function calcPlayerCount() {
        const body = JSON.parse(localStorage.lists)?.list;

        if (!body.hasOwnProperty('game_modes') && !body.hasOwnProperty('message')) return alert('API of Rivet is down!');
        if (body.message === 'too many requests') return alert('Ratelimit reached! Wait 15 minutes.');

        PLAYER_COUNT = 0;
        body.game_modes.forEach(function(g) { g.regions.forEach(function(r) { r.lobbies.forEach(function(l) { PLAYER_COUNT += l.total_player_count }); }); });
    }

    calcPlayerCount();
    setInterval(calcPlayerCount, 60000);

    const crx = CanvasRenderingContext2D.prototype;

    crx.fillText = new Proxy(crx.fillText, {
        apply(f, _this, args) {
            if (args[0].includes('ms do'))
                args[0] += ` ‖ ${PLAYER_COUNT} players`;
            return f.apply(_this, args);
        }
    });

    crx.strokeText = new Proxy(crx.strokeText, {
        apply(f, _this, args) {
            if (args[0].includes('ms do'))
                args[0] += ` ‖ ${PLAYER_COUNT} players`;
            return f.apply(_this, args);
        }
    });

    crx.measureText = new Proxy(crx.measureText, {
        apply(f, _this, args) {
            if (args[0].includes('ms do'))
                args[0] += ` ‖ ${PLAYER_COUNT} players`;
            return f.apply(_this, args);
        }
    });
})();

QingJ © 2025

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