florr megg timer

shows 15s timer for mythic egg/yggdrasil

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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();