您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
framework for FlatMMO
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/538103/1600331/FlatmmoPlus%20-%20Framework.js
// ==UserScript== // @name FlatmmoPlus - Framework // @namespace com.blank.flatmmo // @version 0.0.1 // @description framework for FlatMMO // @author blank // @match *://flatmmo.com/play.php* // @grant none // ==/UserScript== (function () { 'use strict'; const VERSION = "0.0.1"; if(window.FlatmmoPlus) { // already loaded return; } function logFancy(s, color="#00f7ff") { console.log("%cIdlePixelPlus: %c"+s, `color: ${color}; font-weight: bold; font-size: 12pt;`, "color: black; font-weight: normal; font-size: 10pt;"); } class FlatmmoPlusPlugin { constructor(id, opts = {}) { if (typeof id !== "string") { throw new TypeError("FlatmmoPlusPlugin constructor requires (id: string, opts?: object)"); } this.id = id; this.opts = opts; this.config = {}; // placeholder for future config handling } onLogin() {} onMessageReceived(data) {} onMessageSent(data) {} onVariableSet(key, valueBefore, valueAfter) {} } class FlatmmoPlus { constructor() { console.log('[Framework] Initialising'); this.messageQueue = []; this.hookedSockets = new WeakSet(); this.plugins = {}; // NEW: store registered plugins this.init(); } registerPlugin(plugin) { if (!(plugin instanceof FlatmmoPlusPlugin)) { console.warn(`[Framework] Invalid plugin:`, plugin); return; } const id = plugin.id; if (this.plugins[id]) { console.warn(`[Framework] Plugin "${id}" already registered.`); return; } this.plugins[id] = plugin; const version = plugin.opts?.about?.version || "?"; logFancy(`registered plugin "${id}" (v${version})`); } broadcast(methodName, ...args) { for (const plugin of Object.values(this.plugins)) { const fn = plugin[methodName]; if (typeof fn === "function") { try { fn.apply(plugin, args); } catch (err) { console.error(`[Framework] Error in plugin "${plugin.id}" method "${methodName}":`, err); } } } } init() { this.overrideGlobalWebSocket(); this.waitForGameVisibility(); } overrideGlobalWebSocket() { const NativeWebSocket = window.WebSocket; const self = this; console.log('[Framework] Overriding global WebSocket constructor'); window.WebSocket = function (...args) { const ws = new NativeWebSocket(...args); setTimeout(() => self.hookSocket(ws), 1000); return ws; }; window.WebSocket.prototype = NativeWebSocket.prototype; Object.assign(window.WebSocket, NativeWebSocket); } hookSocket(ws) { if (!ws || this.hookedSockets.has(ws)) return; this.hookedSockets.add(ws); const origSend = ws.send; ws.send = (...args) => { const data = args[0]; this.onMessageSent(data); return origSend.apply(ws, args); }; const origOnMessage = ws.onmessage; ws.onmessage = (event) => { this.onMessageReceived(event.data); if (typeof origOnMessage === 'function') { origOnMessage.call(ws, event); } }; } waitForGameVisibility() { const gameDiv = document.getElementById('game'); if (!gameDiv) return console.warn('[Framework] #game not found'); const obs = new MutationObserver(() => { const visible = window.getComputedStyle(gameDiv).display !== 'none'; if (visible) { obs.disconnect(); this.onLogin(); } }); obs.observe(gameDiv, { attributes: true, attributeFilter: ['style'] }); } // Event relays to plugins onMessageReceived(data) { this.broadcast("onMessageReceived", data); } onMessageSent(data) { this.broadcast("onMessageSent", data); } onLogin() { this.broadcast("onLogin"); } } // Add to window and init window.FlatmmoPlusPlugin = FlatmmoPlusPlugin; window.FlatmmoPlus = new FlatmmoPlus(); })();