您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Definable is a modular ModMenu for Drawaria.Online
// ==UserScript== // @name Definable ModMenu // @namespace Definable // @version 0.2.5 // @description Definable is a modular ModMenu for Drawaria.Online // @homepage https://drawaria.online/profile/?uid=63196790-c7da-11ec-8266-c399f90709b7 // @author ≺ᴄᴜʙᴇ³≻ // @match https://drawaria.online/ // @match https://drawaria.online/test // @match https://drawaria.online/room/* // @icon https://i.ibb.co/8Xb1gXg/Andrew-T-Austin-brightly-lit-tesseract-hypercube.png // @grant none // @license GNU GPLv3 // @run-at document-end // ==/UserScript== (() => { if (window.location.hostname === "drawaria.online" && window.location.pathname === "/") window.location.assign("/test"); String.prototype.toFunction = function () { return new Function("(" + this + ")()"); }; String.prototype.__invokeAsFunction = function (...args) { new Function("(" + this + ")()")(); }; Function.prototype.callAsWorker = function (...args) { return new Promise((resolve, reject) => { const code = `self.onmessage = e => self.postMessage((${this.toString()}).call(null, ...e.data));`, blob = new Blob([code], { type: "text/javascript" }), worker = new Worker((window.URL ?? window.webkitURL).createObjectURL(blob)); worker.onmessage = (e) => (resolve(e.data), worker.terminate()); worker.onerror = (e) => (reject(e.message), worker.terminate()); worker.postMessage(args); }); }; const originalElementPrototypeAppend = Element.prototype.append; Element.prototype.append = function (...elements) { elements = elements.filter((appendingElement) => { if (appendingElement instanceof HTMLElement) return true; return false; }); originalElementPrototypeAppend.apply(this, elements); return this; }; const sockets = []; const originalWebSocketSend = WebSocket.prototype.send; WebSocket.prototype.send = function (message) { let socket = this; if (sockets.indexOf(socket) === -1) { sockets.push(socket); originalWebSocketSend.call(socket, "2"); } socket.addEventListener("close", function () { const pos = sockets.indexOf(socket); if (~pos) sockets.splice(pos, 1); }); try { const msgObject = JSON.parse(message.replace(/^\d+/, "")); if (msgObject[0] === "startplay") { const width = msgObject[6][2]; const height = msgObject[6][3]; const canvas = document.querySelector("#canvas"); canvas._width = width; canvas._height = height; } } catch (error) {} return originalWebSocketSend.call(socket, message); }; globalThis["sockets"] = sockets; // Function.toString().replace(/^\s*\/\/.+$/gm, "").split("\n").filter((s) => s).map((s) => s.trim()).join(""); })(); (async function ($name) { "use strict"; let canvas = document.querySelector("canvas#canvas"); const cache = { storage: await caches.open($name), /** * @param {string} url * @param {string} scriptContent */ saveScript: function (url, scriptContent) { this.storage.put(url, new Response(scriptContent, { headers: { "Content-Type": "application/javascript" } })); }, /** * @param {string} url * @param {object} json */ saveObject: function (url, json) { this.storage.put(url, new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json" } })); }, /** * @param {string} url * @returns {Promise<string>} */ loadScript: async function (url) { const response = (await this.storage.match(url)) || (await fetch(url)); return await response.text(); }, /** * @param {string} url * @returns {Promise<object>} */ loadObject: async function (url) { const response = (await this.storage.match(url)) || (await fetch(url)); return await response.json(); }, }; const UI = { /** * Returns the first element that is a descendant of node that matches selectors. * @param {string} selectors * @param {ParentNode} parentElement * @returns {Element|null} */ querySelect: (selectors, parentElement = document) => parentElement.querySelector(selectors), /** * Returns all element descendants of node that match selectors. * @param {string} selectors * @param {ParentNode} parentElement * @returns {NodeListOf<Element>} */ querySelectAll: (selectors, parentElement = document) => parentElement.querySelectorAll(selectors), /** * Create Element and assign properties to it. * @param {string} tagName * @param {object} properties * @returns {Element} */ createElement: (tagName, properties = {}) => { /** @type {Element} */ const element = Object.assign(document.createElement(tagName), properties); if (properties.title) { try { element.setAttribute("data-toggle", "tooltip"); element.setAttribute("data-html", "true"); jQuery(element).tooltip({ boundary: "window" }); } catch (error) {} } return element; }, /** * Assign attributes to element. * @param {Element} element * @param {object} attributes */ setAttributes: (element, attributes) => Object.entries(attributes).forEach(([k, v]) => element.setAttribute(k, v)), /** * Assign styles to element. * @param {Element} element * @param {object} styles */ setStyles: (element, styles) => Object.assign(element.style, styles), /** * @param {string} name * @returns {HTMLDivElement} */ createContainer: function (name = "div") { return this.createElement(name, { className: "container" }); }, /** * @returns {HTMLDivElement} */ createRow: function () { return this.createElement("div", { className: "row" }); }, /** * @param {string} name * @returns {HTMLElement} */ createIcon: function (name) { return this.createElement("i", { className: `fas fa-${name}` }); }, /** * @param {string} type * @param {object} properties * @returns {HTMLInputElement} */ createInput: function (type, properties = {}) { const input = this.createElement("input", { ...{ className: "form-control" }, ...properties, ...{ type: type } }); if (!input.id) input.id = helpers.uid(8); return input; }, /** * @param {HTMLInputElement} input * @param {object} properties * @returns {HTMLLabelElement} */ createLabelFor: function (input, properties = {}) { const label = this.createElement("label", { ...{ className: "btn btn-sm btn-outline-secondary" }, ...properties, ...{ htmlFor: input.id } }); label.appendChild(input); input.hidden = true; if (input.type === "checkbox" || input.type === "radio") { input.addEventListener("input", function () { label.classList[input.checked ? "add" : "remove"]("active"); }); } return label; }, /** * @param {string} className * @returns {HTMLElement & { show: Function, hide: Function }} */ createSpinner: function (className = "text-secondary") { const spinner = this.createElement("div", { className: [className, "spinner-border spinner-border-sm"].join(" ") }); spinner.show = function () { spinner.classList.remove("d-none"); }; spinner.hide = function () { spinner.classList.add("d-none"); }; spinner.hide(); return spinner; }, /** * @param {HTMLInputElement} input * @param {HTMLLabelElement|HTMLInputElement|HTMLButtonElement|HTMLElement} addon * @returns {HTMLDivElement} */ createGroup: function (input, addon) { const group = this.createElement("div", { className: "input-group input-group-sm" }); const groupAppend = this.createElement("div", { className: "input-group-append" }); if (!(addon instanceof HTMLInputElement || addon instanceof HTMLButtonElement)) { addon.classList.add("input-group-text"); } groupAppend.appendChild(addon); group.appendChild(input); group.appendChild(groupAppend); return group; }, /** * @param {Array<HTMLLabelElement|HTMLInputElement|HTMLButtonElement|HTMLElement>} inputs * @returns {HTMLDivElement} */ createInputGroup: function (...inputs) { const group = this.createElement("div", { className: "input-group input-group-sm" }); let previousElementSibling = inputs[0]; let appendGroup = this.createElement("div", { className: "input-group-append" }); for (let index = 0; index < inputs.length; index++) { const input = inputs[index]; if (input instanceof HTMLInputElement) { if (!(previousElementSibling instanceof HTMLInputElement)) { group.appendChild(appendGroup); appendGroup = this.createElement("div", { className: `input-group-${index > 0 ? "append" : "prepend"}` }); } input.hidden = false; group.appendChild(input); } else { input.classList.add("input-group-text"); appendGroup.appendChild(input); if (index + 1 === inputs.length) { group.appendChild(appendGroup); } } previousElementSibling = input; } return group; }, }; const DrawariaOnlineMessageTypes = { /** * @param {string} message * @returns {string} */ chatmsg: function (message) { // 42["chatmsg","a"] const data = ["chatmsg", message]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ passturn: function () { // 42["passturn"] const data = ["passturn"]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @returns {string} */ pgdrawvote: function (playerid) { // 42["pgdrawvote",2,0] const data = ["pgdrawvote", playerid, 0]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ pgswtichroom: function () { // 42["pgswtichroom"] const data = ["pgswtichroom"]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ playerafk: function () { // 42["playerafk"] const data = ["playerafk"]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ playerrated: function () { // 42["playerrated"] const data = ["playerrated"]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} gestureid * @returns {string} */ sendgesture: function (gestureid) { // 42["sendgesture",16] const data = ["sendgesture", gestureid]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ sendvote: function () { // 42["sendvote"] const data = ["sendvote"]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @returns {string} */ sendvotekick: function (playerid) { // 42["sendvotekick",93] const data = ["sendvotekick", playerid]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} wordid * @returns {string} */ wordselected: function (wordid) { // 42["wordselected",0] const data = ["sendvotekick", wordid]; return `${42}${JSON.stringify(data)}`; }, /** * @param {string} roomID * @param {string} name * @param {string} uid * @param {string} wt * @returns {string} */ startplay: function (roomID, name = undefined, uid = undefined, wt = undefined, width = 1000, height = 1000) { const data = `${420}${JSON.stringify(["startplay", name, 2, "en", roomID, null, [null, "https://drawaria.online/", width, height, [null, uid, wt], null]])}`; return data; }, clientcmd: { /** * @param {number|string} itemid * @param {boolean} isactive * @returns {string} */ activateitem: function (itemid, isactive) { const data = ["clientcmd", 12, [itemid, isactive]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @returns {string} */ buyitem: function (itemid) { const data = ["clientcmd", 11, [itemid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @param {"zindex"|"shared"} target * @param {any} value * @returns {string} */ canvasobj_changeattr: function (itemid, target, value) { const data = ["clientcmd", 234, [itemid, target, value]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ canvasobj_getobjects: function () { const data = ["clientcmd", 233]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @returns {string} */ canvasobj_remove: function (itemid) { let data = ["clientcmd", 232, [itemid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @param {number|string} positionX * @param {number|string} positionY * @param {number|string} speed * @returns {string} */ canvasobj_setposition: function (itemid, positionX, positionY, speed) { const data = ["clientcmd", 230, [itemid, 100 / positionX, 100 / positionY, { movespeed: speed }]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @param {number|string} rotation * @returns {string} */ canvasobj_setrotation: function (itemid, rotation) { const data = ["clientcmd", 231, [itemid, rotation]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {any} value * @returns {string} */ customvoting_setvote: function (value) { const data = ["clientcmd", 301, [value]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {any} value * @returns {string} */ getfpid: function (value) { const data = ["clientcmd", 901, [value]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ getinventory: function () { const data = ["clientcmd", 10, [true]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ getspawnsstate: function () { const data = ["clientcmd", 102]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} positionX * @param {number|string} positionY * @returns {string} */ moveavatar: function (positionX, positionY) { const data = ["clientcmd", 103, [1e4 * Math.floor(positionX * 0.01 * 1e4) + Math.floor(positionY * 0.01 * 1e4), false]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ setavatarprop: function () { const data = ["clientcmd", 115]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} flagid * @param {boolean} isactive * @returns {string} */ setstatusflag: function (flagid, isactive) { const data = ["clientcmd", 3, [flagid, isactive]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {number|string} tokenid * @returns {string} */ settoken: function (playerid, tokenid) { const data = ["clientcmd", 2, [playerid, tokenid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {any} value * @returns {string} */ snapchatmessage: function (playerid, value) { const data = ["clientcmd", 330, [playerid, value]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ spawnavatar: function () { const data = ["clientcmd", 101]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ startrollbackvoting: function () { const data = ["clientcmd", 320]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ trackforwardvoting: function () { const data = ["clientcmd", 321]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} trackid * @returns {string} */ votetrack: function (trackid) { const data = ["clientcmd", 1, [trackid]]; return `${42}${JSON.stringify(data)}`; }, }, clientnotify: { /** * @param {number|string} playerid * @returns {string} */ requestcanvas: function (playerid) { const data = ["clientnotify", playerid, 10001]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} base64 * @returns {string} */ respondcanvas: function (playerid, base64) { const data = ["clientnotify", playerid, 10002, [base64]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {number|string} imageid * @returns {string} */ galleryupload: function (playerid, imageid) { const data = ["clientnotify", playerid, 11, [imageid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {any} type * @returns {string} */ warning: function (playerid, type) { const data = ["clientnotify", playerid, 100, [type]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} targetname * @param {boolean} mute * @returns {string} */ mute: function (playerid, targetname, mute = false) { const data = ["clientnotify", playerid, 1, [mute, targetname]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} targetname * @param {boolean} hide * @returns {string} */ hide: function (playerid, targetname, hide = false) { const data = ["clientnotify", playerid, 3, [hide, targetname]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} reason * @param {string} targetname * @returns {string} */ report: function (playerid, reason, targetname) { const data = ["clientnotify", playerid, 2, [targetname, reason]]; return `${42}${JSON.stringify(data)}`; }, }, drawcmd: { /** * @param {number|string} playerid * @param {number|string} x1 * @param {number|string} y1 * @param {number|string} x2 * @param {number|string} y2 * @param {number|string} size * @param {number|string} color * @param {boolean} ispixel * @returns {string} */ line: function (x1, y1, x2, y2, color, size = 4, ispixel = true, playerid = 0) { const data = ["drawcmd", 0, [x1 * (1 / canvas.width), y1 * (1 / canvas.height), x2 * (1 / canvas.width), y2 * (1 / canvas.height), false, -size, color, playerid, ispixel]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {number|string} x1 * @param {number|string} y1 * @param {number|string} x2 * @param {number|string} y2 * @param {number|string} size * @param {number|string} color * @returns {string} */ erase: function (x1, y1, x2, y2, color, size, ispixel = true, playerid = 0) { const data = ["drawcmd", 1, [x1 * 0.01, y1 * 0.01, x2 * 0.01, y2 * 0.01, false, -size, color, playerid, ispixel]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} x * @param {number|string} y * @param {number|string} color * @param {number|string} tolerance * @param {number|string} r * @param {number|string} g * @param {number|string} b * @param {number|string} a * @returns {string} */ flood: function (x, y, color, tolerance, r, g, b, a) { // 42["drawcmd",2,[x, y,color,{"0":r,"1":g,"2":b,"3":a},size]] const data = ["drawcmd", 2, [x * 0.01, y * 0.01, color, { 0: r, 1: g, 2: b, 3: a }, tolerance]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @returns {string} */ undo: function (playerid) { // 42["drawcmd",3,[playerid]] const data = ["drawcmd", 3, [playerid]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ clear: function () { // 42["drawcmd",4,[]] const data = ["drawcmd", 4, []]; return `${42}${JSON.stringify(data)}`; }, }, }; const helpers = { /** * @param {string} message * @param {string} styles */ log: (message, styles = "color:#5090C1", application = undefined) => console.log("%c" + [`[${application ?? $name}]`, message].join(" "), styles), /** * Generate radnow UID * @param {number} size * @returns {string} */ uid: (size = 8) => { const MASK = 0x3d; const LETTERS = "abcdefghijklmnopqrstuvwxyz"; const NUMBERS = "1234567890"; const SPECIALS = "-_"; const charset = `${NUMBERS}${LETTERS}${LETTERS.toUpperCase()}${SPECIALS}`.split(""); const bytes = new Uint8Array(size); crypto.getRandomValues(bytes); return bytes.reduce((acc, byte) => `${acc}${charset[byte & MASK]}`, ""); }, /** * @param {number[]} byteArray * @returns {string} */ toHexString: (byteArray) => { return byteArray.map((byte) => byte.toString(16).padStart(2, "0")).join(""); }, /** * @param {string} key * @param {string} value */ setCookie: (key, value) => { if (window.Cookie) Cookies.set(key, value); document.cookie = `${key}=${value}; Secure; Path=/; SameSite=None; Partitioned;`; }, /** * @returns {Array<*>&{addEventListener:(event:"delete"|"set",handler:(property:string,value:*)=>void))=>}} */ makeObservableArray: () => { if (!("Proxy" in window)) { console.warn("Your browser doesn't support Proxies."); return []; } const onDeleteCall = []; const onSetCall = []; // a proxy for our array const proxy = new Proxy([], { deleteProperty: function (target, property) { onDeleteCall.forEach((callback) => callback(property, target[property])); delete target[property]; return true; }, set: function (target, property, value, receiver) { target[property] = value; onSetCall.forEach((callback) => callback(property, target[property])); return true; }, }); proxy.addEventListener = (event, handler) => { switch (event) { case "set": onSetCall.push(handler); return; case "delete": onDeleteCall.push(handler); return; default: break; } }; return proxy; }, /** * @param {string} message * @returns {Array<any>|object} */ tryParseJSON: (message) => { try { return JSON.parse(message); } catch (error) { return []; } }, }; const clearScripts = (remove = true) => { try { let array = document.querySelectorAll('script[src]:not([data-codemaid="ignore"])'); array.forEach((script) => { if (script.src != "") document.head.appendChild(script); }); } catch (error) { console.error(error); } try { let unifiedScript = UI.createElement("script"); let scripts = document.querySelectorAll('script:not([src]):not([data-codemaid="ignore"])'); let unifiedScriptContent = ""; scripts.forEach((script) => { let content = script.textContent; //.replaceAll(/\s/g, ''); unifiedScriptContent += `try{${content}}catch(e){console.warn(e);}`; script.remove(); }); unifiedScript.textContent = unifiedScriptContent; if (!remove) document.head.appendChild(unifiedScript); } catch (error) { console.error(error); } }; const clearStyles = (remove = false) => { try { let unifiedStyles = UI.createElement("style"); unifiedStyles.textContet = ""; let styles = document.querySelectorAll('style:not([data-codemaid="ignore"])'); styles.forEach((style) => { unifiedStyles.textContent += style.textContent; style.remove(); }); if (!remove) document.head.appendChild(unifiedStyles); } catch (error) { console.error(error); } }; const clearEmbeds = () => { try { let array = document.querySelectorAll("iframe"); array.forEach((iframe) => { iframe.remove(); }); } catch (error) { console.error(error); } }; const clearAll = () => { clearEmbeds(); clearScripts(); clearStyles(); UI.querySelectAll(".extimages").forEach((e) => e.remove()); UI.querySelectAll(".promlinks").forEach((e) => e.remove()); }; class Player { /** @type {Array<Player>} */ static instances = []; static get noConflict() { return Player.instances[0] ?? new Player(helpers.uid(12)); } /** * @param {string|undefined} inviteLink * @returns {URL} */ static getSocketServerURL(inviteLink) { if (typeof inviteLink === "undefined") return `wss://sv3.drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`; const roomID = this.getRoomID(inviteLink); const [_voidable, serverPrefix] = roomID.split("."); return new URL(`wss://${typeof serverPrefix === "undefined" ? "" : "sv".concat(serverPrefix, ".")}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`); } /** * @param {string|undefined} inviteLink * @returns {string} */ static getRoomID(inviteLink) { const inviteURL = new URL(inviteLink); return inviteURL.pathname.slice(6); } /** * @param {MessageEvent} messageEvent * @returns {[string, string, Array<any>|object]} */ static parseMessageEventData(messageEvent) { const rawData = String(messageEvent.data); const messageType = (rawData.match(/^\d+/i) ?? [""])[0]; const messageData = messageType.length === rawData.length ? [] : helpers.tryParseJSON(rawData.slice(messageType.length)); return [messageType, Array.isArray(messageData) ? messageData.shift() : "", messageData]; } static parseMessage = DrawariaOnlineMessageTypes; /** @type {string} */ name; /** @type {string} */ uid; /** @type {string} */ wt; /** @type {string} */ roomID; /** @type {WebSocket} */ socket; /** @type {Map<string, Function[]>} */ events; /** * @param {string} name */ constructor(name = undefined) { this.name = name; this.uid = "_"; this.wt = undefined; this.roomID = undefined; this.events = new Map(); Player.instances.push(this); } /** * @param {string} inviteLink */ connect = (inviteLink) => { if (this.isConnected) return; this.#createNewConnection(inviteLink); }; disconnect = () => { this.send("41"); if (this.isConnected) this.socket.close(); }; reconnect = () => { if (!this.isConnected) { this.connect(`https://drawaria.online/room/${this.roomID}`); return; } this.send("41"); this.send("40"); }; /** * @param {string} inviteLink */ enterRoom = (inviteLink = undefined) => { this.roomID = Player.getRoomID(inviteLink ?? document.querySelector("#invurl").value); this.reconnect(); }; nextRoom = () => { this.send(Player.parseMessage.pgswtichroom()); }; leaveRoom = () => { this.send("41"); }; /** * @param {string} payload */ send = (payload) => { if (this.isConnected) this.socket.send(payload); else debug(`send failed! Connection is closed`); }; /** * @returns {boolean} */ get isConnected() { return typeof this.socket !== "undefined" && this.socket instanceof WebSocket && (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING); } #sendHeartbeat = () => { if (this.isConnected) this.socket.send(2); }; /** * @param {string} inviteLink */ #createNewConnection = (inviteLink) => { this.socket = new WebSocket(Player.getSocketServerURL(inviteLink)); this.roomID = Player.getRoomID(inviteLink); this.socket.addEventListener("open", this.#startHeartbeat); this.socket.addEventListener("message", this.#handleMessage); }; #startHeartbeat = () => { this.heartbeatInterval = setInterval(this.#sendHeartbeat, 25000); }; #handleMessage = (rawMessage) => { const [eventType, eventName, eventData] = Player.parseMessageEventData(rawMessage); switch (eventType) { case "40": this.send(Player.parseMessage.startplay(this.roomID, this.name, this.uid, this.wt)); break; case "430": break; case "42": this.__invokeEvent(eventName, eventData); break; default: } }; /** * @param {DrawariaOnlineEvents} event * @param {Function} callback */ addEventListener = (event, callback, id = undefined) => { if (!this.hasEventListener(event)) { this.events.set(event, []); } callback.id = id ?? this.addEventListener.caller.name ?? helpers.uid(8); try { this.events.get(event).push(callback); } catch (error) { debug(`addEventListener returned error \"${error}\"`, "color:firebrick"); } }; /** * @param {DrawariaOnlineEvents} event * @param {*} data */ __invokeEvent = (event, data) => { if (this.hasEventListener(event)) { const listeners = this.events.get(event); listeners.forEach((listener) => listener(data)); } }; /** * @param {DrawariaOnlineEvents} name * @returns {boolean} */ hasEventListener = (name) => { return this.events.has(name); }; } class DefinableCore { static UI = UI; static Player = Player; static helper = helpers; static runtime = []; constructor(moduleName, moduleIcon = "code") { this.name = moduleName; this.__initializeHead(moduleIcon); this.__initializeBody(); } __initializeHead(moduleIcon) { const input = this.UI.createInput("checkbox"); this.label = this.UI.createLabelFor(input, { title: this.name }); const icon = this.UI.createIcon(moduleIcon); this.label.appendChild(icon); } __initializeBody() { const submoduleSelectionContainer = this.UI.createElement("nav", { className: "row" }); const wrapper = this.UI.createElement("div"); this.wrapper = wrapper; this.__contaier = this.UI.createElement("div"); this.__contaier.appendChild(this.UI.createElement("b", { textContent: this.name })); // this.wrapper.appendChild(submoduleSelectionContainer); this.__contaier.appendChild(submoduleSelectionContainer); this.wrapper.appendChild(this.__contaier); const input = this.UI.querySelect("&>input", this.label); input.addEventListener("input", function () { wrapper.classList[input.checked ? "remove" : "add"]("d-none"); }); wrapper.classList.add("d-none"); } createRow() { const row = this.UI.createRow(); this.__contaier.appendChild(row); return row; } /** * @param {DefinableCore} submodule */ registerModule(submodule) { // const submoduleSelectionContainer = this.UI.querySelect("&>nav", this.wrapper); const submoduleSelectionContainer = this.UI.querySelect("&>nav", this.__contaier); submoduleSelectionContainer.appendChild(submodule.label); this.wrapper.appendChild(submodule.wrapper); DefinableCore.runtime.push(submodule); } get UI() { return DefinableCore.UI; } get Player() { return DefinableCore.Player; } } window.addEventListener("definable:core:init", function () { const ui = DefinableCore.UI; const definable = new DefinableCore("Definable", "code"); const container = UI.createElement("section", { style: "position: relative" }); const chatbox = ui.querySelect("#chatbox_messages"); /** @type {HTMLElement} */ const devider = chatbox.previousElementSibling; devider.before(container); container.appendChild(definable.wrapper); definable.wrapper.style.position = "absolute"; container.before(devider.cloneNode(false)); setTimeout(() => { window.dispatchEvent(new CustomEvent("definable:init", { detail: { main: definable, core: DefinableCore } })); definable.wrapper.classList.remove("d-none"); definable.wrapper.classList.add("container"); definable.wrapper.id = "definable"; definable.wrapper.ModMenu = definable; }, 500); }); setTimeout(() => { window.dispatchEvent(new CustomEvent("definable:core:init")); clearEmbeds(); clearScripts(); clearStyles(); document.head.appendChild( UI.createElement("style", { id: "definableStyles", textContent: [ "#definable { position: relative; isolation: isolate; }", "#definable::before { position: absolute; content: ''; inset: 0; background-color: var(--light); z-index: -1; }", "#definable .row { gap: 0.125rem; margin-bottom: 0.125rem; }", "#definable label { margin: 0; }", "#definable .row>label { min-width: 2rem; }", ].join("\n"), }) ); jQuery.getScript("/3rd/lib/moveable.min.js?" + window.VERID, function (data, textStatus, jqxhr) { globalThis["transformable"] = initTransformable(Moveable); }); jQuery.getScript("/pageres/stencils.js?" + window.VERID); // console.clear(); }, 500); function initTransformable(TransformationController) { const transformable = new TransformationController(document.body, { target: null, container: document.body, draggable: true, scalable: true, rotatable: true, snappable: true, origin: true, keepRatio: true, }); transformable.snapGridWidth = 64; transformable.snapGridHeight = 64; /* draggable */ transformable.on("drag", ({ target, transform, left, top, right, bottom, beforeDelta, beforeDist, delta, dist, clientX, clientY }) => { target.style.left = `${left}px`; target.style.top = `${top}px`; }); /* scalable */ transformable.on("scale", ({ target, scale, dist, delta, transform, clientX, clientY }) => { target.style.transform = transform; }); /* rotatable */ transformable.on("rotate", ({ target, beforeDelta, delta, dist, transform, clientX, clientY }) => { target.style.transform = transform; }); /* Handle Transformable target selection */ window.addEventListener("mousedown", function (event) { /** @type {HTMLElement} */ const target = event.target; if (!target) return; if (target.classList.contains("moveable-control-box") || this.document.querySelector(".moveable-control-box").contains(target)) return; if (target.classList.contains("transformable")) { transformable.target = target; return; } transformable.target = null; }); /* Handle ZIndex changes via keybinds */ window.addEventListener("keydown", function (event) { /** @type {HTMLElement|HTMLImageElement} */ const target = transformable.target; if (!target) return; // console.log(event.key); const zIndex = Number(target.style.zIndex ?? "0"); switch (event.key) { case "+": target.style.zIndex = zIndex + 1; event.preventDefault(); event.stopPropagation(); break; case "-": target.style.zIndex = zIndex - 1; event.preventDefault(); event.stopPropagation(); break; case "Delete": transformable.target = null; target.remove(); break; case "ArrowUp": target.style.top = parseFloat(target.style.top) - 1 + "px"; transformable.updateRect(); break; case "ArrowDown": target.style.top = parseFloat(target.style.top) + 1 + "px"; transformable.updateRect(); break; case "ArrowLeft": target.style.left = parseFloat(target.style.left) - 1 + "px"; transformable.updateRect(); break; case "ArrowRight": target.style.left = parseFloat(target.style.left) + 1 + "px"; transformable.updateRect(); break; default: break; } if (event.ctrlKey && event.key == "d") { event.preventDefault(); event.stopPropagation(); const duplicate = new Image(); duplicate.src = target.src; duplicate.classList.add("transformable"); duplicate.style.top = parseFloat(target.style.top) + 20 + "px"; duplicate.style.left = parseFloat(target.style.left) + 20 + "px"; transformable.target = duplicate; transformable.updateRect(); document.body.appendChild(duplicate); } }); return transformable; } function launchScriptManager() { const ui = DefinableCore.UI; const container = ui.createContainer(); { const row = ui.createRow(); const scriptSourceLinkInput = ui.createInput("text", { className: "form-control" }); const requestSourceInput = ui.createInput("button"); const requestSourceLabel = ui.createLabelFor(requestSourceInput); const group = ui.createGroup(scriptSourceLinkInput, requestSourceLabel); const spinnerIcon = ui.createSpinner(""); const defaultIcon = ui.createIcon("external-link-alt"); requestSourceLabel.appendChild(defaultIcon); requestSourceLabel.appendChild(spinnerIcon); requestSourceInput.addEventListener("click", function () { defaultIcon.classList.add("d-none"); spinnerIcon.show(); if (!scriptSourceLinkInput.value.startsWith("http")) { helpers.log("Not a valid Link: ".concat(scriptSourceLinkInput.value), "color: firebrick;"); spinnerIcon.hide(); defaultIcon.classList.remove("d-none"); return; } const requestSourceLink = new URL(scriptSourceLinkInput.value); helpers.log("Requesting Module: ".concat(requestSourceLink), "color: rebeccapurple;"); fetch(requestSourceLink).then(async (response) => { const copy = response.clone(); const content = await copy.text(); if (copy.status === 200 && content) { cache.saveScript(requestSourceLink, content); helpers.log("Module installed!", "color: forestgreen;"); spinnerIcon.hide(); defaultIcon.classList.remove("d-none"); scriptSourceLinkInput.value = ""; } }); }); row.appendChild(group); container.appendChild(row); } DefinableCore.UI.querySelect("#login-leftcol").appendChild(container); } })("definable");
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址