MacPS Dropdown

Allows for people to join the private server whenever it's open.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

// ==UserScript==
// @name         MacPS Dropdown
// @author       Mac
// @description Allows for people to join the private server whenever it's open.
// @version      1.34
// @namespace    MacPS
// @license MIT
// @icon https://cavegame.io/asset/scaled/redsand.png
// @antifeature remote-config
// @match        https://cavegame.io/*
// @match        https://mineroyale.io/*
// @match        http://localhost:8080/*
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @connect      drive.google.com
// @connect      drive.usercontent.google.com
// @connect      trycloudflare.com
// @connect      *.trycloudflare.com
// ==/UserScript==

(() => {

    const TARGET = "cavegame-io-servers";
    const DRIVE_URL = "https://drive.google.com/uc?export=download&id=1F8AfmLdeXXcpdEGCm04hKYY2T22gbVmz";
    const MACPS_ID = "macps-option";
    const STORAGE_KEY = "macps-last-selected";

    const FAVICON_URL = "https://cavegame.io/asset/scaled/redsand.png";
    const TITLE_TEXT = "Cavegame.io - Modded";

    let currentIP = "";
    let lastState = "Initializing";
    let driveBusy = false;
    let pingBusy = false;

    const saveSelection = v => v && localStorage.setItem(STORAGE_KEY, v);
    const getSavedSelection = () => localStorage.getItem(STORAGE_KEY);

    function applyMeta() {
        document.title = TITLE_TEXT;

        const link = document.querySelector("link[rel*='icon']");
        if (link && link.href !== FAVICON_URL) {
            link.href = FAVICON_URL;
        }
    }

    applyMeta();

    setInterval(applyMeta, 1500);

    function setPlayButtonLocked(locked) {
        const el = document.getElementById("main-play-btn-cont");
        if (!el) return;
        el.style.pointerEvents = locked ? "none" : "";
        el.style.opacity = locked ? "0.5" : "";
    }

    function setLocked(select, locked) {
        if (select) select.disabled = locked;
    }

    function applySelection(select) {
        const saved = getSavedSelection();
        const macps = document.getElementById(MACPS_ID)?.value;
        const target = saved || macps;
        if (!target) return;

        const exists = [...select.options].some(o => o.value === target);
        if (!exists) return;

        select.value = target;
        select.dispatchEvent(new Event("change", { bubbles: true }));
    }

    function injectDropdown() {
        const select = document.querySelector("#select-server");
        if (!select) return;

        let opt = document.getElementById(MACPS_ID);

        if (!opt) {
            opt = document.createElement("option");
            opt.id = MACPS_ID;
            select.appendChild(opt);
        }

        opt.value = currentIP ? `wss://${currentIP}` : "__MACPS_OFFLINE__";
        opt.textContent = `MacPS - ${lastState}`;

        applySelection(select);
        setLocked(select, lastState === "Initializing");
        setPlayButtonLocked(lastState === "Initializing");
    }

    function updateDropdown() {
        const opt = document.getElementById(MACPS_ID);
        const select = document.querySelector("#select-server");

        if (opt) {
            opt.value = currentIP ? `wss://${currentIP}` : "__MACPS_OFFLINE__";
            opt.textContent = `MacPS - ${lastState}`;
        }

        setLocked(select, lastState === "Initializing");
        setPlayButtonLocked(lastState === "Initializing");
    }

    document.addEventListener("change", e => {
        if (e.target?.id !== "select-server") return;
        saveSelection(e.target.value);
    });

    function fetchDrive(cb) {
        if (driveBusy) return;
        driveBusy = true;

        GM_xmlhttpRequest({
            method: "GET",
            url: DRIVE_URL + "&t=" + Date.now(),
            timeout: 4000,

            onload: res => {
                driveBusy = false;

                const raw = (res.responseText || "").trim();
                if (!raw.startsWith("wss://")) return;

                const newIP = raw.replace("wss://", "").replace(/\/$/, "");

                if (newIP !== currentIP) {
                    currentIP = newIP;
                    lastState = "Pinging";
                    updateDropdown();
                    cb?.();
                }
            },

            onerror: () => driveBusy = false,
            ontimeout: () => driveBusy = false
        });
    }

    function ping(ip) {
        if (!ip || pingBusy) return;
        pingBusy = true;

        GM_xmlhttpRequest({
            method: "GET",
            url: `https://${ip}?t=${Date.now()}`,
            timeout: 4000,

            onload: res => {
                const t = (res.responseText || "").trim();

                if (t.includes("OK")) lastState = "Online";
                else if (res.status === 502) lastState = "Idle";
                else {
                    lastState = "Offline";
                    fetchDrive(() => ping(currentIP));
                }

                pingBusy = false;
                updateDropdown();
            },

            onerror: () => {
                pingBusy = false;
                lastState = "Offline";
                fetchDrive(() => ping(currentIP));
                updateDropdown();
            },

            ontimeout: () => {
                pingBusy = false;
                lastState = "Offline";
                fetchDrive(() => ping(currentIP));
                updateDropdown();
            }
        });
    }

    function run() {
        if (!currentIP) fetchDrive(() => ping(currentIP));
        else ping(currentIP);
    }

    const origFetch = unsafeWindow.fetch;

    unsafeWindow.fetch = function (...args) {
        const url = args[0]?.toString?.() || args[0];

        if (typeof url === "string" && url.includes(TARGET)) {
            return origFetch.apply(this, args).then(res => {
                setTimeout(() => {
                    injectDropdown();
                    run();
                }, 0);
                return res;
            });
        }

        return origFetch.apply(this, args);
    };

    const open = XMLHttpRequest.prototype.open;
    const send = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function (m, url, ...r) {
        this._url = url;
        return open.call(this, m, url, ...r);
    };

    XMLHttpRequest.prototype.send = function (...args) {
        if (this._url?.includes(TARGET)) {
            this.addEventListener("load", () => {
                setTimeout(() => {
                    injectDropdown();
                    run();
                }, 0);
            });
        }
        return send.apply(this, args);
    };

})();