Greasy Fork

IdlePixel+

Idle-Pixel plugin framework

当前为 2022-03-09 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/441206/1025986/IdlePixel%2B.js

// ==UserScript==
// @name         IdlePixel+
// @namespace    com.anwinity.idlepixel
// @version      0.0.1
// @description  Idle-Pixel plugin framework
// @author       Anwinity
// @match        https://idle-pixel.com/play.php*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    class IdlePixelPlusPlugin {

        constructor(id, name, opts) {
            if(typeof id !== "string" || typeof name !== "string") {
                throw new TypeError("IdlePixelPlusPlugin constructor takes the following arguments: (id:string, name:string, opts?:object)");
            }
            this.id = id;
            this.name = name;
            this.opts = opts || {};
        }

        onLogin() { }
        onMessageReceived(data) { }
        onVariableSet(key, valueBefore, valueAfter) { }
        onChat(data) { }
        onPanelChanged(panelBefore, panelAfter) { }

    }

    class IdlePixelPlus {

        constructor() {
            this.version = "0.0.1";
            this.plugins = {};
            this.debug = false;
        }

        init() {
            const self = this;

            // hook into websocket messages
            const original_open_websocket = window.open_websocket;
            window.open_websocket = function() {
                original_open_websocket.apply(this, arguments);
                const original_onmessage = window.websocket.websocket.onmessage;
                window.websocket.websocket.onmessage = function(event) {
                    original_onmessage.apply(window.websocket.websocket, arguments);
                    self.onMessageReceived(event.data);
                }
            }

            // hook into Items.set, which is where var_ values are set
            const original_items_set = Items.set;
            Items.set = function(key, value) {
                let valueBefore = window["var_"+key];
                original_items_set.apply(this, arguments);
                let valueAfter = window["var_"+key];
                self.onVariableSet(key, valueBefore, valueAfter);
            }

            // hook into switch_panels, which is called when the main panel is changed. This is also used for custom panels.
            const original_switch_panels = window.switch_panels;
            window.switch_panels = function(id) {
                let panelBefore = Globals.currentPanel;
                if(panelBefore && panelBefore.startsWith("panel-")) {
                    panelBefore = panelBefore.substring("panel-".length);
                }
                self.hideCustomPanels();
                original_switch_panels.apply(this, arguments);
                let panelAfter = Globals.currentPanel;
                if(panelAfter && panelAfter.startsWith("panel-")) {
                    panelAfter = panelAfter.substring("panel-".length);
                }
                self.onPanelChanged(panelBefore, panelAfter);
            }

            console.log("IdlePixelPlus initialized");
        }

        registerPlugin(plugin) {
            if(!(plugin instanceof IdlePixelPlusPlugin)) {
                throw new TypeError("IdlePixelPlus.registerPlugin takes the following arguments: (plugin:IdlePixelPlusPlugin)");
            }
            if(plugin.id in this.plugins) {
                throw new Error(`IdlePixelPlusPlugin with id "${plugin.id}" is already registered. Make sure your plugin id is unique!`);
            }

            // TODO: easy config system
            // TODO: custom panels

            this.plugins[plugin.id] = plugin;
            console.log(`IdlePixelPlus registered plugin "${plugin.id}" (${plugin.name})`);
        }

        forEachPlugin(f) {
            if(typeof f !== "function") {
                throw new TypeError("IdlePixelPlus.forEachPlugin takes the following arguments: (f:function)");
            }
            Object.values(this.plugins).forEach(plugin => {
                try {
                    f(plugin);
                }
                catch(err) {
                    console.error(`Error occurred while executing function for plugin "${plugin.id}."`);
                    console.error(err);
                }
            });
        }

        setPanel(panel) {
            if(typeof panel !== "string") {
                throw new TypeError("IdlePixelPlus.setPanel takes the following arguments: (panel:string)");
            }
            window.switch_panels(panel);
        }

        sendMessage(message) {
            if(typeof message !== "string") {
                throw new TypeError("IdlePixelPlus.sendMessage takes the following arguments: (message:string)");
            }
            if(window.websocket && window.websocket.websocket && window.websocket.websocket.readyState==1) {
                window.websocket.websocket.send(message);
            }
        }

        hideCustomPanels() {
            this.forEachPlugin((plugin) => {
                if(plugin.opts.panel) {
                    let panels = plugin.opts.panel;
                    if(!Array.isArray(panels)) {
                        panels = [panels];
                    }
                    panels.forEach(panel => {
                        if(panel.id) {
                            const el = document.getElementById(`panel-${panel.id}`);
                            if(el) {
                                el.style.display = "none";
                            }
                        }
                    });
                }
            });
        }

        onMessageReceived(data) {
            if(this.debug) {
                console.log(`IP+ onMessageReceived: ${data}`);
            }
            if(data) {
                this.forEachPlugin((plugin) => {
                    if(typeof plugin.onMessageReceived === "function") {
                        plugin.onMessageReceived(data);
                    }
                });
                if(data.startsWith("VALID_LOGIN")) {
                    this.onLogin();
                }
                else if(data.startsWith("CHAT=")) {
                    const split = data.substring("CHAT=".length).split("~");
                    const chatData = {
                        username: split[0],
                        tag: null,
                        sigil: null,
                        level: split[3],
                        message: split[4]
                    };
                    // CHAT=anwinity~none~none~1565~test
                    // TODO: none and none, probably for tag and sigil
                }
            }
        }

        onLogin() {
            if(this.debug) {
                console.log(`IP+ onLogin`);
            }
            this.forEachPlugin((plugin) => {
                if(typeof plugin.onLogin === "function") {
                    plugin.onLogin();
                }
            });
        }

        onVariableSet(key, valueBefore, valueAfter) {
            if(this.debug) {
                console.log(`IP+ onVariableSet "${key}": "${valueBefore}" -> "${valueAfter}"`);
            }
            this.forEachPlugin((plugin) => {
                if(typeof plugin.onVariableSet === "function") {
                    plugin.onVariableSet(key, valueBefore, valueAfter);
                }
            });
        }

        onChat(data) {
            if(this.debug) {
                console.log(`IP+ onChat`, data);
            }
            this.forEachPlugin((plugin) => {
                if(typeof plugin.onChat === "function") {
                    plugin.onChat(data);
                }
            });
        }

        onPanelChanged(panelBefore, panelAfter) {
            if(this.debug) {
                console.log(`IP+ onPanelChanged "${panelBefore}" -> "${panelAfter}"`);
            }
            this.forEachPlugin((plugin) => {
                if(typeof plugin.onPanelChanged === "function") {
                    plugin.onPanelChanged(panelBefore, panelAfter);
                }
            });
        }

    }

    // Add to window and init
    window.IdlePixelPlusPlugin = IdlePixelPlusPlugin;
    window.IdlePixelPlus = new IdlePixelPlus();
    window.IdlePixelPlus.init();

})();