Zeph Menu

Speed Hack, Set KP (Work In Progress) Invisibility

当前为 2025-02-09 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Zeph Menu
// @match        *://kour.io/*
// @version      1.0.2
// @author       Happyjeffery
// @icon         https://i.imgur.com/11sYWVM.png
// @description  Speed Hack, Set KP (Work In Progress) Invisibility
// @run-at       document-start
// @grant        unsafeWindow
// @namespace    https://greasyfork.org/users/1369586
// ==/UserScript==

(function() {
    'use strict';

    /***************************************
     * Performance.now Speed Hack
     ***************************************/
    const originalPerfNow = performance.now.bind(performance);
    function updatePerformanceNow(multiplier) {
        if (multiplier === 1) {
            performance.now = originalPerfNow;
        } else {
            performance.now = new Proxy(originalPerfNow, {
                apply: function(target, thisArg, argArray) {
                    try {
                        throw new Error();
                    } catch (e) {
                        if (!e.stack.includes("invoke_")) {
                            return target.apply(thisArg, argArray) * multiplier;
                        }
                    }
                    return target.apply(thisArg, argArray);
                }
            });
        }
    }
    updatePerformanceNow(1);

    /***************************************
     * Invisibility WebSocket Hook
     *
     * Wraps both addEventListener and the onmessage setter so that incoming
     * messages with the damage signature are blocked when invisibility is enabled.
     ***************************************/
    const wsInstances = [];  // Store all open WebSocket instances.
    const OriginalWebSocket = unsafeWindow.WebSocket;
    function hookOnMessage(ws) {
        // Wrap addEventListener("message", ...)
        const originalAddEventListener = ws.addEventListener;
        ws.addEventListener = function(type, listener, options) {
            if (type === "message") {
                const wrappedListener = function(event) {
                    try {
                        if (event.data && typeof event.data !== "string") {
                            const data = new Uint8Array(event.data);
                            const hexString = Array.from(data)
                                .map(b => b.toString(16).padStart(2, '0'))
                                .join(" ");
                            const damageSignature = "f3 04 c8 02 f5 15 04";
                            if (hexString.startsWith(damageSignature) && kourInstance.config.Invisible) {
                                return; // Block this damage packet.
                            }
                        }
                    } catch (e) { /* ignore errors */ }
                    listener.call(this, event);
                };
                return originalAddEventListener.call(this, type, wrappedListener, options);
            } else {
                return originalAddEventListener.call(this, type, listener, options);
            }
        };

        // Hook the onmessage property setter.
        const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(ws), 'onmessage');
        Object.defineProperty(ws, 'onmessage', {
            set: function(fn) {
                const wrapped = function(event) {
                    try {
                        if (event.data && typeof event.data !== "string") {
                            const data = new Uint8Array(event.data);
                            const hexString = Array.from(data)
                                .map(b => b.toString(16).padStart(2, '0'))
                                .join(" ");
                            const damageSignature = "f3 04 c8 02 f5 15 04";
                            if (hexString.startsWith(damageSignature) && kourInstance.config.Invisible) {
                                return;
                            }
                        }
                    } catch (e) { }
                    fn(event);
                };
                descriptor.set.call(this, wrapped);
            },
            get: function() {
                return descriptor.get.call(this);
            }
        });
    }
    unsafeWindow.WebSocket = function(...args) {
        const ws = new OriginalWebSocket(...args);
        wsInstances.push(ws);
        hookOnMessage(ws);
        return ws;
    };
    unsafeWindow.WebSocket.prototype = OriginalWebSocket.prototype;

    /***************************************
     * Minimal Kour Config Storage
     ***************************************/
    class Kour {
        constructor() {
            this.config = {
                Invisible: true  // When true, damage packets are blocked.
            };
        }
    }
    const kourInstance = new Kour();
    unsafeWindow.kourInstance = kourInstance;

    /***************************************
     * Admin Panel: Set KP (Work in progress)
     ***************************************/
    function setKP() {
        let kpValue = prompt("Enter KP value:", "35");
        if (!kpValue) return;
        const numKP = Number(kpValue);
        if (isNaN(numKP)) {
            console.error("Invalid KP value entered.");
            return;
        }
        if (typeof unityInstance !== 'undefined' && typeof unityInstance.SendMessage === 'function') {
            try {
                // Send numeric KP value – adjust the receiver method if needed.
                unityInstance.SendMessage('MainManager', 'OnReceivedIsAdmin', numKP);
                console.log(`[Zeph Menu] Sent KP value ${numKP} via SendMessage.`);
            } catch (e) {
                console.error("[Zeph Menu] SendMessage failed:", e);
            }
        } else {
            console.error("[Zeph Menu] unityInstance not found.");
        }
        unsafeWindow.kpValue = numKP;
    }

    /***************************************
     * Force Update of WebSocket Handlers on Invisibility Toggle
     ***************************************/
    function refreshWebSocketHandlers() {
        wsInstances.forEach(ws => {
            try {
                let current = ws.onmessage;
                ws.onmessage = current; // Reassign to trigger the setter.
            } catch (e) { /* ignore errors */ }
        });
    }

    /***************************************
     * Create UI (toggled with the "o" key)
     ***************************************/
    function createUI() {
        const menu = document.createElement('div');
        menu.id = "zephMenu";
        Object.assign(menu.style, {
            position: "fixed",
            top: "50px",
            right: "50px",
            width: "250px",
            backgroundColor: "#8b008b",
            color: "#fff",
            padding: "10px",
            zIndex: "10000",
            fontFamily: "Arial, sans-serif",
            fontSize: "14px",
            borderRadius: "5px",
            display: "none"
        });

        // Header
        const header = document.createElement("div");
        header.textContent = "Zeph Menu";
        header.style.textAlign = "center";
        header.style.fontWeight = "bold";
        header.style.marginBottom = "10px";
        menu.appendChild(header);

        // Set KP Button with "(Work in progress)"
        const adminBtn = document.createElement("button");
        adminBtn.textContent = "Set KP (Work in progress)";
        Object.assign(adminBtn.style, {
            width: "100%",
            margin: "5px 0",
            padding: "5px",
            cursor: "pointer"
        });
        adminBtn.addEventListener("click", setKP);
        menu.appendChild(adminBtn);

        // Speed Hack Slider (max 6×)
        const speedContainer = document.createElement("div");
        speedContainer.style.margin = "10px 0";
        const speedLabel = document.createElement("label");
        speedLabel.textContent = "Speed Hack Multiplier: ";
        speedContainer.appendChild(speedLabel);
        const speedValue = document.createElement("span");
        speedValue.textContent = "1x";
        speedContainer.appendChild(speedValue);
        const speedSlider = document.createElement("input");
        speedSlider.type = "range";
        speedSlider.min = "1";
        speedSlider.max = "6"; // Maximum 6×
        speedSlider.step = "0.5";
        speedSlider.value = "1";
        speedSlider.style.width = "100%";
        speedSlider.addEventListener("input", function() {
            let multiplier = parseFloat(speedSlider.value);
            speedValue.textContent = multiplier.toFixed(1) + "x";
            updatePerformanceNow(multiplier);
        });
        speedContainer.appendChild(speedSlider);
        menu.appendChild(speedContainer);

        // Invisibility Toggle
        const invisContainer = document.createElement("div");
        const invisCheckbox = document.createElement("input");
        invisCheckbox.type = "checkbox";
        invisCheckbox.id = "invisToggle";
        invisCheckbox.checked = kourInstance.config.Invisible;
        invisCheckbox.addEventListener("change", function() {
            kourInstance.config.Invisible = this.checked;
            console.log("Invisibility set to " + this.checked);
            refreshWebSocketHandlers();
        });
        const invisLabel = document.createElement("label");
        invisLabel.htmlFor = "invisToggle";
        invisLabel.textContent = " Invisible";
        invisContainer.appendChild(invisCheckbox);
        invisContainer.appendChild(invisLabel);
        menu.appendChild(invisContainer);

        document.body.appendChild(menu);
    }

    // Toggle the UI when pressing the "o" key (unless typing in an input/textarea)
    document.addEventListener("keydown", function(e) {
        if (e.key === "o" && !e.target.matches("input, textarea")) {
            const menu = document.getElementById("zephMenu");
            if (menu) {
                menu.style.display = (menu.style.display === "none" ? "block" : "none");
            }
        }
    });

    window.addEventListener("load", createUI);
})();