Kour.io Zeph Menu

Speed Hack, Set KP (Work In Progress) Invisibility

目前為 2025-04-04 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Kour.io Zeph Menu
// @match        *://kour.io/*
// @version      1.0.4
// @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
     ***************************************/
    const wsInstances = [];  // Store all open WebSocket instances.
    const OriginalWebSocket = unsafeWindow.WebSocket;
    function hookOnMessage(ws) {
        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) { }
                    listener.call(this, event);
                };
                return originalAddEventListener.call(this, type, wrappedListener, options);
            } else {
                return originalAddEventListener.call(this, type, listener, options);
            }
        };

        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;


    class Kour {
        constructor() {
            this.config = {
                Invisible: true  
            };
        }
    }
    const kourInstance = new Kour();
    unsafeWindow.kourInstance = kourInstance;

    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 {
                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;
    }

    function refreshWebSocketHandlers() {
        wsInstances.forEach(ws => {
            try {
                let current = ws.onmessage;
                ws.onmessage = current; 
            } catch (e) { /* ignore errors */ }
        });
    }

    function createUI() {
        const menu = document.createElement('div');
        menu.id = "zephMenu";
        Object.assign(menu.style, {
            position: "fixed",
            top: "50px",
            right: "50px",
            width: "250px",
            backgroundColor: "#5a2d72", 
            color: "#fff",
            padding: "15px",
            zIndex: "10000",
            fontFamily: "Arial, sans-serif",
            fontSize: "16px",
            borderRadius: "8px",
            boxShadow: "0 4px 8px rgba(0,0,0,0.2)",
            display: "none",
            transition: "all 0.3s ease-in-out"
        });

        const header = document.createElement("div");
        header.textContent = "Zeph Menu";
        header.style.textAlign = "center";
        header.style.fontWeight = "bold";
        header.style.fontSize = "20px";
        header.style.marginBottom = "15px";
        menu.appendChild(header);

        const adminBtn = document.createElement("button");
        adminBtn.textContent = "Set KP (Work in progress)";
        Object.assign(adminBtn.style, {
            width: "100%",
            margin: "8px 0",
            padding: "8px",
            cursor: "pointer",
            backgroundColor: "#9b3e9f",
            border: "none",
            borderRadius: "5px",
            fontSize: "14px",
            color: "#fff",
            transition: "background-color 0.3s",
        });
        adminBtn.addEventListener("click", setKP);
        adminBtn.addEventListener("mouseover", () => adminBtn.style.backgroundColor = "#a74cbf");
        adminBtn.addEventListener("mouseout", () => adminBtn.style.backgroundColor = "#9b3e9f");
        menu.appendChild(adminBtn);

        const speedContainer = document.createElement("div");
        speedContainer.style.margin = "15px 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);

        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);
    }

    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);
})();