MyBot Tools

MyBot Pixel Place Tools

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.greasyfork.org/scripts/479130/1275795/MyBot%20Tools.js

// ==UserScript==
// @name         MyBot Tools
// @description  MyBot Pixel Place Tools
// @version      1.6.2
// @author       SamaelWired
// @namespace    https://greasyfork.org/tr/users/976572
// @match        https://pixelplace.io/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=pixelplace.io
// @license      MIT
// @grant        none
// @run-at       document-start
// ==/UserScript==
(() => {
    const MyBot = window.MyBot || { modules: {} };
    window.MyBot = MyBot;
    if ('Tools' in MyBot.modules) return;

    const progressManager = func => {
        const callbacks = {};
        const root = new Proxy({}, {
            get(target, key) {
                if (!target[key]) target[key] = callback => (callbacks[key] = callback, root);
                return target[key];
            }
        });
        root.start = (...args) => func(callbacks)(...args);
        return root;
    };

    const worker = progressManager(({ progress = () => 0, finish = () => 0 }) =>
        (data, func) => {
            const worker = new Worker(URL.createObjectURL(new Blob([`
            const progress = value => self.postMessage({ progress: true, value });
            const finish = value => self.postMessage({ finish: true, value });
            onmessage = async ({ data }) => {
                await (${func.toString()})(data);
                close();
            };
        `], { type: "text/javascript" })));
            worker.addEventListener('message', ({ data }) => data.progress && progress(data.value));
            worker.addEventListener('message', ({ data }) => data.finish && finish(data.value));
            worker.postMessage(data);
        });

    const module = {
        args: {},

        _wheelID: 0,
        get wheel() {
            const { exclude, colors } = module.args;
            let pixel = module._wheelID + 1;
            while (exclude.includes(colors[pixel]))
                if (colors[++pixel] == null)
                    pixel = 0;
            module._wheelID = pixel;
            return pixel;
        },

        pixel: 0,
        size: 9,
        innerSize: 0,
        interval: 0,

        RGB2P(r, g, b) {
            const closest = module.args.rgb.map(([r2, g2, b2]) =>
                ((r2 - r) ** 2 + (g2 - g) ** 2 + (b2 - b) ** 2) * 0x1000000 + (r2 << 16) + (g2 << 8) + b
            )
                .sort((a, b) => a - b)[0];

            return module.args.colors.indexOf(closest & 0xFFFFFF);
        },
        CLR2P(color) {
            return module.RGB2P((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
        },
    };

    module.config = ({ colors, exclude, zero, timer, tickSpeed }) => {
        const palette = [...colors].map(color => exclude.includes(color) ? zero : color);
        const rgb = palette.filter(clr => clr != zero).map(clr => [((clr >> 16) & 0xFF), ((clr >> 8) & 0xFF), (clr & 0xFF)]);
        Object.assign(module.args, { colors, exclude, zero, timer, tickSpeed, palette, rgb });
    };

    module.shader = progressManager(({
        progress = () => 0, finish = () => 0, tick = () => 0,
        silent = true,
        interval = module.interval
    }) => (map) => {
        const { timer } = module.args;
        let pos = 0;

        let t = timer.setInterval(() => {
            const { tickSpeed } = module.args;
            let i = 0;

            for (; pos < map.pixels.length;) {
                silent || progress(pos / map.pixels.length, t);
                if (map.pixels[pos] === 255) {
                    pos++;
                    continue;
                }

                tick(pos % map.width, pos / map.width >> 0, map.pixels[pos]);
                pos++;

                i++;
                if (i > tickSpeed) return;
                continue;
            }

            timer.clearInterval(t);
            finish(t);
        }, interval);

        return t;
    });

    module.square = progressManager(({
        progress = () => 0, finish = () => 0, tick = () => 0,
        silent = true,
        interval = module.interval,
        size = module.size,
        innerSize = module.innerSize,
    }) => (x, y, pixel = module.pixel) => {
        const { timer } = module.args;
        const half = size >> 1;
        const innerHalf = innerSize >> 1;
        let xi = -half;
        let yi = -half;

        let t = timer.setInterval(() => {
            const { tickSpeed } = module.args;
            let i = 0;

            for (; yi < half + 1;) {
                for (; xi < half + 1;) {
                    const pos = (xi + half + (yi + half) * size);
                    silent || progress(pos / size ** 2, t);

                    if (pixel === 255 || xi > -innerHalf && xi < innerHalf && yi > -innerHalf && yi < innerHalf) {
                        xi++;
                        continue;
                    }

                    tick(x + xi, y + yi, pixel);
                    xi++;

                    i++;
                    if (i > tickSpeed) return;
                    continue;
                }
                yi++;
                xi = -half;
            }

            timer.clearInterval(t);
            finish(t);
        }, interval);

        return t;
    });

    module.circle = progressManager(({
        progress = () => 0, finish = () => 0, tick = () => 0,
        silent = true,
        interval = module.interval,
        radius = module.size >> 1,
        innerRadius = module.innerSize >> 1,
    }) => (x, y, pixel = module.pixel) => {
        const { timer } = module.args;
        const half = radius;
        const innerHalf = innerRadius;
        let xi = -half;
        let yi = -half;

        let t = timer.setInterval(() => {
            const { tickSpeed } = module.args;
            let i = 0;

            for (; yi < half + 1;) {
                for (; xi < half + 1;) {
                    const pos = (xi + half + (yi + half) * size);
                    silent || progress(pos / size ** 2, t);

                    if (pixel === 255 || xi ** 2 + yi ** 2 > half ** 2 || xi ** 2 + yi ** 2 < innerHalf ** 2) {
                        xi++;
                        continue;
                    }

                    tick(x + xi, y + yi, pixel);
                    xi++;

                    i++;
                    if (i > tickSpeed) return;
                    continue;
                }
                yi++;
                xi = -half;
            }

            timer.clearInterval(t);
            finish(t);
        }, interval);

        return t;
    });

    module.image = progressManager(({
        progress = () => 0, finish = () => 0, tick = () => 0,
        interval = module.interval,
    }) => (pixels, x, y, w, h) => {
        const { timer } = module.args;
        let xi = 0;
        let yi = 0;

        let t = timer.setInterval(() => {
            const { tickSpeed } = module.args;
            let i = 0;

            for (; yi < h;) {
                for (; xi < w;) {
                    const pos = xi + yi * w;
                    progress(pos / pixels.length, t);

                    const pixel = pixels[pos];
                    if (pixel === 255) {
                        xi++;
                        continue;
                    }

                    tick(x + xi, y + yi, pixel);
                    xi++;

                    i++;
                    if (i > tickSpeed) return;
                    continue;
                }
                yi++;
                xi = 0;
            }

            timer.clearInterval(t);
            finish(t);
        }, interval);

        return t;
    });

    module.order = new Proxy({}, {
        get(_, type) {
            return progressManager(({
                progress = () => 0, finish = () => 0,
                silent = true,
                center = [0, 0]
            }) => (queue) => {
                if (type == 'fromCenterQueue' || type == 'toCenterQueue') {
                    type = type.replace('Queue', '');
                    const [cxn, cyn] = queue.reduce(([x, y], [x2, y2]) => [x + x2, y + y2], [0, 0]);
                    center = [cxn / queue.length >> 0, cyn / queue.length >> 0];
                }
                worker.progress(progress).finish(finish)
                    .start(
                        { queue, type, center, silent },
                        async ({ queue, type, center, silent }) => {
                            const q = [...queue];
                            const size = queue.length * Math.log(queue.length) | 0;
                            const [cx, cy] = center;
                            let i = 0;

                            const method = ({
                                start([x, y, p, i], [x2, y2, p2, i2]) {
                                    silent || progress(i++ / size);
                                    return i - i2;
                                },
                                end([x, y, p, i], [x2, y2, p2, i2]) {
                                    silent || progress(i++ / size);
                                    return i2 - i;
                                },
                                rand() {
                                    silent || progress(i++ / size);
                                    return Math.random() - .5;
                                },

                                top([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return y - y2;
                                },
                                left([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return x - x2;
                                },
                                right([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return x2 - x;
                                },
                                bottom([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return y2 - y;
                                },

                                fromCenter([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return ((x - cx) ** 2 + (y - cy) ** 2) - ((x2 - cx) ** 2 + (y2 - cy) ** 2);
                                },
                                toCenter([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return ((x2 - cx) ** 2 + (y2 - cy) ** 2) - ((x - cx) ** 2 + (y - cy) ** 2);
                                },

                                fromVertical([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return Math.abs(x - cx) - Math.abs(x2 - cx);
                                },
                                toVertical([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return Math.abs(x2 - cx) - Math.abs(x - cx);
                                },

                                fromHorizontal([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return Math.abs(y - cy) - Math.abs(y2 - cy);
                                },
                                toHorizontal([x, y], [x2, y2]) {
                                    silent || progress(i++ / size);
                                    return Math.abs(y2 - cy) - Math.abs(y - cy);
                                },
                            });

                            q.sort(method[type] || method['start']);
                            silent || progress(1);
                            finish(q);
                        }
                    );
            });
        }
    });

    MyBot.modules.Tools = module;
})();