Neon's custom editor

A Mod to extend editor functionality.

// ==UserScript==
// @name         Neon's custom editor
// @namespace    http://tampermonkey.net/
// @version      v1.1.2
// @description  A Mod to extend editor functionality.
// @author       iNeonz
// @match        https://heav.io/game.html
// @match        https://hitbox.io/game.html
// @match        https://heav.io/game2.html
// @match        https://hitbox.io/game2.html
// @match        https://hitbox.io/game-beta.html
// @require      https://unpkg.com/blockly/blockly.min.js
// @icon         https://www.google.com/s2/favicons?sz=64&domain=heav.io
// @grant        none
// @run-at       document-start
// ==/UserScript==
const debug = () => {}; // This is here because i am lazy to remove every console.log in this script
debug("HELLO");
const version = "v1.0.9";
const codeNames = {};
const codeNamesRegex = {
    "simulation": {
        reg: /\];\}.{0,2}\(.{0,3}\) {var .{0,3},.{0,3},.{0,3},.{0,3},.{0,3},.{0,3};(.*?)\{throw new Error\("Failed to simulate(.*?)\);\}(.*?)\.step\((.*?)\);(.*?).{0,2}\(\);(.*?)\}.{0,2}\(\)/ig,
        verify: function(match)
        {
            //debug(match);
            let world = match[0].match(/this\..{2,2}\.step\(/ig)[0];
            let sim = match[0].split(";}")[1].split("(")[0];
            //debug(sim);
            let thisses = match[0].split("this.");
            //debug(thisses);
            for (let i of thisses){
                if (i.match("=")){
                    i = i.split("=")[0];
                }else{
                    i = null;
                }
            }
            thisses.filter(a => a != null);
            return [sim,thisses[1].split(".")[0],thisses[1].split(".")[1].split("(")[0],world.split("this.")[1].split(".")[0]];
        }
    },
}


function appendScript(link,head){
    let scr = document.createElement("script");
    scr.src = link;
    (head? document.head : document.body).appendChild(scr);
}


const symbolStepD = Symbol("SF");
const symbolStepVB = Symbol("Eb");
const testString = "eJw1jsEOgzAMQ%2F%2FF52pK08JofmXisglN2mkacEL8%2BxwCvThWHedteMIeY8InZA75hiwrdUOGqSQoLJeEO6wJbRZYR%2FFfVw1bYHLzocKYzh09pecyhctVrkc%2FMOTh5lsMqBxbytLlt06c6nFud5pXUL1PutPO0wLbULw5oV7nWdRL4EnQlZ5FbQimekId6KTSLENtuu9%2Fwdk6dQ%3D%3D";
let editorState;
let turretObj;
let lastSelected = [];
let lastSelection;
Object.defineProperty(Object.prototype, "Eb", {
    get() {
        return this[symbolStepVB]
    },
    set(value) {
        debug("h",this,value);
        //lastSelected.push(value[0]);
        this[symbolStepVB] = value
    },
    configurable: true
});

const pointerDown = (data) => {
    debug("down",data);
}

const pointerMove = (data) => {
    //onsole.log("move",data);
}

const pointerUp = (data) => {
    debug("up",data);
}

const pointerupoutside = (data) => {
    debug("upoutside",data);
}

const placeholder = () => {};

let ebs = {};
let shiftKey = false;
const updateVB = (i) => {
    i.eb.clear();
    let rect = new PIXI.Rectangle();
    let b = i.Bb();
    //i.eb.clear();
    b.Ic.getBounds(!1,rect);
    i.eb.lineStyle(3, 0x00FF00);
    i.eb.alpha = 0.7;
    i.eb.drawRect(-rect.width / ("2" ^ 0), -rect.height / +"2", rect.width, rect.height);
    i.eb.x = rect.x + rect.width / 2;
    i.eb.y = rect.y + rect.height / 2;
    i.pb.x = (-rect.width/2)-15;
    i.pb.y = (rect.height/2)+15;
}

const VBMv = (self,a) => {
    debug(self,a);
    if (self.il) {
        self.mvv(a);
        return;
    }
    let center = self.dv || self.ak || self.ck;
    let diffX = center.x;
    let diffY = center.y;
    self.mvv(a);
    diffX = center.x-diffX;
    diffY = center.y-diffY;
    let interest = self.ak || self;
    for (let i of lastSelected) {
        let IInterest = i.ak || i;
        if (IInterest != interest) {
            // let a8u = editorState.mF.state.all[5][i.id];
            // let jc = new i.Jc.constructor(a8u,editorState.ed,i.Jc.Gc)
            // i = new i.constructor(a8u,jc);
            //injectVB(i);
            if (i.ak) {
                let ak = editorState.mF.state.all[2][i.id];
                ak.x += diffX;
                ak.y += diffY;
                continue;
            }
            if (i.il) {
                i.il.Va.x += diffX;
                i.il.Va.y += diffY;
                i.il.Oa.x += diffX;
                i.il.Oa.y += diffY;
                continue;
            }
            let center2 = i.dv || i.ck;
            center2.x += diffX;
            center2.y += diffY;
        }
    }
}

const VBIb = (self,a) => {
    self.ibb(a);
    for (let i of lastSelected) {
        if (i.ibb && i != self) {
            i.ibb(a);
        }
    }
}

const injectVB = (i) => {
    i.injected = true;
    i.mvv = i.mv;
    i.mv = (a) => {
        return VBMv(i,a);
    };
    if (i.Ib) {
        i.ibb = i.Ib;
        i.Ib = (a) => {
            return VBIb(i,a);
        };
    }
}

const reapplyVB = () => {
    editorState.fff()
    let vb = editorState.vb[0];
    if (!vb.dv && !vb.ak && !vb.il && !vb.ck) {return;}
    //debug(vb);
    lastSelection = vb;
    if (!vb.injected) {
        injectVB(vb);
        if (vb.ak) {
            vb.id = editorState.mF.state.all[2].indexOf(vb.ak);
        }
        if (vb.ck) {
            vb.id = editorState.mF.state.all[10].indexOf(vb.CK);
        }
    }
    if (shiftKey) {
        if (vb && lastSelected.indexOf(vb) == -1) {
            for (let x in lastSelected) {
                let i = lastSelected[x];
                if (i.constructor == vb.constructor && i.id == vb.id) {
                    i.eb.destroy();
                    lastSelected.splice(x,1);
                }
            }
            debug("PUSHED",vb);
            lastSelected.push(vb);
        }
    }else if (lastSelected.indexOf(vb) == -1 && !vb.ak){
        for (let i of lastSelected) {
            i.eb.destroy();
            delete i.eb;
            i = null;
        }
        lastSelected = [];
    }
    if (lastSelected.length > 0) {
        for (let i of lastSelected) {
            if (!i.eb) {
                i.eb = new PIXI.Graphics();
                i.pb = new PIXI.Text('',{
                    fontFamily:'Courier New',
                    fill: '#0000ff',
                    align: 'center',
                    fontSize: 20
                });
                i.pb.text = i.id;
                i.eb.addChild(i.pb);
                editorState.hb.Cg.addChild(i.eb);
            }
            updateVB(i);
            //i.zh = new PIXI.Graphics();
            //i.zh.beginFill("4881073");
            //i.zh.x = rect.width/2;
            //i.zh.y = rect.height/2;
            //i.eb.addChild(i.zh);
        }
    }
    editorState.render();
}

const reapplyRender = () => {
    if (lastSelected.length > 0) {
        for (let i of lastSelected) {
            if (i.eb) {
                if (i.eb.parent != editorState.hb.Cg) {
                    editorState.hb.Cg.addChild(i.eb);
                }
                updateVB(i);
            }
        }
    }
    editorState.rrender();
}

const ondelete = (e) => {
    debug(e);
    if (e.Key != 'Delete' && e.key != 'Backspace' && e.key != "Escape") return;
    for (let i of lastSelected) {
        i.eb.destroy();
        delete i.eb;
        i = null;
    }
    lastSelected = [];
    editorState.render();
}

const reapplyWB = (a) => {
    editorState.wwb(a);
    debug("ey");
}

setInterval(() => {editorState.render()},500);

Object.defineProperty(Object.prototype, "SF", {
    get() {
        return this[symbolStepD]
    },
    set(value) {
        debug(this,"FOUND");
        editorState = this;
        window.editorSTATE = editorState;
        editorState.nF.push({Bb: placeholder,mb: placeholder,fb: ondelete,disable: placeholder,enable: placeholder,gb: placeholder,ab: pointerDown, wb: pointerMove,ub: pointerUp,pb: pointerupoutside,cb: placeholder,lb: placeholder});
        editorState.mF.state.ac(testString);
        editorState.fff = editorState.FF;
        editorState.FF = reapplyVB;
        editorState.wwb = editorState.wb;
        editorState.wb = reapplyWB;
        editorState.rrender = editorState.render;
        editorState.render = reapplyRender;
        turretObj = editorState.mF.state.Fl[0].constructor;
        debug(turretObj,"FOUND!");
        if (typeof value == "function") {
            const original = value
            value = function () {
                return original.apply(this, arguments)
            }
        }
        this[symbolStepD] = value
    },
    configurable: true
})

document.addEventListener("DOMContentLoaded",() => {
    fetch(`https://hitbox.io/bundle.js`)
        .then(code => code.text())
        .then(code => {
        parent.document.getElementById("adboxverticalright").style.top = "-100000%";
        parent.document.getElementById("adboxverticalleft").style.top = "-200000%";
        for (let i in codeNamesRegex){
            codeNames[i] = codeNamesRegex[i].verify(code.match(codeNamesRegex[i].reg));
        }

        const newScope = (scope, script) => Function(`"use strict"; const globalThis = null; const window = null; const document = null; const game = this; for (let i in game.usedMath) {Math[i] = (...args) => {return game.Math[i](...args)};}; ${script}`).bind(scope);
        let DN = [
            "gsFightersCollide",
            "recordMode",
            "o",
            "l",
            "u",
            "m",
            "g",
            "v",
            "k",
            "N",
            "S",
            "M",
            "C",
            "_",
            "T",
            "P",
            "B",
            "I",
            "F",
            "R",
            "O",
            "A",
            "D",
            "L",
            "U",
            "H",
            "J",
            "W",
            "G",
            "Y", // ss
            "V",
            "q",
            "K",
            "X",
            "Z",
            "$",
            "tt",
            "it",
            "st",
            "ht",
            "et",
            "nt",
            "ot",
            "rt",
            "at",
            "lt",
            "ut",
            "ct",
            "dt",
            "wt",
            "ft",
            "gt",
            "bt"
        ]

        function timeConverter(UNIX_timestamp){
            let a = new Date(UNIX_timestamp * 1000);
            let months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
            let month = months[a.getMonth()];
            let date = a.getDate();
            let hour = a.getHours();
            let min = a.getMinutes();
            let sec = a.getSeconds();
            let time = date + ' ' + month + ' ' + hour + ':' + min + ':' + sec ;
            return time;
        }

        let autosaves = JSON.parse(localStorage.getItem('autosaves') || '[]');
        let stateMaker;
        let mostScore = -1;
        debug('damn bro');
        function autosave(){
            if (WSS && hostId == myid){
                setAdvice("Auto saved map!");
                let data = editorState.mF.state.rc();
                autosaves.push([data,editorMaps[0].BN,Date.now()]);
                if (autosaves.length > 5){
                    autosaves.splice(0,1);
                }
                localStorage.setItem('autosaves',JSON.stringify(autosaves));
            }
        }

        setInterval(() => {
            if (WSS){
                autosave();
            }
        },50000);

        for (let a1 in window.multiplayerSession){
            let a = window.multiplayerSession[a1];
            if (typeof a == "object")
            {
                let score = 0;
                for (let x1 in a){
                    let x = a[x1];
                    if (typeof x == "object")
                    {
                        if (x.constructor.name == "Array"){

                        }
                        else
                        {
                            let length = 0;
                            for (let y1 in x){
                                let y = x[y1];
                                length++
                                if (length > 2){
                                    break;
                                }
                            }
                            if (length == 1){
                                for (let y1 in x){
                                    let y = x[y1];
                                    if (y.constructor.name == "Map"){
                                        score++
                                    }
                                    break;
                                }
                            }else{
                                let isDN = true;
                                for (let i of DN){
                                    if (!i in x){
                                        isDN = false;
                                        break;
                                    }
                                }
                                if (isDN){
                                    score+=5;
                                }
                            }
                        }
                    }
                }
                if (score > mostScore && score < 50){
                    mostScore = score;
                    stateMaker = a;
                }
            }
        }
        function encodeState(state){
            let newState = state;
            newState.cubes = newState.all[8];
            newState.projectiles = [];
            for (let id in newState.all[9]){
                let proj = newState.all[9][id];
                if (proj && codeNames.general){
                    if (!codeNames.projectiles){
                        let matches = String(proj.constructor).match(/this\.(.*?)=(.*?);/ig);
                        let m = [];
                        for (let i of matches){
                            m.push(i.split("this.")[1].split("=")[0]);
                        }
                        codeNames.projectiles = m;
                    }
                    let newProj = {
                        p: [proj.x,proj.y],
                        lv: [proj[codeNames.lv[0]],proj[codeNames.lv[1]]],
                        a: proj.angle,
                        av: proj.angularVelocity,
                        ftd: proj[codeNames.projectiles[10]],
                        tr: proj[codeNames.projectiles[14]], // turn rate
                        gs: proj[codeNames.projectiles[17]], // gravity scale
                        er: proj[codeNames.projectiles[15]], // explode radius
                        bb: proj[codeNames.projectiles[18]], // bullet bounces
                        owner: proj[codeNames.projectiles[13]],
                        round: proj[codeNames.projectiles[24]], // bullet round
                        restitution: proj.restitution, // bullet restitution
                        bc: proj[codeNames.projectiles[22]], // bounce count
                        br: proj[codeNames.projectiles[6]], // bullet radius
                    }
                    newState.projectiles[id] = newProj;
                }
            }
            for (let id in newState.all[13]){
                if (codeNames.general && newState.all[13][id]){
                    let flag = newState.all[13][id];
                    if (!codeNames.flags){
                        let constructor = String(flag.constructor);
                        let matches = constructor.match(/this\..{0,2}=(.*?);/ig);
                        let m = [];
                        for (let i of matches){
                            m.push(i.split("this.")[1].split("=")[0]);
                        }
                        let t = [''];
                        for (let i in m) {
                            t.push(m[i]);
                        }
                        codeNames.flags = t;
                    }
                    flag.p = [flag.x,flag.y];
                    flag.capFrames = flag[codeNames.flags[7]];
                    flag.capLimit = flag[codeNames.flags[6]];
                    flag.takenBy = flag[codeNames.flags[5]];
                }
            }
            newState.flags = newState.all[13];
            for (let id in newState.cubes){
                let cube = newState.cubes[id];
                if (!codeNames.general){
                    let constructor = String(cube.constructor);
                    let matches = constructor.match(/this\..{0,2}=(.*?);/ig);
                    let m = [];
                    for (let i of matches){
                        m.push(i.split("this.")[1].split("=")[0]);
                    }
                    let t = [''];
                    for (let i in m) {
                        t.push(m[i]);
                    }
                    codeNames.general = t;
                    codeNames.lv = [codeNames.general[4],codeNames.general[5]]
                }
                cube.p = [cube.x,cube.y];
                cube.lv = [cube[codeNames.lv[0]],cube[codeNames.lv[1]]];
                cube.st = cube[codeNames.general[21]];
                cube.team = cube[codeNames.general[9]];
                cube.ff = cube[codeNames.general[15]];
                cube.dj = cube[codeNames.general[10]];
                cube.rf = cube[codeNames.general[30]];
                cube.hp = cube[codeNames.general[8]];
                cube.ra = cube[codeNames.general[31]];
                cube.stepsSurvived = cube[codeNames.general[14]];
                cube.iframes = Math.max(0,cube[codeNames.general[13]]-1);
                cube.ba = cube[codeNames.general[25]];
                cube.bf = cube[codeNames.general[24]];
                cube.a = cube.angle;
                cube.av = cube.angularVelocity;
                delete cube.angle;
                delete cube.angularVelocity;
                delete cube[codeNames.general[21]];
                delete cube[codeNames.general[8]];
                delete cube[codeNames.general[14]];
                delete cube[codeNames.general[22]];
                delete cube[codeNames.lv[0]];
                delete cube[codeNames.lv[1]];
                delete cube.x;
                delete cube.y;
            }
            for (let id in newState.all[4]){
                let info = newState.all[4][id];
                if (!codeNames.deathReg){
                    let constructor = String(info.constructor);
                    let matches = constructor.match(/this\..{0,2}=(.*?);/ig);
                    let m = [];
                    for (let i of matches){
                        m.push(i.split("this.")[1].split("=")[0]);
                    }
                    let t = [];
                    for (let i in m) {
                        t.push(m[i]);
                    }
                    codeNames.deathReg = t;
                }
                let playerData = info[codeNames.deathReg[10]];
                let finalPlrData = {};
                for (let id2 in playerData){
                    let info2 = playerData[id2];
                    if (info2){
                        if (!codeNames.playerReg){
                            let constructor = String(info2.constructor);
                            let matches = constructor.match(/this\..{0,2}=(.*?);/ig);
                            let m = [];
                            for (let i of matches){
                                m.push(i.split("this.")[1].split("=")[0]);
                            }
                            let t = [];
                            for (let i in m) {
                                t.push(m[i]);
                            }
                            codeNames.playerReg = t;
                        }
                        info2.lives = info2[codeNames.playerReg[14]];
                        info2.kills = info2[codeNames.playerReg[2]];
                        info2.respawnIndex = info2[codeNames.playerReg[34]];
                        info2.killedBy = info2[codeNames.playerReg[18]];
                        info2.respawn = info2[codeNames.playerReg[12]];
                    }
                }
                newState.playerData = playerData;
            }
            return newState;
        }

        let lastPixiContainer = null;

        function decodeState(state) {
            let newState = state;
            newState.all[8] = newState.cubes;
            for (let id in newState.projectiles){
                let proj = newState.projectiles[id];
                let p = newState.all[9][id];
                if (proj && p && codeNames.general){
                    p.x = proj.p[0]
                    p.y = proj.p[1]
                    p[codeNames.lv[0]] = proj.lv[0]
                    p[codeNames.lv[1]] = proj.lv[1]
                    p.angle = proj.a;
                    p.angularVelocity = proj.av;
                    p[codeNames.projectiles[10]] = proj.ftd;
                    p[codeNames.projectiles[14]] = proj.tr; // turn rate
                    p[codeNames.projectiles[17]] = proj.gs; // gravity scale
                    p[codeNames.projectiles[15]] = proj.er; // explode radius
                    p[codeNames.projectiles[18]] = proj.bb; // bullet bounces
                    p[codeNames.projectiles[13]] = proj.owner;
                    p[codeNames.projectiles[24]] = proj.round; // bullet round
                    p.restitution = proj.restitution; // bullet restitution
                    p[codeNames.projectiles[22]] = proj.bc; // bounce count
                    p[codeNames.projectiles[6]] = proj.br; // bullet radius
                }
            }
            delete newState.projectiles;
            newState.all[13] = newState.flags;
            for (let id in newState.all[13]){
                if (codeNames.general && newState.all[13][id]){
                    let flag = newState.all[13][id];
                    if (!codeNames.flags){
                        let constructor = String(flag.constructor);
                        let matches = constructor.match(/this\..{0,2}=(.*?);/ig);
                        let m = [];
                        for (let i of matches){
                            m.push(i.split("this.")[1].split("=")[0]);
                        }
                        let t = [''];
                        for (let i in m) {
                            t.push(m[i]);
                        }
                        codeNames.flags = t;
                    }
                    if (flag.p){
                        flag.x = flag.p[0];
                        flag.y = flag.p[1];
                        flag[codeNames.flags[7]] = flag.capFrames;
                        flag[codeNames.flags[6]] = flag.capLimit;
                        flag[codeNames.flags[5]] = flag.takenBy;
                    }
                }
            }
            for (let id in newState.all[8]){
                let cube = newState.all[8][id];
                if (!codeNames.general){
                    let constructor = String(cube.constructor);
                    let matches = constructor.match(/this\..{0,2}=(.*?);/ig);
                    let m = [];
                    for (let i of matches){
                        m.push(i.split("this.")[1].split("=")[0]);
                    }
                    let t = [''];
                    for (let i in m) {
                        t.push(m[i]);
                    }
                    codeNames.general = t;
                    codeNames.lv = [codeNames.general[4],codeNames.general[5]]
                }
                cube.x = cube.p[0];
                cube.y = cube.p[1];
                cube[codeNames.lv[0]] = cube.lv[0];
                cube[codeNames.lv[1]] = cube.lv[1];
                cube.angularVelocity = cube.av;
                cube[codeNames.general[10]] = cube.dj;
                cube[codeNames.general[8]] = cube.hp;
                cube[codeNames.general[13]] = cube.iframes;
                cube[codeNames.general[21]] = cube.st;
                cube[codeNames.general[15]] = cube.ff;
                cube[codeNames.general[9]] = cube.team;
                cube[codeNames.general[30]] = cube.rf;
                cube[codeNames.general[31]] = cube.ra;
                cube[codeNames.general[14]] = cube.stepsSurvived;
                cube[codeNames.general[25]] = cube.ba;
                cube[codeNames.general[24]] = cube.bf;
                cube.angle = cube.a;
                delete cube.a;
                delete cube.av;
                delete cube.stepsSurvived;
                delete cube.st;
                delete cube.dj;
                delete cube.iframes;
                delete cube.lv;
                delete cube.hp;
                delete cube.p;
                delete cube.ba;
                delete cube.bf;
                delete cube.ra;
                delete cube.rf;
                delete cube.ff;
                delete cube.team;
            }

            for (let id in newState.playerData){
                let info = newState.playerData[id];
                if (info){
                    info[codeNames.playerReg[14]] = info.lives;
                    info[codeNames.playerReg[12]] = info.respawn;
                }
            }
            for (let i in newState.all[4]){
                if (newState.all[4][i]){
                    newState.all[4][i][codeNames.deathReg[10]] = newState.playerData;
                }
            }
            return newState;
        }


        // vh down
        // yh up
        // kh rocket
        // Xh bat
        // qh force push
        // Zh grab

        function loadKeys(classi,typ){
            let cons = String(classi.constructor);
            let defines = (cons.split("constructor() {")[1]).split("this.");
            let m = [];
            for (let i of defines){
                m.push(i.split("=")[0]);
            }
            codeNames.keys = m;
        }

        function updateInEditor() {
            return;
            document.querySelector("#appContainer > div.cornerButton > div.items > div:nth-child(7)").click();
            document.querySelector("#appContainer > div.lobbyContainer > div.settingsBox > div:nth-child(6)").click();
        }

        function makeInputs(frame,cubes){
            let inputs = stateMaker[codeNames.simulation[1]][codeNames.simulation[2]](frame,true);
            let ts = stateMaker[codeNames.simulation[1]].get(-1);
            if (!codeNames.keys && ts){
                loadKeys(ts);
                codeNames.keySample = ts;
            }
            if (inputs){
                let array = [];
                for (let id in inputs){
                    array[id] = {
                        left: inputs[id].left,
                        right: inputs[id].right,
                        up: inputs[id][codeNames.keys[3]],
                        down: inputs[id][codeNames.keys[4]],
                        action3: inputs[id][codeNames.keys[7]], // BAT
                        action4: inputs[id][codeNames.keys[6]], // ROCKET
                        action2: inputs[id][codeNames.keys[8]], // GRAB
                        action1: inputs[id][codeNames.keys[5]] // FP
                    }
                }
                for (let id in cubes){
                    if (cubes[id]){
                        if (!array[id]){
                            array[id] = {
                                left: false,
                                right: false,
                                up: false,
                                down: false,
                                action3: false, // BAT
                                action4: false, // ROCKET
                                action2: false, // GRAB
                                action1: false // FP
                            }
                        }
                    }
                }
                return array;
            }
        }

        const createGraphics = (info) => {
            let id = game.state.graphics.index;
            game.state.graphics.index++;
            game.state.graphics.drawings[id] = info;
            return id;
        }

        //debug(stateMaker,"won",mostScore)
        const stateVars = String(stateMaker.constructor).match(/this\.(.*?)=/ig);
        stateVars.splice(0,1);
        const stateArray = [];
        for (let i of stateVars) {
            if (i && i.match("=")) {
                stateArray.push(i.split("this.")[1].split("=")[0]);
            }
        }
        // 23
        const Tsettings = stateMaker[stateArray[13]].settings[0]
        const settingsArray = String(Tsettings.constructor).split("constructor() {")[1].match(/this\..{0,2}=(.*?);/ig);
        //debug(String(Tsettings.constructor));
        const settingsEndArray = [];
        for (let i of settingsArray) {
            if (i.match("=")) {
                settingsEndArray.push(i.split("this.")[1].split("=")[0]);
            }
        }
        debug(settingsEndArray);
        codeNames.settings = settingsEndArray;
        debug(stateArray);
        const editorInfo = stateMaker[stateArray[18]];
        let editorMaps = [];
        const editorVar = String(editorInfo.constructor).match(/this\.(.*?)=/ig);
        editorVar.splice(0,1);
        const editorVarArray = [];
        for (let i of editorVar) {
            if (i && i.match("=")) {
                editorVarArray.push(i.split("this.")[1].split("=")[0]);
            }
        }
        debug(editorVarArray,"l");
        editorMaps = editorInfo[editorVarArray[4]];
        const stateVars2 = String(stateMaker[stateArray[23]].constructor).match(/this\.(.*?)=/ig);
        // debug(stateVars2);
        stateVars.splice(0,1);
        const stateArray2 = [];
        for (let i of stateVars2) {
            if (i && i.match("=")) {
                stateArray2.push(i.split("this.")[1].split("=")[0]);
            }
        }
        window.editorMaps = editorMaps;
        // debug(stateArray2);
        // 15
        /*debug(stateMaker[stateArray[23]]);
    const stateVars3 = String(stateMaker[stateArray[23]][stateArray2[15]].constructor).match(/this\.(.*?)=/ig);
  //  debug(stateVars3);
    stateVars.splice(0,1);
    const stateArray3 = [];
    for (let i of stateVars3) {
        if (i && i.match("=")) {
         stateArray3.push(i.split("this.")[1].split("=")[0]);
        }
    }*/

        const lerpNumber = function(a, b, weight) {
            return ((1 - weight) * a + weight * b);
        };
        // 0
        // codeNames.deathReg = [stateArray[23],stateArray2[15],stateArray3[0],stateMaker[stateArray[23]][stateArray2[15]][stateArray3[0]]];

        // Stopped here

        /*[
    Ja: {
        "Rr": 0,
        "x": 0,
        "y": 0,
        "color": 16777215,
        "Ir": true,
        "Dr": 0,
        "texture": 0,
        "Lr": 0,
        "Ur": 0,
        "jr": 1,
        "Jr": false,
        "zIndex": 0,
        "Wr": [
            {
                "x": -1,
                "y": -2
            },
            {
                "x": 2,
                "y": 1
            },
            {
                "x": -1,
                "y": 1
            }
        ]
    }
]
*/

        function getWorld(){
            for (let i in stateMaker[codeNames.simulation[3]]){
                if (stateMaker[codeNames.simulation[3]][i].m_island){
                    return stateMaker[codeNames.simulation[3]][i];
                }else if (stateMaker[codeNames.simulation[3]][i].PostSolve && !stateMaker[codeNames.simulation[3]][i].injected){
                    stateMaker[codeNames.simulation[3]][i].injected = true;
                    let a = stateMaker[codeNames.simulation[3]][i];
                    const postSolve = a.PostSolve;
                    a.PostSolve = function(contact, impulses) {
                        if (impulses.normalImpulses[0] > 0.0) {
                            const worldManifold = new window.Box2D.Collision.b2WorldManifold();
                            contact.GetWorldManifold(worldManifold);
                            /*gmm.collisions.push({
                            fixtureAData: contact.GetFixtureA().GetUserData(),
                            fixtureABodyData: contact.GetFixtureA().GetBody().GetUserData(),
                            fixtureBData: contact.GetFixtureB().GetUserData(),
                            fixtureBBodyData: contact.GetFixtureB().GetBody().GetUserData(),
                            normal: {x: worldManifold.m_normal.x, y: worldManifold.m_normal.y},
                        });*/
                        }

                        return postSolve(...arguments);
                    };
                }
            }
        }
        let b2World = getWorld();
        const b2Vec2 = window.Box2D.Common.Math.b2Vec2

        stateMaker.mmR = stateMaker[codeNames.simulation[1]][codeNames.simulation[2]];
        let inputsPropertie = null;
        for (let i in stateMaker[codeNames.simulation[1]]){
            if (stateMaker[codeNames.simulation[1]][i].constructor === Array){
                inputsPropertie = i;
            }
        }

        //eval defineGMM("game.events.add('step',function() {game.state.po[0].th = -5;})")

        function getAllStates(){
            let state;
            for (let a in stateMaker){
                let b = stateMaker[a];
                if (b.constructor.name == "Array"){
                    for (let i of b){
                        if (typeof(i) == "object" && "all" in i && i.all.constructor.name == "Array"){
                            if (i.all.length > 10 && i.all.length < 15){
                                state = b;
                                break;
                            }

                        }
                    }
                }
            }
            if (state){
                return state;
            }
        }

        function setStates(states){
            let state;
            for (let a in stateMaker){
                let b = stateMaker[a];
                if (b.constructor.name == "Array"){
                    for (let i of b){
                        if (typeof(i) == "object" && "all" in i && i.all.constructor.name == "Array"){
                            if (i.all.length > 10 && i.all.length < 15){
                                state = b;
                                break;
                            }

                        }
                    }
                }
            }
            if (state){
                state = states;
            }
        }

        function getCurrentState(){
            let state;
            for (let a in stateMaker){
                let b = stateMaker[a];
                if (b && b.constructor && b.constructor.name == "Array"){
                    for (let it in b){
                        let i = b[it];
                        if (typeof(i) == "object" && "all" in i && i.all.constructor.name == "Array"){
                            if (i.all.length > 10 && i.all.length < 15){
                                state = b;
                                break;
                            }

                        }
                    }
                }
            }
            if (state){
                let last;
                for (let a in state){
                    state[a].frame = a;
                    last = state[a];
                }
                return last;
            }
        }

        function sendInfo(sett = {},offset = 0){
            if (hostId == myid){
                sett.frame = getCurrentState()?.frame-offset;
                settings.nhm = sett;
                WSS.send(`42[1,[62,${JSON.stringify(settings)}]]`)
                WSS.onmessage({data: `42[63,${JSON.stringify(settings)}]`})
            }
        }

        let settings = {};
        let trace = [];
        let tracing = -1;
        let traceLimit = 0;

        function setSett(setts)
        {
            let sett = {};
            let sects = setts.split('|');
            for (let o of sects){
                let pr = o.split(':');
                if (pr[1]){
                    let v = JSON.parse(`[${pr[1]}]`)[0];
                    sett[pr[0]] = v;
                }
            }
            WSS.onmessage({data: `42[63,${JSON.stringify(sett)}]`})
            WSS.send(`42[1,[62,${JSON.stringify(sett)}]]`)
        }

        //<textarea class="scrollBox" wrap="soft" spellcheck="false" style="border: none; outline: none; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; resize: none; position: absolute; overflow-y: scroll; overflow-x: hidden; background-color: #2f2f2f; height: calc(100% - 60px); width: calc(100% - 80px); left: 80px; top: 50px; box-sizing: border-box; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; white-space: nowrap;"></textarea>

        let myid = -1;
        let hostId = -1;

        let users = [];
        let abc = 'abcdefghijklmnopqrstuvwxyz';
        const alive = {};
        // Your code here...

        let toppest = null;
        // scope.toppest.children[1].children[0] is bg
        // starting from 1 to end, first is the most behind and the last is the furthest on the z index sort
        let overlayWidth = .25;
        let overlayHeight = .25;

        let lastRender = Date.now();
        // This a hacky method that will be replaced soon. this shit isn't very good

        const render = window.PIXI.Graphics.prototype._render;
        window.PIXI.Graphics.prototype._render = function(...args){
            render.call(this,...args)
            if (this.batchDirty == -1)
            {
                let parent = this.parent;
                while (parent.parent){
                    parent = parent.parent;
                }
                toppest = parent;
                window.toppest = toppest;
            }
        }

        const render2 = window.PIXI.Text.prototype._render;
        window.PIXI.Text.prototype._render = function(...args){
            render2.call(this,...args)
            if (this.parent && this._text) {
                alive[this._text] = {orbj: this,obj: this.parent,frames: 16, txt: this};
            }
        }

        const render3 = window.PIXI.Renderer.prototype.render;
        window.PIXI.Renderer.prototype.render = function(...args){
            if (lastOverlayGraphics){
                if (lastOverlayGraphics.parent != toppest.children[1] || lastOverlayGraphics != toppest.children[toppest.children.length-1]){
                    toppest.addChild(lastOverlayGraphics);
                }
                let bg = document.getElementById('backgroundImage')
                let w = bg.offsetWidth;
                let zoom = (toppest.children[1].width / w);
                let width = toppest.children[1].width;
                let height = toppest.children[1].height;
                lastOverlayGraphics.width = (overlayWidth/1)*width;
                lastOverlayGraphics.height = (overlayHeight/1)*height;
                lastOverlayGraphics.x = toppest.children[1].x+(overlayX/1)*width;
                lastOverlayGraphics.y = toppest.children[1].y+(overlayY/1)*height;
                lastOverlayGraphics.anchor.x = .5;
                lastOverlayGraphics.anchor.y = .5;
            }
            render3.call(this,...args)
        };

        let frames = 0;
        let lc = Date.now();

        function gCoordinates(x,y){
            let bg = document.getElementById('backgroundImage')
            if (bg){
                let w = bg.clientWidth;
                let h = bg.clientHeight;
                let scale = w/730;
                return [x/scale,y/scale];
            }
            return [0,0];
        }

        function lerp(a, b, x) {
            return a + x * (b - a);
        }

        let lastMO;

        //SP.SE.ve[0].name
        //SP.zE.eo[0];
        let empty = {};

        window.requestAnimationFrame = new Proxy( window.requestAnimationFrame, {
            apply( target, thisArgs, args ) {
                let T = Date.now();
                let dt = (T-lc)/1000;
                lc = T;
                frames++
                Reflect.apply(...arguments);
                editorMaps = editorInfo[editorVarArray[4]];
                /*if (currentState && currentState.mo){
            for (let id in currentState.mo){
             let info = currentState.mo[id];
                if (!info.injected){
                    info.injected = true;
                    let player = findUser(info.$h);
                    debug(player.name,"died?",info);
                }
            }
        }*/

                for (let i in alive) {
                    let unalive = (!alive[i].obj || !alive[i].obj.transform || !alive[i].obj.parent || !alive[i].txt || !alive[i].txt.visible || alive[i].txt.parent != alive[i].obj || !alive[i].obj.visible || alive[i].obj.alpha <= 0);
                    let p = findUser(i);
                    if (p){
                        if (unalive){
                            alive[i].frames--
                            if (alive[i].frames <= 0){
                                delete alive[i];
                            }
                        }else{

                        }
                    }else{
                        delete alive[i];
                    }
                }
            }
        })

        const originalSend = window.WebSocket.prototype.send;
        let excludewss = [];
        let WSS = 0;

        function findUser(id){
            for (let t in users) {
                let o = users[t];
                if (o.id == id || o.name == id){
                    o.index = t;
                    return o;
                    break;
                }
            }
        }

        //eval setInterval(() => {sendInfo({execute:`this.state.po[0].th = -20;`});},2000);

        function decodeString(encodedString){
            let V7T = atob(decodeURIComponent(encodedString));
            let g9_ = pako.inflate(V7T, {
                '\x74\x6f': "string"
            });
            return JSON.parse(g9_);
        }

        function encodeString(jsonData){
            let B8e = JSON.stringify(jsonData);
            let p1E = btoa(pako.deflate(B8e, {
                '\x74\x6f': "string"
            }));
            return encodeURIComponent(p1E);
        }

        const defaultMap = '{"b":[],"j":[],"s":[],"p":[],"tu":[],"tc":[],"gp":[],"c":[],"set":{"3":40,"4":0.5,"10":60,"11":0,"12":3690098,"15":40,"16":25,"17":2108492}}';

        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 200;
        canvas.height = 200;

        function mapFromImage(url,w,h,sample,colorscale)
        {
            canvas.width = w;
            canvas.height = h;
            var img = new Image();
            img.src = url;
            img.setAttribute('crossOrigin', '');
            let data = {
                '\x62': [],
                '\x73\x65\x74': {
                    "3": 40,
                    "4": 0.5,
                    "10": 60,
                    "11": 0,
                    "12": 3690098,
                    "15": 40,
                    "16": 25,
                    "17": 2108492
                }
            };
            if (!codeNames.body){
                for (let i in editorMaps[0].state.all[5]){//[bodyId].Sa) {
                    let body = editorMaps[0].state.all[5][i];
                    if (body && body.Sa && body.Sa.length > 0){
                        for (let i2 in body.Sa){
                            let shape = body.Sa[i2];
                            if (shape && shape.ca && shape.ca[0]){
                                codeNames.body = {
                                    body: body.constructor,
                                    shape: shape.constructor,
                                    point: shape.ca[0].constructor
                                }
                                break;
                            }
                        }
                        break;
                    }
                }
            }
            editorMaps[0].state.ac('eJwtyjEKgDAQRNG7TB1kNyYx2auIjSKClZBYiXd3ZVM9%2FjAPVsi8OJxGNS6j3d3NPPres%2B4N8mCEBHIIEBqiAxMkaTProHjImApRyRrRvpwg%2Fv9OKlMOxb%2FvB5nHII8%3D');
            let bod = new codeNames.body.body();
            img.onload = function() {
                if (WSS){
                    WSS.send(`42[1,[58]]`);
                }
                canvas.width = img.width;
                canvas.height = img.height;
                let size = Math.floor(((1+Math.floor(canvas.width/370))+(1+Math.floor(canvas.height/370)))/2);
                canvas.width /= size;
                canvas.height /= size;
                if (sample == 0){
                    sample = 40/canvas.width;
                }
                if (w == 0) {
                    w = canvas.width;
                }
                if (h == 0){
                    h = canvas.height;
                }
                ctx.clearRect(0,0,canvas.width,canvas.height)
                ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
                const pixelData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                const pixels = pixelData.data;
                bod.Jr = true;
                const colors = {};
                const colorGoals = {};
                const colorStarts = {};
                debug("Pixel hashing start");
                const colorMergeHash = {};
                const canvasWidth = canvas.width;
                const colorscaleSquared = colorscale ** 2;

                for (let x = 0; x < w; x++) {
                    for (let y = 0; y < h; y++) {
                        const index = (y * canvasWidth + x) * 4;
                        const alpha = pixels[index + 3]; // Alpha (transparency) component (0-255)

                        if (alpha > 240) {
                            const red = pixels[index]; // Red component (0-255)
                            const green = pixels[index + 1]; // Green component (0-255)
                            const blue = pixels[index + 2]; // Blue component (0-255)
                            let color = rgbToInt(red, green, blue);

                            let mergedColor = colorMergeHash[color] || null;
                            if (!mergedColor) {
                                for (const existingColor in colors) {
                                    const existingRed = (existingColor >> 16) & 0xFF;
                                    const existingGreen = (existingColor >> 8) & 0xFF;
                                    const existingBlue = existingColor & 0xFF;

                                    const colorDistanceSquared =
                                          (red - existingRed) ** 2 +
                                          (green - existingGreen) ** 2 +
                                          (blue - existingBlue) ** 2;

                                    if (colorDistanceSquared < colorscaleSquared) {
                                        mergedColor = existingColor;
                                        colorMergeHash[color] = mergedColor;
                                        break;
                                    }
                                }
                            }

                            if (mergedColor !== null) {
                                color = mergedColor;
                            }
                            if (!colors[color]) {
                                colors[color] = {};
                                colorStarts[color] = [x, y];
                                colorGoals[color] = [x,y];
                            }
                            colorStarts[color] = [Math.min(x,colorStarts[color][0]),Math.min(y,colorStarts[color][1])];
                            colorGoals[color] = [Math.max(x,colorGoals[color][0]),Math.max(y,colorGoals[color][1])];
                            colors[color][x + '.' + y] = true;
                        }
                    }
                }
                debug("Pixel hashing end");
                debug("Color meshing start");
                for (let color in colors) {
                    let pixels = colors[color];
                    if (pixels) {
                        let rectangles = [];
                        let polygons = [];
                        let checkX = colorStarts[color][0];
                        let checkY = colorStarts[color][1];
                        let goalX = w;// colorGoals[color][0];
                        let goalY = h;//colorGoals[color][1];
                        overall:
                        for (let round = 0; round < 1; round++){
                            //debug("PIXEL RASTERIZATION ROUND "+round);
                            let broke = true;
                            for (let i in pixels){
                                if (pixels[i]){
                                    broke = false;
                                    break;
                                }
                            }
                            if (broke){
                                break;
                            }
                            for (let y = checkY - 1; y <= goalY; y++) {
                                for (let x = checkX - 1; x <= goalX; x++) {
                                    let key = x + '.' + y;
                                    if (pixels[key]) {
                                        let endX = x;
                                        let endY = y;

                                        // Find the maximum endX for the current row
                                        while (endX < goalX && pixels[(endX + 1) + '.' + y]) {
                                            endX++;
                                        }

                                        // Check the rectangular area
                                        outerLoop:
                                        for (let iy = y; iy <= goalY; iy++) {
                                            for (let ix = x; ix <= endX; ix++) {
                                                if (!pixels[ix + '.' + iy]) {
                                                    break outerLoop;
                                                }
                                            }
                                            endY = iy;
                                        }

                                        // Mark the rectangle as processed and collect it
                                        rectangles.push([x, y, (endX + 1) - x, (endY + 1) - y]);

                                        // Collect keys to delete
                                        let keysToDelete = [];
                                        for (let iy = y; iy <= endY; iy++) {
                                            for (let ix = x; ix <= endX; ix++) {
                                                keysToDelete.push(ix + '.' + iy);
                                            }
                                        }
                                        keysToDelete.forEach(key => delete pixels[key]);
                                    }
                                }
                            }
                        }
                        debug("Color meshing end");
                        // Placeholder for merging rectangles into polygons logic
                        // This can be a complex process involving checking adjacency and overlaps
                        // For simplicity, we will assume rectangles are merged if they share an edge or overlap

                        // Example simple merge implementation (improvement needed for complex merging)
                        debug("Shape building start");
                        for (let rectangle of rectangles) {
                            let shape = new codeNames.body.shape();
                            let we = rectangle[2]*sample/2;
                            let he = rectangle[3]*sample/2;
                            shape.ca = [
                                new codeNames.body.point(we,he),
                                new codeNames.body.point(we,-he),
                                new codeNames.body.point(-we,-he),
                                new codeNames.body.point(-we,he)
                            ];
                            shape.x = (rectangle[0] * sample)+we;
                            shape.y = (rectangle[1] * sample)+he;
                            shape.Jr = true;
                            shape.color = parseInt(color); // Ensure color is parsed as an integer

                            bod.Sa.push(shape);
                        }

                        let pixelsleft = 0;
                        for (let pixel in pixels){
                            pixelsleft++;
                            let x = pixel.split('.')[0]-0;
                            let y = pixel.split('.')[1]-0;
                            let shape = new codeNames.body.shape();
                            let we = sample/2;
                            let he = sample/2;
                            shape.ca = [
                                new codeNames.body.point(we,he),
                                new codeNames.body.point(we,-he),
                                new codeNames.body.point(-we,-he),
                                new codeNames.body.point(-we,he)
                            ];
                            shape.x = x*sample+we;
                            shape.y = y*sample+he;
                            shape.Jr = true;
                            shape.color = parseInt(color);

                            bod.Sa.push(shape);
                        }
                    }
                }
                debug("Shape building stop");
                editorMaps[0].state.all[5].push(bod);
                if (WSS){
                    debug("Map rewrite start");
                    WSS.send(`2[1, [50,"${editorMaps[0].state.rc()}"]]`);
                    window.multiplayerSession.TJ.bW();
                }
                //editorMaps[0].state.ac(editorMaps[0].state.rc());
            }

        }


        window.mapFromImage = mapFromImage;
        /*{
    "b": [
        {
            "2": 12.25,
            "3": 11.25,
            "8": 3,
            "14": 2,
            "23": true,
            "s": [
                {
                    "7": 10595505,
                    "14": true,
                    "p": [
                        -0.25,
                        -0.25,
                        0.25,
                        -0.25,
                        0.25,
                        0.25,
                        -0.25,
                        0.25
                    ]
                }
            ]
        }
    ],
    "j": [],
    "s": [],
    "p": [],
    "tu": [],
    "tc": [],
    "gp": [],
    "c": [],
    "set": {
        "3": 40,
        "4": 0.5,
        "10": 60,
        "11": 0,
        "12": 3690098,
        "15": 40,
        "16": 25,
        "17": 2108492
    }
}*/

        window.WebSocket.prototype.send = function(args) {
            if(this.url.includes("/socket.io/?EIO=3&transport=websocket&sid=")){
                if(typeof(args) == "string" && !excludewss.includes(this)){
                    if (!WSS){
                        WSS = this;
                    }
                    if (WSS == this){
                        if (args.startsWith('42[1,[')) {
                            try{
                                let packet = JSON.parse(args.slice(5,-1))
                                if (packet[0] == 62){
                                    settings = packet[1];
                                }
                            }catch(error){}
                        }else if (args.startsWith('42[2,')) {
                            myid = 0;
                            hostId = 0;
                        }
                    }else{
                        excludewss.push(this);
                    }
                    //debug('SENT',args);
                }
                if (!this.injectedNCE){
                    this.injectedNCE = true;
                    const originalClose = this.onclose;
                    this.onclose = (...args) => {
                        if (WSS == this){
                            WSS = 0;
                            excludewss = [];
                            users = [];
                        }
                        originalClose.call(this,...args);
                    }
                    this.onmessage3 = this.onmessage;
                    this.onmessage = function(event){
                        if(!excludewss.includes(this) && typeof(event.data) == 'string'){
                            if (event.data.startsWith('42[')){
                                let packet = JSON.parse(event.data.slice(2,event.data.length));
                                if (packet[0] == 63){
                                    settings = packet[1];
                                }
                                if (packet[0] == 7){
                                    myid = packet[1][0]
                                    hostId = packet[1][1];
                                    for (let i of packet[1][3]){
                                        users.push({"team": i[2],"color":(i[7][0] || i[7][1]),"name":i[0],"id":i[4],"lvl":i[6]});
                                    }
                                }
                                if (packet[0] == 25){
                                    let plr = findUser(packet[1]);
                                    if (plr){
                                        plr.team = packet[2];
                                    }
                                }
                                if (packet[0] == 9){
                                    hostId = packet[2];
                                    let user = findUser(packet[1]);
                                    if (user){
                                        users.splice(user.index,1);
                                    }
                                }
                                if (packet[0] == 45){
                                    hostId = packet[1];
                                }
                                if (packet[0] == 8){
                                    users.push({"name":packet[1][0],"color":(packet[7]? (packet[7][1] || packet[7][0]):undefined),"team":packet[1][2],"id":packet[1][4],"lvl":packet[1][6]});
                                }
                            }
                        }
                        this.onmessage3.call(this,event);
                    }
                }
            }
            return originalSend.call(this, args);
        }

        let chats = document.getElementsByClassName('content');
        window.addEventListener('keydown',(event) => {
            shiftKey = event.shiftKey
        });

        window.addEventListener('keyup',(event) => {
            shiftKey = event.shiftKey
        });

        window.hescape = (s) => {
            let lookup = {'$':'&#36;','%':'&#37;','.':'&#46;','+':'&#43;','-':'&#45;','&':"&amp;",'"': "&quot;",'\'': "&apos;",'<': "&lt;",'*':'&#42;','=':'&#61;','>': "&gt;",'#':'&#35;',':':'&#58;',';':'&#59;','`':'&#96;'};
            return s.replace( /[\*=%#\-+&"'<>]/g, c => lookup[c] );
        }

        var lastMousePos = {x: 0,y: 0};

        window.addEventListener("mousemove",(e) => {
            e = e || window.event;
            let pos1 = lastMousePos.x || e.clientX;
            let pos2 = lastMousePos.y || e.clientY;
            lastMousePos = {x: e.clientX,y: e.clientY};
            if (document.activeElement && document.activeElement.dataset.dragable){
                e.preventDefault();
                document.activeElement.style.top = (document.activeElement.offsetTop + (e.clientY-pos2)) + "px";
                document.activeElement.style.left = (document.activeElement.offsetLeft + (e.clientX-pos1)) + "px";
            }
        });

        function getRGBFromNUM(colorID,offset,max){
            const red = (colorID >> 16) & 0xFF;
            const green = (colorID >> 8) & 0xFF;
            const blue = colorID & 0xFF;

            // Construct the RGB color representation
            return `rgb(${Math.max(max || 0,red-(offset || 0))}, ${Math.max(max || 0,green-(offset || 0))}, ${Math.max(max || 0,blue-(offset || 0))})`;
        }

        function display(text,ingamecolor,lobbycolor,sanitize){
            if (WSS){
                let div = document.createElement('div');
                div.classList.add('statusContainer');
                let span = document.createElement('span');
                span.classList.add('status');
                span.style.color = lobbycolor || "#ffffff";
                if (sanitize != false){
                    span.textContent = text;
                }else{
                    span.innerHTML = text;
                }
                span.style.backgroundColor = 'rgba(37, 38, 42, 0.768627451)';
                div.style.borderRadius = '7px';
                div.appendChild(span);
                let clone = div.cloneNode(true);
                clone.children[0].style.color = ingamecolor || '#ffffff';
                setTimeout(() => {
                    clone.remove();
                },11500);
                for (let i of chats){
                    if (i.parentElement.classList.contains('chatBox')){
                        i.appendChild(div);
                        i.scrollTop = Number.MAX_SAFE_INTEGER;
                    }else{
                        i.appendChild(clone);
                    }
                }
            }
        }

        function updateEditor() {
            document.querySelector("#editorContainer > div.topMenu > div.topLabel.fileMenu > div > div:nth-child(5)").click();
            window.multiplayerSession.TJ.hide();
        }

        let windowContent;
        let windowTopProperties;

        function setPropertiesName(title) {
            let closeClick = windowTopProperties.children[0].onclick;
            let minimizeClick = windowTopProperties.children[1].onclick;
            windowTopProperties.innerHTML = windowTopProperties.innerHTML.replace("Merge Shapes",title);
            windowTopProperties.children[0].onclick = closeClick;
            windowTopProperties.children[1].onclick = minimizeClick;
        }

        let fields = 0;

        function addPropertiesField(title,description) {
            let div = document.createElement('div');
            div.classList.add("row");
            fields += 1;
            if (fields % 2 == 0) {
                div.classList.add("bgalt");
            }
            windowContent.appendChild(div);
            div.innerHTML = `<span class="title">${title}</span><span class="subtitle">${description}</span><input>`;
            return div;
        }

        function addPropertiesButton(title) {
            let div = document.createElement('div');
            div.classList.add("row");
            windowContent.appendChild(div);
            div.innerHTML = `<button>${title}</button>`;
            return div;
        }

        function setAdvice(advice) {
            if (document.querySelector("#editorContainer").style.display != 'none'){
                document.querySelector("#relativeContainer > div").textContent = advice;
            }
        }

        function openProperties() {
            document.querySelector("#editorContainer > div.topMenu > div.topLabel.toolsMenu > div > div:nth-child(1)").click();
            windowTopProperties = document.querySelector("#editorPropertiesWindow > div.topBar");
            windowContent = document.querySelector("#editorPropertiesWindow > div.contentDiv");
            windowContent.innerHTML = '';
        }

        function scaleBody(bodyId,sampleX,sampleY,sample,reverse) {
            for (let i in editorState.mF.state.all[5][bodyId].Sa) {
                let p = editorState.mF.state.all[5][bodyId].Sa[i];
                if (p) {
                    p.x *= sampleX;
                    p.y *= sampleY;
                    p.ra *= sample;
                    for (let i in p.ca) {
                        let z = p.ca[i];
                        if (z) {
                            z.x *= sampleX;
                            z.y *= sampleY;
                        }
                    }
                    if (reverse){
                        p.ca.reverse();
                    }
                }
            }
            editorState.render();
        }

        const editorTools = document.querySelector("#editorContainer > div.topMenu > div.topLabel.toolsMenu > div");
        let scaleBodyTool = document.createElement('div');
        let lastGraphicsAlpha = .5;
        editorTools.appendChild(scaleBodyTool);
        let overlayTool = document.createElement('div');
        editorTools.appendChild(overlayTool);
        let autosavesTool = document.createElement('div');
        editorTools.appendChild(autosavesTool);
        let centerTool = document.createElement('div');
        editorTools.appendChild(centerTool);
        let createTurret = document.createElement('div');
        editorTools.appendChild(createTurret);
        let mergeSel = document.createElement('div');
        editorTools.appendChild(mergeSel);
        let overlayX = 0.5;
        let overlayY = 0.5;
        // let brush = document.createElement('div');
        //editorTools.appendChild(brush);
        let copyMap = document.createElement('div');
        editorTools.appendChild(copyMap);
        copyMap.textContent = 'Copy Map';
        copyMap.classList.add("item");
        overlayTool.classList.add("item");
        overlayTool.textContent = 'Overlay Tool';
        createTurret.classList.add("item");
        createTurret.textContent = 'Create Turret';
        autosavesTool.classList.add("item");
        mergeSel.textContent = 'Merge selected';
        mergeSel.classList.add("item")
        mergeSel.onclick = () => {
            const sel = lastSelection;
            const mSel = lastSelected;
            document.querySelector("#editorContainer > div.topMenu > div.topLabel.toolsMenu > div > div:nth-child(1)").click()
            for (let x in mSel) {
                let i = mSel[x];
                if (i != sel && i.dv) {
                    let inp1 = document.querySelector("#editorPropertiesWindow > div.contentDiv > div.row.bgalt > input");
                    let inp2 = document.querySelector("#editorPropertiesWindow > div.contentDiv > div:nth-child(2) > input");;
                    inp1.value = i.id;
                    inp2.value = sel.id;
                    inp1.oninput({currentTarget: inp1});
                    inp2.oninput({currentTarget: inp2});
                    document.querySelector("#editorPropertiesWindow > div.contentDiv > div:nth-child(3) > button").click();
                }
            }
            document.querySelector("#editorPropertiesWindow > div.topBar > div.closeButton").click();
            for (let i of lastSelected) {
                i.eb.destroy();
                delete i.eb;
                i = null;
            }
            lastSelected = [];
        };
        autosavesTool.textContent = 'Auto Saves';
        overlayTool.textContent = 'Overlay Tool';
        let overlayTexture = null;
        let lastOverlayGraphics = null;
        let lastOverlayLink = '';
        createTurret.onclick = () => {
            let turret = new turretObj();
            turret.x = 0;
            turret.y = 0;
            editorState.mF.state.Fl.push(turret);
            editorState.render();
        }
        autosavesTool.onclick = () => {
            openProperties();
            setPropertiesName("Auto saves");
            const clearButton = addPropertiesButton("Delete saves");
            clearButton.children[0].onclick = () => {
                autosaves = [];
                localStorage.setItem('autosaves','[]');
            }
            for (let id in autosaves){
                const data = autosaves[id];
                if (data){
                    const button = addPropertiesButton("Save #"+id+" by "+data[1]+" - "+timeConverter(data[2] || Date.now()));
                    button.children[0].onclick = () => {
                        editorState.mF.state.ac(data[0]);
                        editorState.mF.BN = data[1];
                        editorState.render();
                    }
                }
            }
        }
        overlayTool.onclick = () => {
            openProperties();
            setPropertiesName("Overlay Tool");
            const image = addPropertiesField("Overlay Image URL","The direct link to the image used for overlay");
            const imageFile = addPropertiesButton("Select File");
            const width = addPropertiesField("Width Scale","width of the image from scale to screen");
            const height = addPropertiesField("Height Scale","height of the image from scale to screen");
            const alpha = addPropertiesField("Alpha","The opacity of the image");
            const sxe = addPropertiesField("Position X Scale","The X position scale of the image to screen");
            const sye = addPropertiesField("Position Y Scale","The Y position scale of the image to screen");
            const alter = addPropertiesButton("Update overlay");
            const rem = addPropertiesButton("Remove overlay");
            alpha.children[2].value = lastGraphicsAlpha;
            image.children[2].value = lastOverlayLink;
            width.children[2].value = overlayWidth;
            height.children[2].value = overlayHeight;
            sxe.children[2].value = overlayX;
            sye.children[2].value = overlayY;
            imageFile.children[0].onclick = () => {
                let input = document.createElement("input");
                input.setAttribute("type", "file");
                input.setAttribute("accept","image/png, image/jpeg");
                input.click();
                input.onchange = () => {
                    if (input.files.length == 1) {
                        const reader = new FileReader();
                        reader.addEventListener(
                            "load",
                            () => {
                                // convert image file to base64 string
                                image.children[2].value = reader.result;
                                alter.children[0].click();
                            },
                            false,
                        );

                        reader.readAsDataURL(input.files[0]);
                    }
                }
            }
            rem.children[0].onclick = () => {
                if (overlayTexture){
                    overlayTexture.baseTexture.destroy();

                }
                if (lastOverlayGraphics){
                    lastOverlayGraphics.destroy();
                }
                lastOverlayGraphics = null;
                overlayTexture = null;
            }
            alter.children[0].onclick = async () => {
                let link = image.children[2].value;
                let widthe = width.children[2].value-0;
                let heighte = height.children[2].value-0;
                let alphae = alpha.children[2].value-0;
                let xe = sxe.children[2].value-0;
                let ye = sye.children[2].value-0;
                if (widthe != widthe || heighte != heighte){
                    widthe = 100;
                    heighte = 100;
                }
                if (overlayTexture){
                    overlayTexture.baseTexture.destroy();

                }
                if (lastOverlayGraphics){
                    lastOverlayGraphics.destroy();
                }
                lastOverlayLink = link;
                let img = new Image();
                img.src = link;
                window.PIXI.BaseImageResource.crossOrigin(img, link, true);
                img.onload = () => {
                    let base = new window.PIXI.BaseTexture(img);
                    let texture = new window.PIXI.Texture(base);
                    overlayTexture = texture;
                    lastOverlayGraphics = new window.PIXI.Sprite(overlayTexture);
                    lastOverlayGraphics.width = widthe;
                    lastOverlayGraphics.height = heighte;
                    lastOverlayGraphics.anchor.x = 0;
                    lastGraphicsAlpha = alphae;
                    lastOverlayGraphics.alpha = alphae;
                    overlayWidth = widthe;
                    overlayHeight = heighte;
                    overlayX = xe;
                    overlayY = ye;
                    lastOverlayGraphics.anchor.y = 0;
                    lastOverlayGraphics.x = 0;
                    lastOverlayGraphics.y = 0;
                    toppest.addChild(lastOverlayGraphics);
                }
            }
        }

        copyMap.onclick = () => {
            document.querySelector("#editorContainer > div.topMenu > div.topLabel.fileMenu > div > div:nth-child(3)").click();
            setAdvice("Saving map...");
            document.querySelector("#appContainer > div.mapListContainer").style.display = 'none';
            new Promise((r,f) => {
                let intervalID = setInterval(() => {
                    if (document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.mapsContainer > div:nth-child(1)")) {
                        r();
                        clearInterval(intervalID);
                    }
                },0);
            })
                .then(() => {
                document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.mapsContainer > div:nth-child(1)").click();
                document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.enterNameWindow > input").value = "#"+Math.floor(Math.random()*1000)+" by " + editorState.mF.BN;
                setAdvice("Map saved as "+document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.enterNameWindow > input").value);
                document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.enterNameWindow > textarea").value = "This map was copied using NCE.";
                document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.enterNameWindow > select").value = 0;
                document.querySelector("#appContainer > div.mapListContainer > div.mapList > div.enterNameWindow > div.button.okButton").click();
                document.querySelector("#editorContainer > div.topMenu > div.topLabel.fileMenu > div > div:nth-child(3)").classList.add("disabled");
                editorState.mF.BN = 'COPIED';
                editorState.mF.FN = 0;
                editorState.mF.IN = true;
            })
        }
        scaleBodyTool.textContent = 'Scale Body';
        scaleBodyTool.classList.add("item");
        centerTool.textContent = 'Center Tools';
        centerTool.classList.add("item");
        //brush.classList.add("item");
        /*brush.onclick = () => {
        openProperties();
        setPropertiesName("Brush Color");
        const hex = addPropertiesField("Hex Color","The hex color used for brush:");
        const buttton = addPropertiesButton("Set");
        buttton.children[0].onclick = () => {
            let color = hexToRgb(botColor.children[1].value);
            if (color){//21
                let int = rgbToInt(color.r,color.g,color.b);
                const currentState = editorMaps[0].state;
                updateInEditor();
                editorMaps[0].state = currentState;
                updateInEditor();
            }
        }
    }*/
        centerTool.onclick = () => {
            openProperties();
            setPropertiesName("Center Body Tools");
            const srcId = addPropertiesField("Source Body ID","The body which center (aka. origin and push or bat point)");
            const sxe = addPropertiesField("Shift X","The scale used for X axis:");
            const sye = addPropertiesField("Shift Y","The scale used for Y axis:");
            const removeGlitch = addPropertiesButton("Remove Glitched Polygons From Body");

            removeGlitch.children[0].onclick = () => {
                let bodyId = srcId.children[2].value-0;
                let body = editorState.mF.state.all[5][bodyId];
                if (body) {
                    for (let i2 in body.Sa) {
                        let s = body.Sa[i2];
                        if (s && s.ca.length < 3 && s.ra <= 0){
                            delete body.Sa[i2];
                            break;
                        }
                    }
                }
                editorState.render();
            }
            const buttton1 = addPropertiesButton("Shift all offsets by X and Y (useful for determining where a player may bat or push the body)");
            buttton1.children[0].onclick = () => {
                let bodyId = srcId.children[2].value-0;
                let shiftX = sxe.children[2].value-0;
                let shiftY = sye.children[2].value-0;
                for (let i in editorState.mF.state.all[5][bodyId].Sa) {
                    let p = editorState.mF.state.all[5][bodyId].Sa[i];
                    if (p) {
                        p.x -= shiftX;
                        p.y -= shiftY;
                    }
                }
                editorState.mF.state.all[5][bodyId].x += shiftX;
                editorState.mF.state.all[5][bodyId].y += shiftY;
                editorState.render();
            }
            const buttton2 = addPropertiesButton("Center all offsets on bounding box (between all shapes, useful for determining where a player may bat or push the body)");
            buttton2.children[0].onclick = () => {
                let bodyId = srcId.children[2].value-0;
                let finalX = 0;
                let finalY = 0;
                let finalZ = 0;
                for (let i in editorState.mF.state.all[5][bodyId].Sa) {
                    let p = editorState.mF.state.all[5][bodyId].Sa[i];
                    if (p) {
                        let offset = 0;
                        let ofx = 0;
                        let ofy = 0;
                        let ofz = 0;
                        for (let i in p.ca) {
                            let z = p.ca[i];
                            if (z) {
                                ofx += z.x;
                                ofy += z.y;
                                ofz++;
                            }
                        }
                        ofx /= ofz;
                        ofy /= ofz;
                        for (let i in p.ca) {
                            let z = p.ca[i];
                            if (z) {
                                z.x -= ofx;
                                z.y -= ofy;
                            }
                        }
                        finalX += (p.x+ofx);
                        finalY += (p.y+ofy);
                        finalZ++;
                    }
                }
                finalX /= finalZ;
                finalY /= finalZ;
                for (let i in editorState.mF.state.all[5][bodyId].Sa) {
                    let p = editorState.mF.state.all[5][bodyId].Sa[i];
                    if (p) {
                        p.x -= finalX;
                        p.y -= finalY;
                    }
                }
                editorState.mF.state.all[5][bodyId].x += finalX;
                editorState.mF.state.all[5][bodyId].y += finalY;
                editorState.render();
            }
        }
        scaleBodyTool.onclick = () => {
            openProperties();
            setPropertiesName("Scale Body");
            const bodyId = addPropertiesField("Source Body ID","The body to be scaled:");
            const sample = addPropertiesField("Scale Sample","The scale used for circles:");
            const sampleX = addPropertiesField("Scale Sample X","The scale used for X axis:");
            const sampleY = addPropertiesField("Scale Sample Y","The scale used for Y axis:");
            const buttton = addPropertiesButton("Scale");
            buttton.children[0].onclick = () => {
                scaleBody(bodyId.children[2].value,sampleX.children[2].value,sampleY.children[2].value,sample.children[2].value);
            }
            const buttton2 = addPropertiesButton("Flip X (Physics shapes compatible)");
            buttton2.children[0].onclick = () => {
                scaleBody(bodyId.children[2].value,-1,1,1,true);
            }
            const buttton3 = addPropertiesButton("Flip Y (Physics shapes compatible)");
            buttton3.children[0].onclick = () => {
                scaleBody(bodyId.children[2].value,1,-1,1,true);
            }
        };

        function hexToRgb(hex) {
            let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            return result ? {
                r: parseInt(result[1], 16),
                g: parseInt(result[2], 16),
                b: parseInt(result[3], 16)
            } : null;
        }

        function rgbToInt(r,g,b) {
            return 256*256*r+256*g+b;
        }

        const bgSet = document.querySelector("#editorContainer > div.sideBar > div:nth-child(17) > div.footer");
        const topColor = document.createElement('div');
        const botColor = document.createElement('div');
        bgSet.appendChild(topColor);
        bgSet.appendChild(botColor);
        topColor.innerHTML = `<span class="label">Top Color</span>
    <input style="position: absolute; width: 100%; background: #303030; top: 24px; border: 1px solid #222222; font-family: 'Bai Jamjuree'; outline: none; color: #ebebeb; padding: 4px;" class="nameField" maxlength="7">`
    botColor.innerHTML =`<span class="label">Bot Color</span>
    <input style="position: absolute; width: 100%; background: #303030; top: 24px; border: 1px solid #222222; font-family: 'Bai Jamjuree'; outline: none; color: #ebebeb; padding: 4px;" class="nameField" maxlength="7">`

    botColor.classList.add('paramContainer');
topColor.classList.add('paramContainer');
botColor.children[1].addEventListener("keyup",() => {
    let color = hexToRgb(botColor.children[1].value);
    if (color){//21
        let int = rgbToInt(color.r,color.g,color.b);
        editorState.mF.state.settings[0][codeNames.settings[10]] = int;
        editorState.render();
        document.querySelector("#editorContainer > div.sideBar > div.preview.bgTexPreview").click();
        botColor.children[1].focus();
    }
})
topColor.children[1].addEventListener("keyup",() => {
    let color = hexToRgb(topColor.children[1].value);
    if (color){//21
        let int = rgbToInt(color.r,color.g,color.b);
        debug(int);
        editorState.mF.state.settings[0][codeNames.settings[21]] = int;
        editorState.render();
        document.querySelector("#editorContainer > div.sideBar > div.preview.bgTexPreview").click();
        topColor.children[1].focus();
    }
})
let editorDiv = document.querySelector("#appContainer > div.lobbyContainer > div.settingsBox > div.editorButton.settingsButton");
let inputs = document.getElementsByClassName('input');
let chatI = [];

for (let c of inputs){
    if (c.parentElement.classList.contains('inGameChat') || c.parentElement.classList.contains('chatBox')){
        chatI.push(c);
        c.addEventListener('keydown',(event) => {
            if (event.keyCode == 13){
                let newMsg = runCMD(c.value);
                if (newMsg) {
                    if (newMsg.length < 2) {c.value = '';}else{c.value = newMsg;}
                }
            }
        });
    }
}

function runCMD(command){
    if (command == "/image"){
        let input = document.createElement("input");
        input.setAttribute("type", "file");
        input.setAttribute("accept","image/png, image/jpeg");
        input.click();
        input.onchange = () => {
            if (input.files.length == 1) {
                const reader = new FileReader();
                reader.addEventListener(
                    "load",
                    () => {
                        // convert image file to base64 string
                        mapFromImage(reader.result,0,0,0,10);
                    },
                    false,
                );

                reader.readAsDataURL(input.files[0]);
            }
        }
        return ' ';
    }
    if (command.length >= 2){
        return command;
    }
}
});
});