The Gaming Guru Community Script

A Community Script for Krunker

// ==UserScript==
// @name         The Gaming Guru Community Script
// @namespace    https://skidlamer.github.io/
// @version      0.1
// @description  A Community Script for Krunker
// @author       The Gaming Guru Community
// @iconURL      https://cdn.discordapp.com/icons/692606346645733396/2c8c01e76973634afcaec17d22ba5e80.webp?size=128
// @match        *://krunker.io/*
// @grant        none
// ==/UserScript==

(function(script, state) {
    'use strict';

    const states = {
        updating:"GAME UPDATING\n",
        disconect:"DISCONNECTED\n",
        connecting:"CONNECTING...\n",
        ready:"CLICK TO PLAY\n",
    }

    var me;
    var GUI;
    var showMenu = true;
    var menuDirty = true;
    var features = [];
    var updatedFeat = new Map();
    var players = new Map();
    var vars = new Map();
    var downKeys = new Set();

    let setVars = function() {
        vars.set("isYou", {regex:/this\['\w+']=k,this\['(\w+)']=w,this\['\w+']=!0x0/,pos:1})
        vars.set("inView", {regex:/if\(!\w+\['(\w+)']\)continue/,pos:1})
        for (const [name, object] of vars.entries()) {
            let result = object.regex.exec(script);
            if ( result ) {
                object.val = result[object.pos];
                console.log("found: ", name, " at ", result.index, " value: ", object.val);
            } else {
                object.val = null;
                alert("Failed to find ", name);
            }
        }
    }

    let decodeText = function(str, array, xor) {
        for (var i = 0, il = array.byteLength; i < il; i ++) {
            str += String.fromCharCode(array.getUint8(i) ^ xor);
        }
        try {
            return decodeURIComponent( escape( str ) );
        } catch ( e ) {
            return str;
        }
    }

    let getVersion = function() {
		const elems = document.getElementsByClassName('terms');
		const version = elems[elems.length - 1].innerText;
        return version;
	}

    let saveAs = function(name, data) {
        let blob = new Blob([data], {type: 'text/plain'});
        let el = window.document.createElement("a");
        el.href = window.URL.createObjectURL(blob);
        el.download = name;
        document.body.appendChild(el);
        el.click();
        document.body.removeChild(el);
    }

    let isDefined = function(object) {
        return void 0 !== object;
    }

    let isType = function(item, type) {
        return typeof item === type;
    }

    let addObserver = function(elm, check, callback, onshow = true) {
        return new MutationObserver((mutationsList, observer) => {
            if (check == 'src' || onshow && mutationsList[0].target.style.display == 'block' || !onshow) {
                callback(mutationsList[0].target);
            }
        }).observe(elm, check == 'childList' ? {
            childList: true
        } : {
            attributes: true,
            attributeFilter: [check]
        });
    }

    let addListener = function(elm, type, callback = null) {
        if (!isDefined(elm)) { alert("Failed creating " + type + "listener"); return }
        elm.addEventListener(type, event => callback(event));
    }

    //Storage
    let canStore = (typeof(Storage) !== "undefined");
    let saveVal = function(name, val) {
        if (canStore) localStorage.setItem(name, val);
    }
    let deleteVal = function(name) {
        if (canStore) localStorage.removeItem(name);
    }
    let getSavedVal = function(name) {
        if (canStore) return localStorage.getItem(name);
        return null;
    }

    //Features
    let newFeature = (name, keyBind, array, myFunction = null) => {
        const cStruct = (...keys) => ((...v) => keys.reduce((o, k, i) => {
            o[k] = v[i];
            return o
        }, {}));
        let item = [];
        const myStruct = cStruct('name', 'key', 'value', 'valueStr', 'container', 'myFunction')
        const value = parseInt(getSavedVal("utilities_" + name) || 0);
        const feature = myStruct(name, keyBind, value, array.length ? array[value] : '', array, myFunction);
        if (array.length || myFunction) features.push(feature);
        item.push(feature);
        return item;
    }

    let getFeature = (name) => {
        for (const feature of features) {
            if (feature.name.toLowerCase() === name.toLowerCase()) {
                return feature;
            }
        }
        return null;
    }

    let onUpdated = (feature) => {
        window.SOUND.play('tick_0', 0.1);
        if (feature.container.length) {
            feature.value += 1;
            if (feature.value > feature.container.length - 1) {
                feature.value = 0;
            }
            feature.valueStr = feature.container[feature.value];
            saveVal("utilities_" + feature.name, feature.value);
        }
        if (feature.container.length == 2 && feature.container[0] == 'Off' && feature.container[1] == 'On') {
            console.debug(feature.name, " is now ", feature.valueStr);
        }

        if (!updatedFeat.has(feature.name)) {
            console.debug(feature.name, " - Update Pending ")
            updatedFeat.set(feature.name, feature);
        }

        menuDirty = true;
    }

    // keyDown
    let keyDown = (key) => downKeys.has(key)

    // onTick Function
    let onTick = function(game, delta) {
        if (!isDefined(me) || !me || !me.active) return;

        const featureBhop = getFeature('Bhop');
        if (isDefined(featureBhop) && featureBhop.value) {
            if (keyDown("Space") || featureBhop.value !== 2 && featureBhop.value !== 4) {
                game.controls.keys[game.controls.jumpKey] ^= 1;
                game.controls.keys[game.controls.crouchKey] = (me.yVel < -0.04 && me.canSlide) && featureBhop.value !== 1 && featureBhop.value !== 2 ? 1 : 0;
            }

        }
    }

    // onInitialize
    let initialize = function() {

        //Add Features
        newFeature('ESP', "5", ['Off', 'On']);
        newFeature('Bhop', "6", ['Off', 'Auto Jump', 'Key Jump', 'Auto Slide', 'Key Slide']);

        // GameState
        addObserver(window.instructionHolder, 'style', (target) => {
            state = target.innerText;
            if (state.includes(states.updating)) {
                alert(state);
                location.reload();
            }
            else console.log(state)
        });

        // GUI Init
        GUI = document.getElementById("myGUI");
        if (GUI == null) {
            GUI = document.createElement('div');
            GUI.id = "myGUI";
            GUI.style = "float:left;width:100%;background-color: rgba(0,0,0,0.25);border-radius:5%;text-align:right;line-height:0.8;margin-top:5%;";
        }


        // Input/output
        let mouseDownL = false, mouseDownM = false, mouseDownR = false;

        addListener(document, "keyup", event => {
            if (downKeys.has(event.code)) downKeys.delete(event.code)
        })

        addListener(document, "keydown", event => {
            if ('INPUT' == document.activeElement.tagName || !window.endUI && window.endUI.style.display) return;
            switch (event.code) {
                case 'F1':
                    showMenu ^= 1;
                    window.SOUND.play('tick_0', 0.1);
                    menuDirty = showMenu;
                    break;
                case 'F2':
                    saveAs("game_" + getVersion() + ".js", script);
                    break;
                default:
                    if (!downKeys.has(event.code)) downKeys.add(event.code);
                    for (const feature of features) {
                        if (feature && "Digit" + feature.key == event.code) {
                            if (feature.container.length) onUpdated(feature);
                            else if (typeof feature.myFunction === "function") feature.myFunction();
                        }
                    }
                    break;
            }

        })

        addListener(document, "mousedown", event =>{
            const Left=0, Middle=1, Right=2;
            switch(event.button) {
                case Left: mouseDownL = true; break;
                case Middle: mouseDownM = true; break;
                case Right: mouseDownR = true; break;
                default: break;
            }
        });

        addListener(document, "mouseup", event =>{
            const Left=0, Middle=1, Right=2;
            switch(event.button) {
                case Left: mouseDownL = false; break;
                case Middle: mouseDownM = false; break;
                case Right: mouseDownR = false; break;
                default: break;
            }
        });

        //Hook Array
        Array.prototype.push = new Proxy(Array.prototype.push, {
            apply: function(target, that, [item, ...sub]) {
                if (!state) return target.apply(that, [item, ...sub]);
                let size = target.apply(that, [item, ...sub]);
                if (item instanceof Object && item.isPlayer) {
                    players.set(size - 1, item);
                }
                return size;
            }
        })

        //Hook Frame
        window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
            apply: function(target, that, args) {
                for (let [key, player] of players) {
                    if (player && player.active) {
                        if (player[vars.get("isYou").val]) {
                            me = player;
                            if (!player.update.proxy) {
                                player.update = new Proxy(player.update, {
                                    apply: function(target, that, [game, delta]) {
                                        that.update.proxy = true;
                                        onTick(game, delta);
                                        return target.apply(that, [game, delta]);
                                    }
                                })
                            }
                            else {
                                const topLeft = document.getElementById("topLeftHolder");
                                if (topLeft && GUI) {
                                    if (!topLeft.contains(GUI)) {
                                       topLeft.appendChild(GUI);
                                    } else if (showMenu) {
                                        if (menuDirty) {
                                            menuDirty = false;
                                            GUI.innerHTML = "<br><h4 style='text-align:center;color:#1E90FF;'>Community Skid</h4><hr>";
                                            for (const feature of features) {
                                                GUI.innerHTML += `<h5><span style='float:left;margin-left:10%;color:rgba(255,193,72,255)'>${feature.key}</span> <span style='float:left;margin-left:10%;color:rgba(255,255,255,255)'>${feature.name}</span> <span style=float:all;margin-right:10%;margin-left:10%;color:${feature.valueStr == "On" ? "#B2F252" : feature.valueStr == "Off" ? "#FF4444" : "#999EA5"};'>${feature.valueStr}</span></h5>`;
                                            }
                                            GUI.innerHTML += "<br>";
                                        }
                                    } else if (GUI.innerHTML) GUI.innerHTML = null;
                                }
                                for (let[name, feature] of updatedFeat) {
                                    updatedFeat.delete(name);
                                }
                            }
                        }
                        else {
                            const featureESP = getFeature('ESP');
                            if (isDefined(featureESP) && featureESP) {
                                player[vars.get("inView").val] = featureESP.value;
                            }
                        }
                    }
                }
                return target.apply(that, args);
            }
        })
    }

    // Hook Promise Respose to buff
    Response.prototype.arrayBuffer = new Proxy(Response.prototype.arrayBuffer, {
        apply: function(target, that, args) {
            const returnValue = target.apply(that, args);
            returnValue.then(buffer => {
                script = decodeText("", new DataView(buffer), 0x69);
                setVars();
                initialize();
            });
            return returnValue;
        }
    })

})("", null);