florr megg timer

shows 15s timer for mythic egg/yggdrasil

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         florr megg timer
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  shows 15s timer for mythic egg/yggdrasil
// @author       bismuth
// @match        https://florr.io/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=florr.io
// @grant        none
// @license       none
// ==/UserScript==
class Automator {
    constructor() {
        this.index = 0;
        this.packet;
        this.buffer = new ArrayBuffer(4);
        this._u8 = new Uint8Array(this.buffer);
        this._i32 = new Int32Array(this.buffer);
        this._f32 = new Float32Array(this.buffer);
        this.init();
        this.ready = false;
    }
    endianSwap(val) { return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val >> 8) & 0xff00) | ((val >> 24) & 0xff) }
    u8() { return this.packet[this.index++] }
    vu() {
        let out = 0, at = 0;
        while (this.packet[this.index] & 0x80) {
            out |= (this.u8() & 0x7f) << at;
            at += 7;
        }
        out |= this.u8() << at;
        return out;
    }
    getConfig(bin) {
        const unreachable = 0x00, block = 0x02, loop = 0x03, if_ = 0x04, else_ = 0x05, end = 0x0b, br = 0x0c, br_if = 0x0d,
              call = 0x10, drop = 0x1a,
              local_get = 0x20, local_set = 0x21, local_tee = 0x22, global_set = 0x24, i32_load = 0x28, f32_load = 0x2a, f64_load = 0x2b, i32_load8_s = 0x2c, i32_load8_u = 0x2d, i32_load16_u = 0x2f,
              i32_store = 0x36, i64_store = 0x37, f32_store = 0x38, i32_store8 = 0x3a, i32_store16 = 0x3b,
              memory_grow = 0x40, i32_const = 0x41, i64_const = 0x42, f32_const = 0x43, i32_eqz = 0x45, i32_eq = 0x46, i32_lt_s = 0x48, i32_lt_u = 0x49,
              f32_eq = 0x5b, f32_lt = 0x5d, f32_gt = 0x5e,
              i32_add = 0x6a, i32_sub = 0x6b,
              i32_and = 0x71, i32_or = 0x72, i32_xor = 0x73,
              f32_add = 0x92, f32_sub = 0x93, f32_mul = 0x94,
              f32_demote_f64 = 0xb6;
        const i32 = 0x7f, i64 = 0x7e, f32 = 0x7d, f64 = 0x4c;
        const param = 0x01, local = 0x02;
        Number.prototype.fromvu = function() {
            let _ = this;
            const ret = [];
            while (_ >= 128) {
                ret.push((_ & 127) | 128);
                _ >>= 7;
            }
            ret.push(_);
            return ret;
        }
        Number.prototype.fromfloat = function() {
            return [...new Uint8Array(new Float32Array([this]).buffer)];
        }
        Array.prototype.countingOccurences = function(val) {
            let count = 0;
            for (const a of this) if (a === val) count++;
            return count;
        }
        const wasmRegex = (regex, repeat = false, start = 0) => {
            let ret = [], rets = [];
            jump: for (let n = start; n < this.packet.length - regex.length; n++) {
                this.index = n;
                ret = [];
                for (let p = 0; p < regex.length; p++) {
                    if (regex[p] === '*') this.vu();
                    else if (regex[p] === '+') ret.push(this.vu());
                    else if (this.u8() !== regex[p]) continue jump;
                }
                ret.index = n;
                if (repeat) rets.push(ret);
                else return ret;
            }
            return rets.length? rets: false;
        }
        const components = ['GUI','player'];
        let entListPtr, offset, entSize, componentOffsets = {}, fieldOffsets = {}, animatedBasePtrPtr, animatedOffset, arenaDimAnimated, squadCodeOffset;
        const c = [], fIndex = [];
        const funcs = [];
        const field_func = new Array(150).fill().map((_,ind) => ind & 1? '*': block);
        let count = 0;
        this.packet = new Uint8Array(bin);
        this.index = 8;
        while (this.index < this.packet.length) {
            const id = this.vu();
            const sectionLen = this.vu();
            if (id !== 10) {
                this.index += sectionLen;
                continue;
            }
            const bodyCount = this.vu();
            for (let i = 0; i < bodyCount; i++) {
                const len = this.vu();
                funcs.push(this.packet.subarray(this.index, this.index += len));
            }
            break;
        }
        for (let funcIndex = 0; funcIndex < funcs.length; funcIndex++) {
            let a;
            this.packet = funcs[funcIndex];
            /*
            if (a = wasmRegex([
                f32_const, ...(10).fromfloat(),
                f32_add,
                local_set, '*',
                end], true)) {
                for (const b of a) {
                    const d = b.index;
                    console.log(this.packet.slice(d,d+9));
                    this.packet.set([i32_const,0,f32_load,0,0], d);
                    count++;
                }
                console.log([
                f32_const, ...(10).fromfloat(),
                f32_add,
                local_set, '*',
                end])
                console.log(a);
            }
            */
            if (a = wasmRegex([
                12,
                i32,
                local_get, '*',
                i32_load, '*', '+'])) { c.push(a[0]); fIndex.push(funcIndex+358)}
            if (a = wasmRegex([i32_add,
                               call, '*',
                               block, '*',
                               i32_const, '*',
                               i32_load8_s, '*', '*',
                               i32_const, 0,
                               i32_lt_s,
                               if_, '*',
                               i32_const, '+',
                               i32_load, '*', '*',
                               i32_const, 0])) squadCodeOffset = a[0];
            if (a = wasmRegex([f32_load, '*', '*',
                               f32_mul,
                               local_tee, '*',
                               i32_const, '+',
                               f32_load])) arenaDimAnimated = a[0];
            if (a = wasmRegex([br_if, '*',
                               local_get, '*',
                               i32_const, '+',
                               i32_add,
                               local_set, '*',
                               i32_const, 1,
                               local_set, '*',
                               block])) fieldOffsets.petalsCollected = a[0];
            if (a = wasmRegex([i32_const, '+',
                               i32_add,
                               local_set, '*',
                               loop, '*',
                               local_get, '*',
                               i32_const, '+',
                               i32_sub,
                               call])) [offset, entSize] = a;
            if (a = wasmRegex([drop,
                               i32_const, '*',
                               i32_const, '*',
                               i32_store, '*', '*',
                               i32_const, '+',
                               call])) entListPtr = a[0];
            if (a = wasmRegex([f64_load, '*', '*',
                               f32_demote_f64,
                               local_get, '*',
                               i32_const, '+',
                               i32_add,
                               f32_load, '*', '*',
                               f32_sub,
                               f32_mul,
                               local_get, '*',
                               i32_const])) animatedOffset = a[0];
            if (a = wasmRegex([f32_load, '*', '+',
                               f32_store, '*', '+',
                               local_get, '*',
                               local_get, '*',
                               f32_load, '*', '+',
                               f32_store, '*', '+',
                               end])) {
                fieldOffsets.x = a[0];
                fieldOffsets.prevx = a[1];
                fieldOffsets.y = a[2];
                fieldOffsets.prevy = a[3];
            }
        }
        for (let funcIndex = 0; funcIndex < funcs.length; funcIndex++) {
            let a;
            this.packet = funcs[funcIndex];
            if (a = wasmRegex(field_func)) {
                const start = this.index;
                a = wasmRegex([block, '*',
                               local_get, '*',
                               call, '+',
                               local_tee, '*',
                               i32_load8_u, '*', '*',
                               i32_eqz,
                               if_, '*',
                               local_get, '*',
                               f32_load, '*', '+'], true, start)
                for (const [compFunc, offset] of a) {
                    if (fIndex.indexOf(compFunc) > 6) {
                        componentOffsets.renderable = c[fIndex.indexOf(compFunc)];
                        fieldOffsets.radius = offset;
                        break;
                    }
                }
                a = wasmRegex([end,
                               local_get, '*',
                               call, '+',
                               local_set, '*',
                               block], true, start);
                a = a.map(_ => _[0]);
                let b = [];
                for (let values of a) if (a.countingOccurences(values) === 3 && b.indexOf(values) === -1) b.push(values);
                if (b[0] < b[1]) componentOffsets.mob = c[fIndex.indexOf(b[0])];
                else componentOffsets.mob = c[fIndex.indexOf(b[1])];
                a = wasmRegex([end,
                               local_get, '*',
                               call, '+',
                               local_set, '*',
                               local_get, '*',
                               local_get, '*',
                               call, '*',
                               local_get, '*',
                               local_get, '*',
                               i32_load16_u, '*', '*',
                               i32_store16, '*', '+'], true, start);
                for (const [compFunc, offset] of a) {
                    if (fIndex.indexOf(compFunc) < 10) {
                        componentOffsets.drop = c[fIndex.indexOf(compFunc)];
                        fieldOffsets.dropID = offset;
                        fieldOffsets.dropRarity = offset+1;
                        break;
                    }
                }
                a = wasmRegex([block, '*',
                               local_get, '*',
                               call, '+',
                               local_tee, '*',
                               i32_load8_u], true, start);
                a = a.map(_ => _[0]);
                for (let values of a) if (a.countingOccurences(values) === 2) componentOffsets.position = c[fIndex.indexOf(values)];
                const mobFunc = fIndex[c.indexOf(componentOffsets.mob)];
                const dropFunc = fIndex[c.indexOf(componentOffsets.drop)];
                const playerFunc = fIndex[1];
                wasmRegex([end,
                           local_get, '*',
                           call, ...dropFunc.fromvu(),
                           local_set, '*',
                           block], false, start);
                fieldOffsets.dropRenderFlag = wasmRegex([i32_store8, '*', '+', br],false,this.index)[0];
                wasmRegex([end,
                           local_get, '*',
                           call, ...dropFunc.fromvu(),
                           local_set, '*',
                           local_get, '*',
                           i32_load], false, start);
                fieldOffsets.dropCount = wasmRegex([i32_store, '*', '+', br],false,this.index)[0];
                fieldOffsets.petalCooldown = wasmRegex([call, ...playerFunc.fromvu(),
                                                        i32_const, '+',
                                                        i32_add,
                                                        local_set, '*',
                                                        local_get, '*'], false, start)[0];
                fieldOffsets.inventory = wasmRegex([call, ...playerFunc.fromvu(),
                                                    i32_const, '+',
                                                    i32_add,
                                                    local_set, '*',
                                                    i32_const, '*'], false, start)[0];
                break;
            }
        }
        for (let funcIndex = 0; funcIndex < funcs.length; funcIndex++) {
            let a;
            this.packet = funcs[funcIndex];
            if (a = wasmRegex([i32_load, '*', ...componentOffsets.mob.fromvu(),
                               i32_load8_u, '*', '+',
                               local_tee, '*',
                               local_get, '*',
                               i32_load, '*', '*',
                               i32_load8_u, '*', '*'])) {
                fieldOffsets.mobRarity = a[0];
                if (fieldOffsets.isFriendly) fieldOffsets.mobID = 27 - fieldOffsets.isFriendly - fieldOffsets.mobRarity;
            }
            if (a = wasmRegex([local_get, '*',
                               if_, '*',
                               local_get, '*',
                               i32_load, '*', ...componentOffsets.mob.fromvu(),
                               i32_load8_u, '*', '+'])) {
                fieldOffsets.isFriendly = a[0];
                if (fieldOffsets.mobRarity) fieldOffsets.mobID = 27 - fieldOffsets.isFriendly - fieldOffsets.mobRarity;
            }
        }
        components.forEach((name,index) => { componentOffsets[name] = c[index]; })
        this.config = { entListPtr, offset, entSize, componentOffsets, fieldOffsets, animatedOffset, arenaDimAnimated, squadCodeOffset };
        console.log("Done with config", fIndex);
    }
    init() {
        const that = this;
        WebAssembly.instantiateStreaming = (r, i) => (r.arrayBuffer().then(b => WebAssembly.instantiate(b, i)));
        const _instantiate = WebAssembly.instantiate;
        WebAssembly.instantiate = new Proxy(WebAssembly.instantiate, {
            apply(t,ta,[bin,imports]) {
                that.getConfig(bin);
                return _instantiate(bin, imports).then(wasm => {
                    for (const exp of Object.values(wasm.instance.exports)) {
                        if (exp.buffer) {
                            const buffer = exp.buffer;
                            that.HEAPU8 = new Uint8Array(buffer);
                            that.HEAP8 = new Int8Array(buffer);
                            that.HEAPU16 = new Uint16Array(buffer);
                            that.HEAP32 = new Int32Array(buffer);
                            that.HEAPF32 = new Float32Array(buffer);
                            that.HEAPF64 = new Float64Array(buffer);
                            that.ready = true;
                            break;
                        }
                    }
                    that.loop();
                    return wasm;
                });
            }
        });
    }
    meggTimer() {
        const { HEAPF32, HEAP32, HEAPU16, HEAPU8 } = this;
        const { entListPtr, offset, entSize, animatedOffset, componentOffsets, fieldOffsets, arenaDimAnimated } = this.config;
        const camInfo = HEAPF32.subarray(entListPtr + animatedOffset >> 2, entListPtr + animatedOffset + 12 >> 2);
        const { inventory, petalCooldown, dropID, radius, x, y } = fieldOffsets;
        const { player, drop, renderable, mob, position } = componentOffsets;
        const {ctx} = this;
        ctx.setTransform(1,0,0,1,0,0);
        this.scale = Math.max(this.canvas.width/1920, this.canvas.height/1080);
        if (!this.playerEnt[player >> 2]) {
            for (let n = 0; n < 8192; n++) {
                if (this.entities[n][player >> 2] && HEAP32[this.entities[n][player >> 2] + inventory >> 2]) {
                    this.playerEnt = this.entities[n];
                    break;
                }
            }
        }
        const playerComponent = this.playerEnt[player >> 2];
        const time = performance.now();
        ctx.setTransform(1,0,0,1,0,0);
        for (let n = 0; n < 8; n++) {
            if (HEAPU16[playerComponent + petalCooldown + 2 * n >> 1] !== 65535) { this.lastLoaded[n] = time; continue; }
            if (HEAPU8[playerComponent + inventory + 2 * n] !== 16 && HEAPU8[playerComponent + inventory + 2 * n] !== 30 ) continue;
            if (camInfo[0] && camInfo[1] && camInfo[2] <= 0.9 && this.toggle) {
                const timeDiff = Math.min((time - this.lastLoaded[n]) / 1000, 15);
                ctx.setTransform(1,0,0,1,this.canvas.width/2,this.canvas.height - 200*this.scale);
                ctx.lineCap = 'round';
                ctx.lineWidth = 8;
                ctx.strokeStyle = '#333333';
                ctx.beginPath();
                ctx.moveTo((n-3.9)*this.scale*this.length,0);
                ctx.lineTo((n-3.1)*this.scale*this.length,0);
                ctx.stroke();
                ctx.lineWidth = 5;
                ctx.strokeStyle = timeDiff < 15? '#ff0000':'#85e37d';
                ctx.beginPath();
                ctx.moveTo((0.8*this.scale*this.length)/15*timeDiff+(n-3.9)*this.scale*this.length,0);
                ctx.lineTo((n-3.9)*this.scale*this.length,0);
                ctx.stroke();
                ctx.lineWidth = 0.9;
                ctx.setTransform(1,0,0,1,0,0);
            }
            else if (!(camInfo[0] && camInfo[1] && camInfo[2] <= 0.9)) for (let n = 0; n < 8; n++) this.lastLoaded[n] = performance.now();
        }
    }
    loop() {
        this.alive = false;
        this.canvas = document.getElementById('canvas'); this.ctx = this.canvas.getContext('2d');
        const { HEAPF32, HEAP32, HEAPU16, HEAPU8 } = this;
        const { entListPtr, offset, entSize, animatedOffset, componentOffsets, fieldOffsets, arenaDimAnimated } = this.config;
        const { inventory, petalCooldown, dropID, radius, x, y } = fieldOffsets;
        const { player, drop, renderable, mob, position } = componentOffsets;
        this.camInfo = HEAPF32.subarray(entListPtr + animatedOffset >> 2, entListPtr + animatedOffset + 12 >> 2);
        this.playerEnt = new Uint8Array(1000);
        this.lastLoaded = new Float32Array(8);
        this.length = 90;
        this.toggle = false; this.scale = 1;
        //const toX = x => (x - camInfo[0]) * (scale*camInfo[2]) + canvas.width / 2;
        //const toY = y => (y - camInfo[1]) * (scale*camInfo[2]) + canvas.height / 2;
        //preload entities with subarray
        let at = entListPtr + offset;
        this.entities = [];
        for (let n = 0; n < 8192; n++) this.entities.push(HEAP32.subarray(at >> 2, (at += entSize) >> 2));
        document.onkeydown = ({code}) => { if (code === 'KeyQ') this.toggle ^= true; }
        const that = this;
        window.requestAnimationFrame = new Proxy(requestAnimationFrame, {
            apply(t,ta,a) {
                that.meggTimer();
                that.alive = that.camInfo[2] <= 0.9;
                return t.apply(ta,a);
            }
        });
    }
}
window.automator = new Automator();