Alguien Client - Survev.io Client

A client to enhance the survev.io in-game experience with many features, as well as future features.

当前为 2025-11-16 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Alguien Client - Survev.io Client
// @namespace    https://github.com/SoyAlguien0/AlguienClient
// @version      0.0.4
// @description  A client to enhance the survev.io in-game experience with many features, as well as future features.
// @author       SoyAlguien
// @license      AGPL-3.0
// @require      https://update.greasyfork.org/scripts/391611/743919/WSHook.js
// @run-at       document-end
// @match        *://survev.io/*
// @match        *://66.179.254.36/*
// @match        *://expandedwater.online/*
// @grant        none
// ==/UserScript==

class PingTest {
    constructor(selectedServer) {
        this.ptcDataBuf = new ArrayBuffer(1);
        this.test = {
            region: selectedServer.region,
            url: `wss://${selectedServer.url}/ptc`,
            ping: 9999,
            ws: null,
            sendTime: 0,
            retryCount: 0,
        };
    }
    startPingTest() {
        if (!this.test.ws) {
            const ws = new WebSocket(this.test.url);
            ws.binaryType = "arraybuffer";
            ws.onopen = () => {
                this.sendPing();
                this.test.retryCount = 0;
            };
            ws.onmessage = () => {
                const elapsed = (Date.now() - this.test.sendTime) / 1e3;
                this.test.ping = Math.round(elapsed * 1000);
                this.test.retryCount = 0;
                setTimeout(() => this.sendPing(), 200);
            };
            ws.onerror = () => {
                this.test.ping = null;
                this.test.retryCount++;
                if (this.test.retryCount < 5) {
                    setTimeout(() => this.startPingTest(), 2000);
                }
                else {
                    try {
                        ws.close();
                    }
                    catch { }
                    this.test.ws = null;
                }
            };
            ws.onclose = () => {
                this.test.ws = null;
            };
            this.test.ws = ws;
        }
    }
    sendPing() {
        if (this.test.ws && this.test.ws.readyState === WebSocket.OPEN) {
            this.test.sendTime = Date.now();
            this.test.ws.send(this.ptcDataBuf);
        }
    }
    getPingResult() {
        return {
            region: this.test.region,
            ping: this.test.ping,
        };
    }
}
class GameMod {
    constructor() {
        this.fpsCounter = null;
        this.pingCounter = null;
        this.killsCounter = null;
        this.menu = null;
        this.currentServer = null;
        this.pingTest = null;
        const settings = this.getSettings();
        this.kills = 0;
        this.isFpsVisible = true;
        this.isPingVisible = true;
        this.isKillsVisible = true;
        this.isMenuVisible = true;
        this.isClean = false;
        this.isFpsUncapped = settings["fps-uncap"] !== undefined ? !!settings["fps-uncap"] : true;
        this.setAnimationFrameCallback();
        this.initCounter("fpsCounter", this.updateFpsVisibility.bind(this));
        this.initCounter("pingCounter", this.updatePingVisibility.bind(this));
        this.initCounter("killsCounter", this.updateKillsVisibility.bind(this));
        this.initMenu();
        this.loadBackgroundFromLocalStorage();
        this.loadLocalStorage();
        this.startUpdateLoop();
        this.setupWeaponBorderHandler();
        this.setupKeyListeners();
    }
    init() {
        this.startUpdateLoop();
        this.pingShow();
        this.customUiElements();
    }
    getSettings() {
        return JSON.parse(localStorage.getItem("gameSettings") || "{}");
    }
    saveSettings() {
        localStorage.setItem("gameSettings", JSON.stringify({ "fps-uncap": this.isFpsUncapped }));
    }
    initCounter(id, updateVisibilityFn) {
        const el = document.createElement("div");
        el.id = id;
        Object.assign(el.style, {
            color: "white",
            backgroundColor: "rgba(0, 0, 0, 0.2)",
            padding: "5px 10px",
            marginTop: "10px",
            borderRadius: "5px",
            fontFamily: "Arial, sans-serif",
            fontSize: "14px",
            zIndex: "10000",
            pointerEvents: "none",
        });
        const uiTopLeft = document.getElementById("ui-top-left");
        if (uiTopLeft)
            uiTopLeft.appendChild(el);
        if (id === "fpsCounter")
            this.fpsCounter = el;
        if (id === "pingCounter")
            this.pingCounter = el;
        if (id === "killsCounter")
            this.killsCounter = el;
        updateVisibilityFn();
    }
    updateFpsVisibility() {
        this.updateVisibility("fpsCounter", this.isFpsVisible);
    }
    updateFpsToggle() {
        this.animationFrameCallback = this.isFpsUncapped
            ? (callback) => setTimeout(callback, 1)
            : (callback) => requestAnimationFrame(callback);
    }
    updatePingVisibility() {
        this.updateVisibility("pingCounter", this.isPingVisible);
    }
    updateKillsVisibility() {
        this.updateVisibility("killsCounter", this.isKillsVisible);
    }
    updateVisibility(id, isVisible) {
        const el = this[id];
        if (el) {
            el.style.display = isVisible ? "block" : "none";
            el.style.backgroundColor = isVisible ? "rgba(0, 0, 0, 0.2)" : "transparent";
        }
    }
    setAnimationFrameCallback() {
        this.animationFrameCallback = (callback) => setTimeout(callback, 1);
    }
    getKills() {
        const killElement = document.querySelector(".ui-player-kills.js-ui-player-kills");
        if (killElement) {
            const kills = Number.parseInt(killElement.textContent || "", 10);
            return Number.isNaN(kills) ? 0 : kills;
        }
        return 0;
    }
    startPingTest() {
        const currentUrl = globalThis.location.href;
        const isSpecialUrl = /\/#\w+/.test(currentUrl);
        const teamSelectElement = document.getElementById("team-server-select");
        const mainSelectElement = document.getElementById("server-select-main");
        const region = isSpecialUrl && teamSelectElement ? teamSelectElement.value : mainSelectElement ? mainSelectElement.value : null;
        if (region && region !== this.currentServer) {
            this.currentServer = region;
            this.resetPing();
            const servers = [
                { region: "NA", url: "usr.mathsiscoolfun.com:8001" },
                { region: "EU", url: "eur.mathsiscoolfun.com:8001" },
                { region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
                { region: "SA", url: "sa.mathsiscoolfun.com:8001" },
            ];
            const selectedServer = servers.find((server) => region.toUpperCase() === server.region.toUpperCase());
            if (selectedServer) {
                this.pingTest = new PingTest(selectedServer);
                this.pingTest.startPingTest();
            }
            else {
                this.resetPing();
            }
        }
    }
    resetPing() {
        if (this.pingTest?.test.ws) {
            try {
                this.pingTest.test.ws.close();
            }
            catch { }
            this.pingTest.test.ws = null;
        }
        this.pingTest = null;
    }
    saveBackgroundToLocalStorage(value) {
        if (typeof value === "string") {
            localStorage.setItem("lastBackgroundType", "url");
            localStorage.setItem("lastBackgroundValue", value);
        }
        else {
            localStorage.setItem("lastBackgroundType", "local");
            const reader = new FileReader();
            reader.onload = () => {
                if (typeof reader.result === "string")
                    localStorage.setItem("lastBackgroundValue", reader.result);
            };
            reader.readAsDataURL(value);
        }
    }
    loadBackgroundFromLocalStorage() {
        const backgroundType = localStorage.getItem("lastBackgroundType");
        const backgroundValue = localStorage.getItem("lastBackgroundValue");
        const backgroundElement = document.getElementById("background");
        if (backgroundElement && backgroundType && backgroundValue) {
            backgroundElement.style.backgroundImage = `url(${backgroundValue})`;
        }
    }
    loadLocalStorage() {
        try {
            const savedSettings = JSON.parse(localStorage.getItem("userSettings") || "null");
            if (savedSettings) {
                this.isFpsVisible = savedSettings.isFpsVisible ?? this.isFpsVisible;
                this.isPingVisible = savedSettings.isPingVisible ?? this.isPingVisible;
                this.isKillsVisible = savedSettings.isKillsVisible ?? this.isKillsVisible;
                this.isClean = savedSettings.isClean ?? this.isClean;
            }
        }
        catch { }
        this.updateKillsVisibility();
        this.updateFpsVisibility();
        this.updatePingVisibility();
    }
    updateHealthBars() {
        const healthBars = document.querySelectorAll("#ui-health-container");
        healthBars.forEach((container) => {
            const bar = container.querySelector("#ui-health-actual");
            if (bar) {
                const width = Math.round(Number.parseFloat(bar.style.width || "0"));
                let percentageText = container.querySelector(".health-text");
                if (!percentageText) {
                    percentageText = document.createElement("span");
                    percentageText.classList.add("health-text");
                    Object.assign(percentageText.style, {
                        width: "100%",
                        textAlign: "center",
                        marginTop: "5px",
                        color: "#333",
                        fontSize: "20px",
                        fontWeight: "bold",
                        position: "absolute",
                        zIndex: "10",
                    });
                    container.appendChild(percentageText);
                }
                percentageText.textContent = `${width}%`;
            }
        });
    }
    updateBoostBars() {
        const boostCounter = document.querySelector("#ui-boost-counter");
        if (!boostCounter)
            return;
        const boostBars = boostCounter.querySelectorAll(".ui-boost-base .ui-bar-inner");
        let totalBoost = 0;
        const weights = [25, 25, 40, 10];
        boostBars.forEach((bar, index) => {
            const width = Number.parseFloat(bar.style.width || "0");
            if (!Number.isNaN(width))
                totalBoost += width * (weights[index] / 100);
        });
        const averageBoost = Math.round(totalBoost);
        let boostDisplay = boostCounter.querySelector(".boost-display");
        if (!boostDisplay) {
            boostDisplay = document.createElement("div");
            boostDisplay.classList.add("boost-display");
            Object.assign(boostDisplay.style, {
                position: "absolute",
                bottom: "75px",
                right: "335px",
                color: "#FF901A",
                backgroundColor: "rgba(0, 0, 0, 0.4)",
                padding: "5px 10px",
                borderRadius: "5px",
                fontFamily: "Arial, sans-serif",
                fontSize: "14px",
                zIndex: "10",
                textAlign: "center",
            });
            boostCounter.appendChild(boostDisplay);
        }
        boostDisplay.textContent = `AD: ${averageBoost}%`;
    }
    setupWeaponBorderHandler() {
        const weaponContainers = Array.from(document.getElementsByClassName("ui-weapon-switch"));
        weaponContainers.forEach((container) => {
            container.style.border = container.id === "ui-weapon-id-4" ? "3px solid #2f4032" : "3px solid #FFFFFF";
        });
        const weaponNames = Array.from(document.getElementsByClassName("ui-weapon-name"));
        weaponNames.forEach((weaponNameElement) => {
            const weaponContainer = weaponNameElement.closest(".ui-weapon-switch");
            if (!weaponContainer)
                return;
            const observer = new MutationObserver(() => {
                const weaponName = (weaponNameElement.textContent || "").trim();
                let border = "#FFFFFF";
                switch (weaponName.toUpperCase()) {
                    case "CZ-3A1":
                    case "G18C":
                    case "M9":
                    case "M93R":
                    case "MAC-10":
                    case "MP5":
                    case "P30L":
                    case "DUAL P30L":
                    case "UMP9":
                    case "VECTOR":
                    case "VSS":
                    case "FLAMETHROWER":
                        border = "#FFAE00";
                        break;
                    case "AK-47":
                    case "OT-38":
                    case "OTS-38":
                    case "M39 EMR":
                    case "DP-28":
                    case "MOSIN-NAGANT":
                    case "SCAR-H":
                    case "SV-98":
                    case "M1 GARAND":
                    case "PKP PECHENEG":
                    case "AN-94":
                    case "BAR M1918":
                    case "BLR 81":
                    case "SVD-63":
                    case "M134":
                    case "GROZA":
                    case "GROZA-S":
                        border = "#007FFF";
                        break;
                    case "FAMAS":
                    case "M416":
                    case "M249":
                    case "QBB-97":
                    case "MK 12 SPR":
                    case "M4A1-S":
                    case "SCOUT ELITE":
                    case "L86A2":
                        border = "#0f690d";
                        break;
                    case "M870":
                    case "MP220":
                    case "SAIGA-12":
                    case "SPAS-12":
                    case "USAS-12":
                    case "SUPER 90":
                    case "LASR GUN":
                    case "M1100":
                        border = "#FF0000";
                        break;
                    case "MODEL 94":
                    case "PEACEMAKER":
                    case "MK45G":
                    case "M1911":
                    case "M1A1":
                        border = "#800080";
                        break;
                    case "DEAGLE 50":
                    case "RAINBOW BLASTER":
                        border = "#000000";
                        break;
                    case "AWM-S":
                    case "MK 20 SSR":
                        border = "#808000";
                        break;
                    case "POTATO CANNON":
                    case "SPUD GUN":
                        border = "#A52A2A";
                        break;
                    case "FLARE GUN":
                        border = "#FF4500";
                        break;
                    case "M79":
                        border = "#008080";
                        break;
                    case "HEART CANNON":
                        border = "#FFC0CB";
                        break;
                    default:
                        break;
                }
                if (weaponContainer.id !== "ui-weapon-id-4") {
                    weaponContainer.style.border = `3px solid ${border}`;
                }
            });
            observer.observe(weaponNameElement, { childList: true, characterData: true, subtree: true });
        });
    }
    updateUiElements() {
        const currentUrl = globalThis.location.href;
        const isSpecialUrl = /\/#\w+/.test(currentUrl);
        const playerOptions = document.getElementById("player-options");
        if (!playerOptions)
            return;
        const teamMenuContents = document.getElementById("team-menu-contents");
        const startMenuContainer = document.querySelector("#start-menu .play-button-container");
        if (isSpecialUrl && teamMenuContents && playerOptions.parentNode !== teamMenuContents) {
            teamMenuContents.appendChild(playerOptions);
        }
        else if (!isSpecialUrl && startMenuContainer && playerOptions.parentNode !== startMenuContainer) {
            const firstChild = startMenuContainer.firstChild;
            startMenuContainer.insertBefore(playerOptions, firstChild);
        }
        const teamMenu = document.getElementById("team-menu");
        if (teamMenu)
            teamMenu.style.height = "355px";
        const menuBlocks = document.querySelectorAll(".menu-block");
        menuBlocks.forEach((block) => { block.style.maxHeight = "355px"; });
    }
    updateCleanMode() {
        const leftColumn = document.getElementById("left-column");
        const newsBlock = document.getElementById("news-block");
        if (this.isClean) {
            if (leftColumn)
                leftColumn.style.display = "none";
            if (newsBlock)
                newsBlock.style.display = "none";
        }
        else {
            if (leftColumn)
                leftColumn.style.display = "block";
            if (newsBlock)
                newsBlock.style.display = "block";
        }
    }
    setupKeyListeners() {
        document.addEventListener("keydown", (event) => {
            if (event.key.toLowerCase() === "p")
                this.toggleMenuVisibility();
        });
    }
    initMenu() {
        const menu = document.createElement("div");
        menu.id = "soyAlguienMenu";
        Object.assign(menu.style, {
            backgroundColor: "rgba(0, 0, 0, 0.5)",
            padding: "15px",
            marginLeft: "15px",
            borderRadius: "10px",
            boxShadow: "0 4px 10px rgba(0, 0, 0, 0.3)",
            zIndex: "10001",
            width: "250px",
            fontFamily: "Arial, sans-serif",
            color: "#fff",
            maxHeight: "400px",
            overflowY: "auto",
        });
        const title = document.createElement("h2");
        title.textContent = "SoyAlguien Client";
        Object.assign(title.style, {
            margin: "0 0 10px",
            textAlign: "center",
            fontSize: "18px",
            color: "#FFAE00",
        });
        menu.appendChild(title);
        const updateLocalStorage = () => {
            localStorage.setItem("userSettings", JSON.stringify({
                isFpsVisible: this.isFpsVisible,
                isPingVisible: this.isPingVisible,
                isKillsVisible: this.isKillsVisible,
                isClean: this.isClean,
            }));
        };
        this.loadLocalStorage();
        const createToggleButton = (text, stateKey, onClick) => {
            const button = document.createElement("button");
            const state = !!this[stateKey];
            button.textContent = `${text} ${state ? "✅" : "❌"}`;
            Object.assign(button.style, {
                backgroundColor: state ? "#4CAF50" : "#FF0000",
                border: "none",
                color: "#fff",
                padding: "10px",
                borderRadius: "5px",
                width: "100%",
                marginBottom: "10px",
                fontSize: "14px",
                cursor: "pointer",
            });
            button.onclick = () => {
                this[stateKey] = !this[stateKey];
                onClick();
                const newState = !!this[stateKey];
                button.textContent = `${text} ${newState ? "✅" : "❌"}`;
                button.style.backgroundColor = newState ? "#4CAF50" : "#FF0000";
                updateLocalStorage();
            };
            return button;
        };
        menu.appendChild(createToggleButton("Show FPS", "isFpsVisible", this.updateFpsVisibility.bind(this)));
        menu.appendChild(createToggleButton("Show Ping", "isPingVisible", this.updatePingVisibility.bind(this)));
        menu.appendChild(createToggleButton("Show Kills", "isKillsVisible", this.updateKillsVisibility.bind(this)));
        menu.appendChild(createToggleButton("Clean Menu", "isClean", this.updateCleanMode.bind(this)));
        const hideShowToggle = document.createElement("button");
        hideShowToggle.textContent = `👀 Hide/Show Menu [P]`;
        Object.assign(hideShowToggle.style, {
            backgroundColor: "#6F42C1",
            border: "none",
            color: "#fff",
            padding: "10px",
            borderRadius: "5px",
            width: "100%",
            marginBottom: "10px",
            fontSize: "14px",
            cursor: "pointer",
        });
        hideShowToggle.onclick = () => this.toggleMenuVisibility();
        menu.appendChild(hideShowToggle);
        const backgroundToggle = document.createElement("button");
        backgroundToggle.textContent = `🎨 Change Background`;
        Object.assign(backgroundToggle.style, {
            backgroundColor: "#007BFF",
            border: "none",
            color: "#fff",
            padding: "10px",
            borderRadius: "5px",
            width: "100%",
            marginBottom: "10px",
            fontSize: "14px",
            cursor: "pointer",
        });
        backgroundToggle.onclick = () => {
            const backgroundElement = document.getElementById("background");
            if (!backgroundElement) {
                alert("Element with id 'background' not found.");
                return;
            }
            const choice = prompt("Enter '1' to provide a URL or '2' to upload a local image:");
            if (choice === "1") {
                const newBackgroundUrl = prompt("Enter the URL of the new background image:");
                if (newBackgroundUrl) {
                    backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
                    this.saveBackgroundToLocalStorage(newBackgroundUrl);
                    alert("Background updated successfully!");
                }
            }
            else if (choice === "2") {
                const fileInput = document.createElement("input");
                fileInput.type = "file";
                fileInput.accept = "image/*";
                fileInput.onchange = (event) => {
                    const file = event.target.files?.[0];
                    if (file) {
                        const reader = new FileReader();
                        reader.onload = () => {
                            if (typeof reader.result === "string") {
                                backgroundElement.style.backgroundImage = `url(${reader.result})`;
                                this.saveBackgroundToLocalStorage(file);
                                alert("Background updated successfully!");
                            }
                        };
                        reader.readAsDataURL(file);
                    }
                };
                fileInput.click();
            }
        };
        menu.appendChild(backgroundToggle);
        const moreSettingsButton = document.createElement("button");
        moreSettingsButton.textContent = "⚙️ More Settings";
        Object.assign(moreSettingsButton.style, {
            backgroundColor: "#1D1616",
            border: "none",
            color: "#fff",
            padding: "10px",
            borderRadius: "5px",
            width: "100%",
            fontSize: "14px",
            cursor: "pointer",
        });
        moreSettingsButton.onclick = () => this.openSubMenu();
        menu.appendChild(moreSettingsButton);
        globalThis.onload = () => {
            const savedBackground = localStorage.getItem("backgroundImage");
            if (savedBackground) {
                const backgroundElement = document.getElementById("background");
                if (backgroundElement)
                    backgroundElement.style.backgroundImage = `url(${savedBackground})`;
            }
        };
        const startRowTop = document.getElementById("start-row-top");
        if (startRowTop)
            startRowTop.appendChild(menu);
        this.menu = menu;
    }
    openSubMenu() {
        const overlay = document.createElement("div");
        const savedOpacity = localStorage.getItem("opacity") ?? "1";
        const savedScale = localStorage.getItem("scale") ?? "0.8";
        Object.assign(overlay.style, {
            position: "fixed",
            top: "0",
            left: "0",
            width: "100%",
            height: "100%",
            backgroundColor: "rgba(0, 0, 0, 0.7)",
            zIndex: "10002",
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
        });
        const subMenu = document.createElement("div");
        Object.assign(subMenu.style, {
            backgroundColor: "#333",
            padding: "20px",
            borderRadius: "15px",
            width: "400px",
            color: "#fff",
            textAlign: "left",
            zIndex: "10003",
            boxShadow: "0 4px 15px rgba(0, 0, 0, 0.5)",
        });
        const createSectionHeader = (text) => {
            const header = document.createElement("h3");
            header.textContent = text;
            Object.assign(header.style, {
                fontSize: "18px",
                fontWeight: "bold",
                color: "#FFD700",
                marginBottom: "10px",
            });
            return header;
        };
        const createSettingItem = (id, label, checked) => {
            const wrapper = document.createElement("div");
            Object.assign(wrapper.style, {
                display: "flex",
                alignItems: "center",
                padding: "10px",
                marginBottom: "10px",
                borderRadius: "8px",
                backgroundColor: "#444",
            });
            const checkbox = document.createElement("input");
            checkbox.id = id;
            checkbox.type = "checkbox";
            checkbox.checked = checked;
            Object.assign(checkbox.style, { marginRight: "10px", cursor: "pointer" });
            const labelText = document.createElement("p");
            labelText.textContent = label;
            Object.assign(labelText.style, { margin: "0", fontSize: "16px", color: "#fff" });
            wrapper.appendChild(checkbox);
            wrapper.appendChild(labelText);
            return wrapper;
        };
        const createCustomSlider = (id, min, max, step, value, onChange) => {
            const wrapper = document.createElement("div");
            Object.assign(wrapper.style, {
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                marginBottom: "10px",
            });
            const slider = document.createElement("input");
            slider.type = "range";
            slider.id = id;
            slider.min = String(min);
            (slider).max = String(max);
            (slider).step = String(step);
            (slider).value = value;
            Object.assign(slider.style, { flex: "1", marginRight: "10px" });
            const valueLabel = document.createElement("span");
            valueLabel.textContent = value;
            Object.assign(valueLabel.style, { minWidth: "30px", textAlign: "right", color: "#fff" });
            slider.oninput = () => {
                valueLabel.textContent = (slider).value;
                onChange((slider).value);
            };
            wrapper.appendChild(slider);
            wrapper.appendChild(valueLabel);
            return wrapper;
        };
        const titleClient = document.createElement("h2");
        titleClient.textContent = "Client Settings";
        Object.assign(titleClient.style, {
            margin: "0 0 20px",
            fontSize: "24px",
            fontWeight: "bold",
            color: "#FFAE00",
            textAlign: "center",
        });
        subMenu.appendChild(titleClient);
        subMenu.appendChild(createSectionHeader("FPS Uncap"));
        subMenu.appendChild(createSettingItem("fps-uncap", "Enable/disable FPS uncap", this.isFpsUncapped));
        const titleUI = document.createElement("h2");
        titleUI.textContent = "UI Settings";
        Object.assign(titleUI.style, {
            margin: "20px 0 20px",
            fontSize: "24px",
            fontWeight: "bold",
            color: "#FFAE00",
            textAlign: "center",
        });
        subMenu.appendChild(titleUI);
        subMenu.appendChild(createSectionHeader("Opacity"));
        subMenu.appendChild(createCustomSlider("opacity-slider", 0, 1, 0.01, savedOpacity, (value) => localStorage.setItem("opacity", value)));
        subMenu.appendChild(createSectionHeader("Scale"));
        subMenu.appendChild(createCustomSlider("scale-slider", 0.5, 1, 0.01, savedScale, (value) => localStorage.setItem("scale", value)));
        const closeButton = document.createElement("button");
        closeButton.textContent = "Close";
        Object.assign(closeButton.style, {
            backgroundColor: "#FF4D4D",
            border: "none",
            color: "#fff",
            padding: "10px 20px",
            borderRadius: "8px",
            marginTop: "20px",
            cursor: "pointer",
            fontSize: "16px",
            fontWeight: "bold",
            transition: "background-color 0.3s ease",
            width: "100%",
        });
        closeButton.onmouseenter = () => { closeButton.style.backgroundColor = "#FF3333"; };
        closeButton.onmouseleave = () => { closeButton.style.backgroundColor = "#FF4D4D"; };
        closeButton.onclick = () => {
            if (overlay.parentElement)
                document.body.removeChild(overlay);
        };
        subMenu.appendChild(closeButton);
        overlay.appendChild(subMenu);
        document.body.appendChild(overlay);
        this.attachSettingsEvents();
    }
    customUiElements() {
        const scale = parseFloat(localStorage.getItem("scale") || "0.8");
        const opacity = parseFloat(localStorage.getItem("opacity") || "1");
        const healthBoost = document.getElementById("ui-bottom-center-0");
        if (healthBoost) {
            healthBoost.style.transform = `translateX(-50%) scale(${scale})`;
            healthBoost.style.opacity = String(opacity);
            healthBoost.style.bottom = globalThis.innerWidth > 1200 ? `-${(1 - scale) * 20 + 2}px` : "";
        }
        const weapon = document.getElementById("ui-weapon-container");
        if (weapon) {
            weapon.style.scale = String(scale);
            weapon.style.opacity = String(opacity);
            weapon.style.transformOrigin = "right";
        }
        const inventory = document.getElementById("ui-right-center");
        if (inventory) {
            inventory.style.scale = String(scale * 1.1);
            inventory.style.opacity = String(opacity);
            inventory.style.marginTop = `-${(1 - scale) * 100}px`;
        }
        const info = document.getElementById("ui-top-left");
        if (info) {
            info.style.transformOrigin = "top left";
            info.style.scale = String(scale * 1.1);
            info.style.opacity = String(opacity);
        }
        const players = document.getElementById("ui-leaderboard-wrapper");
        if (players) {
            players.style.scale = String(scale);
            players.style.opacity = String(opacity);
            players.style.transformOrigin = "top right";
        }
        const killfeed = document.getElementById("ui-killfeed-wrapper");
        if (killfeed) {
            killfeed.style.scale = String(scale);
            killfeed.style.opacity = String(opacity);
            killfeed.style.transformOrigin = "right";
        }
        const ammo = document.getElementById("ui-equipped-ammo-wrapper");
        if (ammo) {
            ammo.style.opacity = String(opacity);
            ammo.style.transform = `translateX(-50%) scale(${scale})`;
            const bottomValue = 62 - (1 - scale) * 20;
            ammo.style.bottom = `${bottomValue}px`;
        }
        const gears = document.getElementById("ui-bottom-center-right");
        if (gears) {
            gears.style.opacity = String(opacity);
            gears.style.scale = String(scale);
        }
        const scopes = document.getElementById("ui-top-center-scopes");
        if (scopes) {
            scopes.style.opacity = String(opacity);
            scopes.style.scale = String(scale);
        }
    }
    attachSettingsEvents() {
        const fpsUncapCheckbox = document.querySelector("#fps-uncap");
        if (fpsUncapCheckbox) {
            fpsUncapCheckbox.addEventListener("change", (event) => {
                const target = event.target;
                this.isFpsUncapped = target.checked;
                this.saveSettings();
            });
        }
        const opacitySlider = document.querySelector("#opacity-slider");
        if (opacitySlider) {
            opacitySlider.addEventListener("input", (event) => {
                const target = event.target;
                localStorage.setItem("opacity", target.value);
                this.customUiElements();
            });
        }
        const scaleSlider = document.querySelector("#scale-slider");
        if (scaleSlider) {
            scaleSlider.addEventListener("input", (event) => {
                const target = event.target;
                localStorage.setItem("scale", target.value);
                this.customUiElements();
            });
        }
    }
    toggleMenuVisibility() {
        if (!this.menu)
            return;
        const isVisible = this.menu.style.display !== "none";
        this.menu.style.display = isVisible ? "none" : "block";
    }
    startUpdateLoop() {
        let lastFrameTime = performance.now();
        let frameCount = 0;
        let fps = 0;
        const loop = () => {
            const now = performance.now();
            const delta = now - lastFrameTime;
            frameCount++;
            if (delta >= 1000) {
                fps = Math.round((frameCount * 1000) / delta) * 2;
                frameCount = 0;
                lastFrameTime = now;
                this.kills = this.getKills();
                if (this.isFpsVisible && this.fpsCounter) {
                    this.fpsCounter.textContent = `FPS: ${Math.round(fps / 2)}`;
                }
                if (this.isKillsVisible && this.killsCounter) {
                    this.killsCounter.textContent = `Kills: ${this.kills}`;
                }
                if (this.isPingVisible && this.pingCounter && this.pingTest) {
                    const result = this.pingTest.getPingResult();
                    this.pingCounter.textContent = `PING: ${result.ping} ms`;
                }
            }
            this.startPingTest();
            this.updateFpsToggle();
            this.animationFrameCallback(() => loop());
            this.updateUiElements();
            this.updateCleanMode();
            this.updateBoostBars();
            this.updateHealthBars();
        };
        loop();
    }
    pingShow() {
        const serverSelect = document.getElementById("server-select-main");
        if (!serverSelect)
            return;
        const updateOptionWithPing = (optionElement, ping) => {
            const pingText = ` (${ping} ms)`;
            const originalText = optionElement.textContent?.replace(/\(\d+ ms\)/g, "").trim() || "";
            optionElement.textContent = `${originalText}${pingText}`;
            if (ping > 300) {
                optionElement.style.color = "red";
            }
            else if (ping > 200) {
                optionElement.style.color = "orange";
            }
            else if (ping > 100) {
                optionElement.style.color = "yellow";
            }
            else {
                optionElement.style.color = "green";
            }
        };
        const servers = [
            { region: "NA", url: "usr.mathsiscoolfun.com:8001" },
            { region: "EU", url: "eur.mathsiscoolfun.com:8001" },
            { region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
            { region: "SA", url: "sa.mathsiscoolfun.com:8001" },
        ];
        servers.forEach((server) => {
            const pingTest = new PingTest(server);
            pingTest.startPingTest();
            const intervalId = globalThis.setInterval(() => {
                const pingResult = pingTest.getPingResult();
                if (pingResult.ping !== 9999 && pingResult.ping !== null) {
                    const optionElement = serverSelect.querySelector(`option[value="${server.region.toLowerCase()}"]`);
                    if (optionElement) {
                        updateOptionWithPing(optionElement, pingResult.ping);
                    }
                    clearInterval(intervalId);
                }
            }, 2000);
        });
    }
}
const gameMod = new GameMod();