Cube Engine

Enhance your Experience

  1. // ==UserScript==
  2. // @name Cube Engine
  3. // @version 5.0.2
  4. // @description Enhance your Experience
  5. // @namespace drawaria.modded.fullspec
  6. // @homepage https://drawaria.online/profile/?uid=63196790-c7da-11ec-8266-c399f90709b7
  7. // @author ≺ᴄᴜʙᴇ³≻
  8. // @match https://drawaria.online/
  9. // @match https://drawaria.online/test
  10. // @match https://drawaria.online/room/*
  11. // @icon https://drawaria.online/avatar/cache/e53693c0-18b1-11ec-b633-b7649fa52d3f.jpg
  12. // @grant none
  13. // @license GNU GPLv3
  14. // @run-at document-end
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. (function CodeMaid(callback) {
  19. class TypeChecker {
  20. constructor() {}
  21. isArray(value) {
  22. return this.isA("Array", value);
  23. }
  24. isObject(value) {
  25. return !this.isUndefined(value) && value !== null && this.isA("Object", value);
  26. }
  27. isString(value) {
  28. return this.isA("String", value);
  29. }
  30. isNumber(value) {
  31. return this.isA("Number", value);
  32. }
  33. isFunction(value) {
  34. return this.isA("Function", value);
  35. }
  36. isAsyncFunction(value) {
  37. return this.isA("AsyncFunction", value);
  38. }
  39. isGeneratorFunction(value) {
  40. return this.isA("GeneratorFunction", value);
  41. }
  42. isTypedArray(value) {
  43. return (
  44. this.isA("Float32Array", value) ||
  45. this.isA("Float64Array", value) ||
  46. this.isA("Int16Array", value) ||
  47. this.isA("Int32Array", value) ||
  48. this.isA("Int8Array", value) ||
  49. this.isA("Uint16Array", value) ||
  50. this.isA("Uint32Array", value) ||
  51. this.isA("Uint8Array", value) ||
  52. this.isA("Uint8ClampedArray", value)
  53. );
  54. }
  55. isA(typeName, value) {
  56. return this.getType(value) === "[object " + typeName + "]";
  57. }
  58. isError(value) {
  59. if (!value) {
  60. return false;
  61. }
  62.  
  63. if (value instanceof Error) {
  64. return true;
  65. }
  66.  
  67. return typeof value.stack === "string" && typeof value.message === "string";
  68. }
  69. isUndefined(obj) {
  70. return obj === void 0;
  71. }
  72. getType(value) {
  73. return Object.prototype.toString.apply(value);
  74. }
  75. }
  76.  
  77. class DOMCreate {
  78. #validate;
  79. constructor() {
  80. this.#validate = new TypeChecker();
  81. }
  82. exportNodeTree(node = document.createElement("div")) {
  83. let referenceTolocalThis = this;
  84.  
  85. let json = {
  86. nodeName: node.nodeName,
  87. attributes: {},
  88. children: [],
  89. };
  90.  
  91. Array.from(node.attributes).forEach(function (attribute) {
  92. json.attributes[attribute.name] = attribute.value;
  93. });
  94.  
  95. if (node.children.length <= 0) {
  96. json.children.push(node.textContent.replaceAll("\t", ""));
  97. return json;
  98. }
  99.  
  100. Array.from(node.children).forEach(function (childNode) {
  101. json.children.push(referenceTolocalThis.exportNodeTree(childNode));
  102. });
  103.  
  104. return json;
  105. }
  106.  
  107. importNodeTree(json = { nodeName: "", attributes: {}, children: [] }) {
  108. let referenceTolocalThis = this;
  109.  
  110. if (referenceTolocalThis.#validate.isString(json)) {
  111. return this.TextNode(json);
  112. }
  113.  
  114. let node = this.Tree(json.nodeName, json.attributes);
  115.  
  116. json.children.forEach(function (child) {
  117. node.appendChild(referenceTolocalThis.importNodeTree(child));
  118. });
  119.  
  120. return node;
  121. }
  122.  
  123. Element() {
  124. return document.createElement.apply(document, arguments);
  125. }
  126. TextNode() {
  127. return document.createTextNode.apply(document, arguments);
  128. }
  129. Tree(type, attrs, childrenArrayOrVarArgs) {
  130. const el = this.Element(type);
  131. let children;
  132. if (this.#validate.isArray(childrenArrayOrVarArgs)) {
  133. children = childrenArrayOrVarArgs;
  134. } else {
  135. children = [];
  136.  
  137. for (let i = 2; i < arguments.length; i++) {
  138. children.push(arguments[i]);
  139. }
  140. }
  141.  
  142. for (let i = 0; i < children.length; i++) {
  143. const child = children[i];
  144.  
  145. if (typeof child === "string") {
  146. el.appendChild(this.TextNode(child));
  147. } else {
  148. if (child) {
  149. el.appendChild(child);
  150. }
  151. }
  152. }
  153. for (const attr in attrs) {
  154. if (attr == "className") {
  155. el[attr] = attrs[attr];
  156. } else {
  157. el.setAttribute(attr, attrs[attr]);
  158. }
  159. }
  160.  
  161. el.appendAll = function (...nodes) {
  162. nodes.forEach((node) => {
  163. el.appendChild(node);
  164. });
  165. };
  166.  
  167. return el;
  168. }
  169. }
  170.  
  171. class CookieManager {
  172. constructor() {}
  173. set(name, value = "") {
  174. document.cookie =
  175. name + "=" + value + "; expires=" + new Date("01/01/2024").toUTCString().replace("GMT", "UTC") + "; path=/";
  176. }
  177. get(name) {
  178. var nameEQ = name + "=";
  179. var ca = document.cookie.split(";");
  180. for (var i = 0; i < ca.length; i++) {
  181. var c = ca[i];
  182. while (c.charAt(0) == " ") c = c.substring(1, c.length);
  183. if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
  184. }
  185. return null;
  186. }
  187. clear(name) {
  188. document.cookie = name + "=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;";
  189. }
  190. }
  191.  
  192. class DocumentCleaner {
  193. document;
  194. constructor() {
  195. this.document = new DOMCreate();
  196. }
  197. scripts(remove = true) {
  198. try {
  199. let array = document.querySelectorAll('script[src]:not([data-codemaid="ignore"])');
  200. array.forEach((script) => {
  201. if (script.src != "") document.head.appendChild(script);
  202. });
  203. } catch (error) {
  204. console.error(error);
  205. }
  206.  
  207. try {
  208. let unifiedScript = this.document.Tree("script");
  209.  
  210. let scripts = document.querySelectorAll('script:not([src]):not([data-codemaid="ignore"])');
  211. let unifiedScriptContent = "";
  212. scripts.forEach((script) => {
  213. let content = script.textContent; //.replaceAll(/\s/g, '');
  214.  
  215. unifiedScriptContent += `try{${content}}catch(e){console.warn(e);}`;
  216. script.remove();
  217. });
  218.  
  219. unifiedScript.textContent = unifiedScriptContent;
  220.  
  221. if (!remove) document.head.appendChild(unifiedScript);
  222. } catch (error) {
  223. console.error(error);
  224. }
  225. }
  226. styles(remove = false) {
  227. try {
  228. let unifiedStyles = this.document.Tree("style");
  229. unifiedStyles.textContet = "";
  230.  
  231. let styles = document.querySelectorAll('style:not([data-codemaid="ignore"])');
  232. styles.forEach((style) => {
  233. unifiedStyles.textContent += style.textContent;
  234. style.remove();
  235. });
  236. if (!remove) document.head.appendChild(unifiedStyles);
  237. } catch (error) {
  238. console.error(error);
  239. }
  240. }
  241. embeds() {
  242. try {
  243. let array = document.querySelectorAll("iframe");
  244. array.forEach((iframe) => {
  245. iframe.remove();
  246. });
  247. } catch (error) {
  248. console.error(error);
  249. }
  250. }
  251. }
  252.  
  253. class CustomGenerator {
  254. constructor() {}
  255. uuidv4() {
  256. return crypto.randomUUID();
  257. }
  258. }
  259.  
  260. globalThis.typecheck = new TypeChecker();
  261. globalThis.cookies = new CookieManager();
  262. globalThis.domMake = new DOMCreate();
  263. globalThis.domClear = new DocumentCleaner();
  264. globalThis.generate = new CustomGenerator();
  265.  
  266. if (window.location.pathname === "/") window.location.assign("/test");
  267. })();
  268.  
  269. (function CubicEngine() {
  270. domMake.Button = function (content) {
  271. let btn = domMake.Tree("button", { class: "btn btn-outline-secondary" });
  272. btn.innerHTML = content;
  273. return btn;
  274. };
  275. domMake.Row = function () {
  276. return domMake.Tree("div", { class: "_row" });
  277. };
  278. domMake.IconList = function () {
  279. return domMake.Tree("div", { class: "icon-list" });
  280. };
  281.  
  282. const sockets = [];
  283. const originalSend = WebSocket.prototype.send;
  284. WebSocket.prototype.send = function (...args) {
  285. let socket = this;
  286. if (sockets.indexOf(socket) === -1) {
  287. sockets.push(socket);
  288. }
  289. socket.addEventListener("close", function () {
  290. const pos = sockets.indexOf(socket);
  291. if (~pos) sockets.splice(pos, 1);
  292. });
  293. return originalSend.call(socket, ...args);
  294. };
  295.  
  296. const identifier = "🧊";
  297.  
  298. class Stylizer {
  299. constructor() {
  300. this.element = domMake.Tree("style", { "data-codemaid": "ignore" }, []);
  301. document.head.appendChild(this.element);
  302. this.initialize();
  303. }
  304.  
  305. initialize() {
  306. this.addRules([
  307. `body * {margin: 0; padding: 0; box-sizing: border-box; line-height: normal;}`,
  308. `#${identifier} {--CE-bg_color: var(--light); --CE-color: var(--dark); line-height: 2rem; font-size: 1rem;}`,
  309. `#${identifier}>details {position:relative; overflow:visible; z-index: 999; background-color: var(--CE-bg_color); border: var(--CE-color) 1px solid; border-radius: .25rem;}`,
  310. `#${identifier} details>summary::marker {content:"📘";}`,
  311. `#${identifier} details[open]>summary::marker {content:"📖";}`,
  312. `#${identifier} details details {margin: 1px 0; border-top: var(--CE-color) 1px solid;}`,
  313. `#${identifier} input.toggle[name][hidden]:not(:checked) + * {display: none !important;}`,
  314. `#${identifier} header>.icon {margin: 1px;}`,
  315. `#${identifier} header>.icon.active {color: var(--success);}`,
  316. `#${identifier} header>.icon:not(.active) {color:var(--danger); opacity:.6;}`,
  317. `#${identifier} header:not(:has([title='Unselect'] + *)) > [title='Unselect'] {display:none;}`,
  318. `#${identifier} .btn {padding: 0;}`,
  319. `#${identifier} .icon-list {display: flex; flex-flow: wrap;}`,
  320. `#${identifier} .nowrap {overflow-x: scroll; padding-bottom: 12px; flex-flow: nowrap;}`,
  321. `#${identifier} .icon {display: flex; flex: 0 0 auto; max-width: 1.6rem; min-width: 1.6rem; height: 1.6rem; border-radius: .25rem; border: 1px solid var(--CE-color); aspect-ratio: 1/1;}`,
  322. `#${identifier} .icon > * {margin: auto; text-align: center; max-height: 100%; max-width: 100%;}`,
  323. `#${identifier} .itext {text-align: center; -webkit-appearance: none; -moz-appearance: textfield;}`,
  324. `#${identifier} ._row {display: flex; width: 100%;}`,
  325. `#${identifier} ._row > * {width: 100%;}`,
  326. `hr {margin: 5px 0;}`,
  327. `.playerlist-row::after {content: attr(data-playerid); position: relative; float: right; top: -20px;}`,
  328. `[hidden] {display: none !important;}`,
  329. `.noselect {-webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none;}`,
  330. ]);
  331. }
  332.  
  333. addRules(rules = []) {
  334. let reference = this;
  335. rules.forEach(function (rule) {
  336. reference.addRule(rule);
  337. });
  338. }
  339. addRule(rule) {
  340. let TextNode = domMake.TextNode(rule);
  341. this.element.appendChild(TextNode);
  342. }
  343. }
  344.  
  345. class ModBase {
  346. static globalListOfExtensions = [];
  347. static localListOfExtensions = [];
  348. static Styles = new Stylizer();
  349.  
  350. static register = function (extension) {
  351. extension.localListOfExtensions = [];
  352. ModBase.globalListOfExtensions.push(extension);
  353. return ModBase;
  354. };
  355. static bind = function (extension, target) {
  356. let parent;
  357. if (typecheck.isFunction(target)) parent = target;
  358. else if (typecheck.isString(target))
  359. parent = ModBase.globalListOfExtensions.find((entry) => entry.name === target);
  360. else if (typecheck.isObject(target)) parent = target.constructor;
  361. else {
  362. console.log(typecheck.getType(target));
  363. }
  364. if (!parent) return new Error(`${parent}`);
  365.  
  366. parent.localListOfExtensions.push(extension);
  367. parent.autostart = true;
  368.  
  369. return parent;
  370. };
  371. static findGlobal = function (extensionName) {
  372. return ModBase.globalListOfExtensions.find((entry) => entry.name === extensionName);
  373. };
  374.  
  375. #id;
  376. #name;
  377. #icon;
  378.  
  379. htmlElements;
  380. children;
  381. parent;
  382.  
  383. constructor(name, icon) {
  384. this.#id = generate.uuidv4();
  385. this.#name = this.constructor.name;
  386. this.#icon = "📦";
  387. this.children = [];
  388. this.htmlElements = {};
  389.  
  390. this.#onStartup();
  391.  
  392. this.setName(name || this.#name);
  393. this.setIcon(icon || this.#icon);
  394. }
  395.  
  396. #onStartup() {
  397. this.#loadInterface();
  398.  
  399. if (this.constructor.autostart)
  400. this.constructor.localListOfExtensions.forEach((extension) => {
  401. this.loadExtension(extension);
  402. });
  403. }
  404.  
  405. #loadInterface() {
  406. this.htmlElements.details = domMake.Tree("details", {
  407. class: "noselect",
  408. open: true,
  409. "data-reference": this.constructor.name,
  410. });
  411. this.htmlElements.summary = domMake.Tree("summary");
  412. this.htmlElements.header = domMake.Tree("header", { class: "icon-list" });
  413. this.htmlElements.section = domMake.Tree("section");
  414. this.htmlElements.children = domMake.Tree("section");
  415.  
  416. this.htmlElements.details.appendChild(this.htmlElements.summary);
  417. this.htmlElements.details.appendChild(this.htmlElements.header);
  418. this.htmlElements.details.appendChild(this.htmlElements.section);
  419. this.htmlElements.details.appendChild(this.htmlElements.children);
  420.  
  421. this.htmlElements.input = domMake.Tree(
  422. "input",
  423. { type: "radio", id: this.#id, name: "QBit", class: "toggle", hidden: true, title: this.#name },
  424. [this.#name]
  425. );
  426. this.htmlElements.label = domMake.Tree("label", { for: this.#id, class: "icon" });
  427.  
  428. {
  429. const input = this.htmlElements.input;
  430. const label = this.htmlElements.label;
  431.  
  432. input.addEventListener("change", (event) => {
  433. this.parent?.children.forEach((child) => {
  434. child.htmlElements.label.classList.remove("active");
  435. });
  436.  
  437. label.classList[input.checked ? "add" : "remove"]("active");
  438. });
  439.  
  440. label.classList[input.checked ? "add" : "remove"]("active");
  441. }
  442. {
  443. const resetImageSelectionLabel = domMake.Tree("div", { class: "icon", title: "Unselect" }, [
  444. domMake.Tree("i", { class: "fas fa-chevron-left" }),
  445. ]);
  446. resetImageSelectionLabel.addEventListener("click", () => {
  447. this.children.forEach((child) => {
  448. child.htmlElements.label.classList.remove("active");
  449. child.htmlElements.input.checked = !1;
  450. });
  451. });
  452. this.htmlElements.header.appendChild(resetImageSelectionLabel);
  453. }
  454. }
  455.  
  456. loadExtension(extension, referenceHandler) {
  457. let activeExtension = new extension();
  458. activeExtension.parent = this;
  459.  
  460. activeExtension.htmlElements.input.name = this.getName();
  461.  
  462. if (referenceHandler) referenceHandler(activeExtension);
  463. else this.children.push(activeExtension);
  464.  
  465. if (!extension.siblings) extension.siblings = [];
  466. extension.siblings.push(activeExtension);
  467.  
  468. if (extension.isFavorite) {
  469. activeExtension.htmlElements.input.click();
  470. if (activeExtension.enable) activeExtension.enable();
  471. }
  472.  
  473. this.htmlElements.header.appendChild(activeExtension.htmlElements.label);
  474. this.htmlElements.children.appendChild(activeExtension.htmlElements.input);
  475. this.htmlElements.children.appendChild(activeExtension.htmlElements.details);
  476.  
  477. return activeExtension;
  478. }
  479.  
  480. notify(level, message) {
  481. if (typeof message != "string") {
  482. try {
  483. message = JSON.stringify(message);
  484. } catch (error) {
  485. throw error;
  486. }
  487. }
  488.  
  489. let color = "";
  490. if ([5, "error"].includes(level)) {
  491. color = "#dc3545";
  492. } else if ([4, "warning"].includes(level)) {
  493. color = "#ffc107";
  494. } else if ([3, "info"].includes(level)) {
  495. color = "#17a2b8";
  496. } else if ([2, "success"].includes(level)) {
  497. color = "#28a745";
  498. } else if ([1, "log"].includes(level)) {
  499. color = "#6c757d";
  500. } else if ([0, "debug"].includes(level)) {
  501. color = "purple";
  502. }
  503.  
  504. console.log(`%c${this.#name}: ${message}`, `color: ${color}`);
  505. let chatmessage = domMake.Tree(
  506. "div",
  507. { class: `chatmessage systemchatmessage5`, "data-ts": Date.now(), style: `color: ${color}` },
  508. [`${this.#name}: ${message}`]
  509. );
  510.  
  511. let loggingContainer = document.getElementById("chatbox_messages");
  512. if (!loggingContainer) loggingContainer = document.body;
  513. loggingContainer.appendChild(chatmessage);
  514. }
  515.  
  516. findGlobal(extensionName) {
  517. return this.referenceToBase.findGlobal(extensionName);
  518. }
  519.  
  520. findLocal(extensionName) {
  521. return this.children.filter((child) => child.constructor.name === extensionName);
  522. }
  523.  
  524. setName(name) {
  525. if (!name) return;
  526.  
  527. this.#name = name;
  528. this.htmlElements.label.title = name;
  529.  
  530. this.htmlElements.summary.childNodes.forEach((child) => child.remove());
  531.  
  532. if (typecheck.isString(name)) {
  533. if (name.startsWith("<")) return (this.htmlElements.summary.innerHTML = name);
  534. name = domMake.TextNode(name);
  535. }
  536.  
  537. this.htmlElements.summary.appendChild(name);
  538. }
  539.  
  540. getName() {
  541. return this.#name;
  542. }
  543.  
  544. setIcon(icon) {
  545. if (!icon) return;
  546.  
  547. this.#icon = icon;
  548.  
  549. this.htmlElements.label.childNodes.forEach((child) => child.remove());
  550.  
  551. if (typecheck.isString(icon)) {
  552. if (icon.startsWith("<")) return (this.htmlElements.label.innerHTML = icon);
  553. icon = domMake.TextNode(icon);
  554. }
  555.  
  556. this.htmlElements.label.appendChild(icon);
  557. }
  558.  
  559. getIcon() {
  560. return this.#icon;
  561. }
  562.  
  563. get referenceToBase() {
  564. return this.constructor.dummy1;
  565. }
  566. get referenceToMaster() {
  567. return this.constructor.dummy2;
  568. }
  569.  
  570. _EXP_destroy(youSure = false) {
  571. if (!youSure) return;
  572.  
  573. this.children.forEach((child) => {
  574. child._EXP_destroy(youSure);
  575. delete [child];
  576. });
  577. this.children = null;
  578.  
  579. let pos = this.parent.children.indexOf(this);
  580. if (~pos) {
  581. this.parent.children.splice(pos, 1);
  582. }
  583.  
  584. this.htmlElements.children.remove();
  585. this.htmlElements.section.remove();
  586. this.htmlElements.header.remove();
  587. this.htmlElements.summary.remove();
  588. this.htmlElements.details.remove();
  589. this.htmlElements.input.remove();
  590. this.htmlElements.label.remove();
  591.  
  592. this.htmlElements = null;
  593.  
  594. let pos2 = this.constructor.siblings.indexOf(this);
  595. if (~pos2) {
  596. this.constructor.siblings.splice(pos2, 1);
  597. }
  598. }
  599. }
  600.  
  601. class CubeEngine extends ModBase {
  602. static dummy1 = ModBase.register(this);
  603.  
  604. constructor() {
  605. super("CubeEngine");
  606. }
  607. }
  608.  
  609. class Await {
  610. static dummy1 = ModBase.register(this);
  611.  
  612. #interval;
  613. #handler;
  614. #callback;
  615. constructor(callback, interval) {
  616. this.#interval = interval;
  617. this.#callback = callback;
  618. }
  619.  
  620. call() {
  621. const localThis = this;
  622. clearTimeout(this.#handler);
  623.  
  624. this.#handler = setTimeout(function () {
  625. localThis.#callback();
  626. }, this.#interval);
  627. }
  628. }
  629.  
  630. globalThis[arguments[0]] = ModBase;
  631.  
  632. return function (when = "load") {
  633. setTimeout(() => {
  634. const ModMenu = new CubeEngine();
  635. // ModMenu.htmlElements.details.open = false;
  636.  
  637. const target = document.getElementById("accountbox");
  638. const container = domMake.Tree("div", { id: identifier, style: "height: 1.6rem; flex: 0 0 auto;" });
  639. container.appendChild(ModMenu.htmlElements.details);
  640. target.after(container);
  641. target.after(domMake.Tree("hr"));
  642.  
  643. globalThis["CubeEngine"] = ModMenu;
  644. globalThis["sockets"] = sockets;
  645.  
  646. domClear.embeds();
  647. domClear.scripts();
  648. domClear.styles();
  649. console.clear();
  650. }, 200);
  651. };
  652. })("QBit")();
  653.  
  654. (function BotClient() {
  655. const QBit = globalThis[arguments[0]];
  656.  
  657. function parseServerUrl(any) {
  658. var prefix = String(any).length == 1 ? `sv${any}.` : "";
  659. return `wss://${prefix}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`;
  660. }
  661.  
  662. function parseRoomId(any) {
  663. return String(any).match(/([a-f0-9.-]+?)$/gi)[0];
  664. }
  665.  
  666. function parseSocketIOEvent(prefix_length, event_data) {
  667. try {
  668. return JSON.parse(event_data.slice(prefix_length));
  669. } catch (error) {}
  670. }
  671.  
  672. function parseAvatarURL(arr = []) {
  673. return `https://drawaria.online/avatar/cache/${arr.length > 0 ? arr.join(".") : "default"}.jpg`;
  674. }
  675.  
  676. // class BotClient extends QBit {
  677. class BotClient {
  678. static dummy1 = QBit.register(this);
  679.  
  680. // constructor(name = '', avatar = []) {
  681. constructor(name = "JavaScript", avatar = ["cf19b8f0-cf31-11ed-9ece-d584b24f60dc", "1680377222354"]) {
  682. // super(name, `<img src="${parseAvatarURL(avatar)}">`);
  683.  
  684. this.name = name;
  685. this.avatar = avatar;
  686. this.attributes = { spawned: false, rounded: false, status: false };
  687.  
  688. this.url = "";
  689. this.socket = null;
  690. this.interval_id = 0;
  691. this.interval_ms = 25000;
  692.  
  693. this.room = {
  694. id: null,
  695. config: null,
  696. type: 2,
  697. players: [],
  698. };
  699.  
  700. this.customObservers = [
  701. {
  702. event: "mc_roomplayerschange",
  703. callback: (data) => {
  704. this.room.players = data[2];
  705. },
  706. },
  707. ];
  708. }
  709.  
  710. getReadyState() {
  711. const localThis = this;
  712. if (!localThis.socket) return false;
  713. return localThis.socket.readyState == localThis.socket.OPEN;
  714. }
  715.  
  716. connect(url) {
  717. const localThis = this;
  718. // if (localThis.getReadyState()) localThis.disconnect();
  719. if (localThis.getReadyState()) return;
  720.  
  721. if (!url) return localThis.enterRoom(document.querySelector("#invurl").value);
  722. localThis.socket = new WebSocket(parseServerUrl(url));
  723.  
  724. localThis.socket.addEventListener("open", function (event) {
  725. localThis.interval_id = setInterval(function () {
  726. if (!localThis.getReadyState()) return clearInterval(localThis.interval_id);
  727. localThis.send(2);
  728. }, localThis.interval_ms);
  729. });
  730.  
  731. localThis.socket.addEventListener("message", function (message_event) {
  732. var prefix = String(message_event.data).match(/(^\d+)/gi)[0] || "";
  733. if (prefix == "40") {
  734. localThis.send(emits.startplay(localThis.room, localThis.name, localThis.avatar));
  735. }
  736.  
  737. var data = parseSocketIOEvent(prefix.length, message_event.data) || [];
  738. if (data && data.length == 1) {
  739. if (data[0].players) localThis.room.players = data[0].players;
  740. }
  741. if (data && data.length > 1) {
  742. var event = data.shift();
  743.  
  744. localThis.customObservers.forEach((listener) => {
  745. if (listener.event === event) if (listener.callback) listener.callback(data);
  746. });
  747. }
  748. });
  749. }
  750.  
  751. disconnect() {
  752. if (!this.getReadyState()) return;
  753. this.socket.close();
  754. }
  755.  
  756. reconnect() {
  757. this.send(41);
  758. this.send(40);
  759. }
  760.  
  761. enterRoom(roomid) {
  762. this.room.id = parseRoomId(roomid);
  763. if (!this.getReadyState()) this.connect(this.room.id.includes(".") ? this.room.id.slice(-1) : "");
  764. this.reconnect();
  765. }
  766.  
  767. leaveRoom() {
  768. this.send(41);
  769. }
  770.  
  771. switchRoom() {
  772. this.emit("pgswtichroom");
  773. // this.send(emits['pgswtichroom']());
  774. }
  775.  
  776. addEventListener(eventname, callback) {
  777. this.customObservers.push({ event: eventname, callback });
  778. }
  779.  
  780. send(data) {
  781. if (!this.getReadyState()) return /*console.warn(data)*/;
  782. this.socket.send(data);
  783. }
  784.  
  785. emit(event, ...data) {
  786. // data = data.length > 0 ? data : null;
  787. var emitter = emits[event];
  788. if (emitter) this.send(emitter(...data));
  789. }
  790. }
  791.  
  792. const emits = {
  793. chatmsg: function (message) {
  794. // 42["chatmsg","a"]
  795. let data = ["chatmsg", message];
  796. return `${42}${JSON.stringify(data)}`;
  797. },
  798. passturn: function () {
  799. // 42["passturn"]
  800. let data = ["passturn"];
  801. return `${42}${JSON.stringify(data)}`;
  802. },
  803. pgdrawvote: function (playerid) {
  804. // 42["pgdrawvote",2,0]
  805. let data = ["pgdrawvote", playerid, 0];
  806. return `${42}${JSON.stringify(data)}`;
  807. },
  808. pgswtichroom: function () {
  809. // 42["pgswtichroom"]
  810. let data = ["pgswtichroom"];
  811. return `${42}${JSON.stringify(data)}`;
  812. },
  813. playerafk: function () {
  814. // 42["playerafk"]
  815. let data = ["playerafk"];
  816. return `${42}${JSON.stringify(data)}`;
  817. },
  818. playerrated: function () {
  819. // 42["playerrated"]
  820. let data = ["playerrated"];
  821. return `${42}${JSON.stringify(data)}`;
  822. },
  823. sendgesture: function (gestureid) {
  824. // 42["sendgesture",16]
  825. let data = ["sendgesture", gestureid];
  826. return `${42}${JSON.stringify(data)}`;
  827. },
  828. sendvote: function () {
  829. // 42["sendvote"]
  830. let data = ["sendvote"];
  831. return `${42}${JSON.stringify(data)}`;
  832. },
  833. sendvotekick: function (playerid) {
  834. // 42["sendvotekick",93]
  835. let data = ["sendvotekick", playerid];
  836. return `${42}${JSON.stringify(data)}`;
  837. },
  838. wordselected: function (wordid) {
  839. // 42["wordselected",0]
  840. let data = ["sendvotekick", wordid];
  841. return `${42}${JSON.stringify(data)}`;
  842. },
  843. activateitem: function (itemid, isactive) {
  844. let data = ["clientcmd", 12, [itemid, isactive]];
  845. return `${42}${JSON.stringify(data)}`;
  846. },
  847. buyitem: function (itemid) {
  848. let data = ["clientcmd", 11, [itemid]];
  849. return `${42}${JSON.stringify(data)}`;
  850. },
  851. canvasobj_changeattr: function (itemid, target, value) {
  852. // target = zindex || shared
  853. let data = ["clientcmd", 234, [itemid, target, value]];
  854. return `${42}${JSON.stringify(data)}`;
  855. },
  856. canvasobj_getobjects: function () {
  857. let data = ["clientcmd", 233];
  858. return `${42}${JSON.stringify(data)}`;
  859. },
  860. canvasobj_remove: function (itemid) {
  861. let data = ["clientcmd", 232, [itemid]];
  862. return `${42}${JSON.stringify(data)}`;
  863. },
  864. canvasobj_setposition: function (itemid, positionX, positionY, speed) {
  865. let data = ["clientcmd", 230, [itemid, 100 / positionX, 100 / positionY, { movespeed: speed }]];
  866. return `${42}${JSON.stringify(data)}`;
  867. },
  868. canvasobj_setrotation: function (itemid, rotation) {
  869. let data = ["clientcmd", 231, [itemid, rotation]];
  870. return `${42}${JSON.stringify(data)}`;
  871. },
  872. customvoting_setvote: function (value) {
  873. let data = ["clientcmd", 301, [value]];
  874. return `${42}${JSON.stringify(data)}`;
  875. },
  876. getfpid: function (value) {
  877. let data = ["clientcmd", 901, [value]];
  878. return `${42}${JSON.stringify(data)}`;
  879. },
  880. getinventory: function () {
  881. let data = ["clientcmd", 10, [true]];
  882. return `${42}${JSON.stringify(data)}`;
  883. },
  884. getspawnsstate: function () {
  885. let data = ["clientcmd", 102];
  886. return `${42}${JSON.stringify(data)}`;
  887. },
  888. moveavatar: function (positionX, positionY) {
  889. let data = [
  890. "clientcmd",
  891. 103,
  892. [1e4 * Math.floor((positionX / 100) * 1e4) + Math.floor((positionY / 100) * 1e4), false],
  893. ];
  894. return `${42}${JSON.stringify(data)}`;
  895. },
  896. setavatarprop: function () {
  897. let data = ["clientcmd", 115];
  898. return `${42}${JSON.stringify(data)}`;
  899. },
  900. setstatusflag: function (flagid, isactive) {
  901. let data = ["clientcmd", 3, [flagid, isactive]];
  902. return `${42}${JSON.stringify(data)}`;
  903. },
  904. settoken: function (playerid, tokenid) {
  905. let data = ["clientcmd", 2, [playerid, tokenid]];
  906. return `${42}${JSON.stringify(data)}`;
  907. },
  908. snapchatmessage: function (playerid, value) {
  909. let data = ["clientcmd", 330, [playerid, value]];
  910. return `${42}${JSON.stringify(data)}`;
  911. },
  912. spawnavatar: function () {
  913. let data = ["clientcmd", 101];
  914. return `${42}${JSON.stringify(data)}`;
  915. },
  916. startrollbackvoting: function () {
  917. let data = ["clientcmd", 320];
  918. return `${42}${JSON.stringify(data)}`;
  919. },
  920. trackforwardvoting: function () {
  921. let data = ["clientcmd", 321];
  922. return `${42}${JSON.stringify(data)}`;
  923. },
  924. startplay: function (room, name, avatar) {
  925. let data = `${420}${JSON.stringify([
  926. "startplay",
  927. name,
  928. room.type,
  929. "en",
  930. room.id,
  931. null,
  932. [null, "https://drawaria.online/", 1000, 1000, [null, avatar[0], avatar[1]], null],
  933. ])}`;
  934. return data;
  935. },
  936. votetrack: function (trackid) {
  937. let data = ["clientcmd", 1, [trackid]];
  938. return `${42}${JSON.stringify(data)}`;
  939. },
  940. requestcanvas: function (playerid) {
  941. let data = ["clientnotify", playerid, 10001];
  942. return `${42}${JSON.stringify(data)}`;
  943. },
  944. respondcanvas: function (playerid, base64) {
  945. let data = ["clientnotify", playerid, 10002, [base64]];
  946. return `${42}${JSON.stringify(data)}`;
  947. },
  948. galleryupload: function (playerid, imageid) {
  949. let data = ["clientnotify", playerid, 11, [imageid]];
  950. return `${42}${JSON.stringify(data)}`;
  951. },
  952. warning: function (playerid, type) {
  953. let data = ["clientnotify", playerid, 100, [type]];
  954. return `${42}${JSON.stringify(data)}`;
  955. },
  956. mute: function (playerid, targetname, mute = 0) {
  957. let data = ["clientnotify", playerid, 1, [mute, targetname]];
  958. return `${42}${JSON.stringify(data)}`;
  959. },
  960. hide: function (playerid, targetname, hide = 0) {
  961. let data = ["clientnotify", playerid, 3, [hide, targetname]];
  962. return `${42}${JSON.stringify(data)}`;
  963. },
  964. report: function (playerid, reason, targetname) {
  965. let data = ["clientnotify", playerid, 2, [targetname, reason]];
  966. return `${42}${JSON.stringify(data)}`;
  967. },
  968. line: function (playerid, lastx, lasty, x, y, isactive, size, color, ispixel) {
  969. let data = [
  970. "drawcmd",
  971. 0,
  972. [lastx / 100, lasty / 100, x / 100, y / 100, isactive, -size, color, playerid, ispixel],
  973. ];
  974. return `${42}${JSON.stringify(data)}`;
  975. },
  976. erase: function (playerid, lastx, lasty, x, y, isactive, size, color) {
  977. let data = ["drawcmd", 1, [lastx / 100, lasty / 100, x / 100, y / 100, isactive, -size, color, playerid]];
  978. return `${42}${JSON.stringify(data)}`;
  979. },
  980. flood: function (x, y, color, size, r, g, b, a) {
  981. // 42["drawcmd",2,[x, y,color,{"0":r,"1":g,"2":b,"3":a},size]]
  982. let data = ["drawcmd", 2, [x / 100, y / 100, color, { 0: r, 1: g, 2: b, 3: a }, size]];
  983. return `${42}${JSON.stringify(data)}`;
  984. },
  985. undo: function (playerid) {
  986. // 42["drawcmd",3,[playerid]]
  987. let data = ["drawcmd", 3, [playerid]];
  988. return `${42}${JSON.stringify(data)}`;
  989. },
  990. clear: function () {
  991. // 42["drawcmd",4,[]]
  992. let data = ["drawcmd", 4, []];
  993. return `${42}${JSON.stringify(data)}`;
  994. },
  995. noop: function () {
  996. // 42["drawcmd",5,[0.44882022129015975,0.3157894736842105,0.44882022129015975,0.3157894736842105,true,-12,"#000000",playerid]]
  997. },
  998. };
  999. const events = {
  1000. bc_announcement: function (data) {
  1001. //
  1002. },
  1003. bc_chatmessage: function (data) {
  1004. // 42["bc_chatmessage",3,"playername","a"]
  1005. },
  1006. bc_clearcanvasobj: function (data) {
  1007. //
  1008. },
  1009. bc_clientnotify: function (data) {
  1010. // 42["bc_clientnotify",playerid,"playername",code,null]
  1011. },
  1012. bc_createcanvasobj: function (data) {
  1013. // 42["bc_createcanvasobj","1",[3,63001,0.5,0.5,0,1,null,"1",true]]
  1014. },
  1015. bc_customvoting_abort: function (data) {
  1016. //
  1017. },
  1018. bc_customvoting_error: function (data) {
  1019. // 42["bc_customvoting_error","rollbackcanvas"]
  1020. },
  1021. bc_customvoting_results: function (data) {
  1022. // 42["bc_customvoting_results",[2],true,0]
  1023. },
  1024. bc_customvoting_start: function (data) {
  1025. // 42["bc_customvoting_start",{"type":321,"secs":20,"acceptratios":[0.51],"pgdrawallow":true,"voteoptions":["YES","NO"]},1]
  1026. },
  1027. bc_customvoting_vote: function (data) {
  1028. // 42["bc_customvoting_vote",1,0,[2,1,[1]]]
  1029. },
  1030. bc_exp: function (data) {
  1031. // 42["bc_exp",29,4357]
  1032. },
  1033. bc_extannouncement: function (data) {
  1034. //
  1035. },
  1036. bc_freedrawsession_reset: function (data) {
  1037. // 42["bc_freedrawsession_reset",-1,{"votingtype":2,"currentvotes":0,"neededvotes":2,"votingtimeout":null}null]
  1038. },
  1039. bc_gesture: function (data) {
  1040. // 42["bc_gesture",3,31]
  1041. },
  1042. bc_musicbox_play: function (data) {
  1043. // 42["bc_musicbox_play",[30394,1,"37678185",252386,1661295694733,"Sony Masterworks - Smooth Criminal","2cellos/smooth-criminal"]]
  1044. },
  1045. bc_musicbox_vote: function (data) {
  1046. // 42["bc_musicbox_vote",[[30394,1]],3,30394]
  1047. },
  1048. bc_pgdrawallow_results: function (data) {
  1049. // 42["bc_pgdrawallow_results",2,true,true]
  1050. },
  1051. bc_pgdrawallow_startvoting: function (data) {
  1052. // 42["bc_pgdrawallow_startvoting",2,1,false]
  1053. },
  1054. bc_pgdrawallow_vote: function (data) {
  1055. // 42["bc_pgdrawallow_vote",2,1,0,false,[1,0]]
  1056. },
  1057. bc_playerafk: function (data) {
  1058. // 42["bc_playerafk",28,"Jinx"]
  1059. },
  1060. bc_playerrated: function (data) {
  1061. // 42["bc_playerrated",1,29,"lil cute girl",28,"Jinx",[1]]
  1062. },
  1063. bc_removecanvasobj: function (data) {
  1064. // 42["bc_removecanvasobj",3,"1",null]
  1065. },
  1066. bc_resetplayername: function (data) {
  1067. //
  1068. },
  1069. bc_round_results: function (data) {
  1070. // 42["bc_round_results",[[5,"Jinx",15,61937,3,"63196790-c7da-11ec-8266-c399f90709b7",0],[4,"ツ♡thick mojo ♡ツ",15,65464,3,"018cdc20-47a4-11ec-b5b5-6bdacecdd51e",1]]]
  1071. },
  1072. bc_setavatarprop: function (data) {
  1073. // 42["bc_setavatarprop",3]
  1074. },
  1075. bc_setobjattr: function (data) {
  1076. // 42["bc_setobjattr","1","shared",false]
  1077. },
  1078. bc_setstatusflag: function (data) {
  1079. // 42["bc_setstatusflag",3,3,true]
  1080. },
  1081. bc_spawnavatar: function (data) {
  1082. // 42["bc_spawnavatar",3,true]
  1083. },
  1084. bc_startinground: function (data) {
  1085. // 42["bc_startinground",200000,[],{"votingtype":0,"currentvotes":0,"neededvotes":2,"votingtimeout":null}]
  1086. },
  1087. bc_token: function (data) {
  1088. // 42["bc_token",1,3,0]
  1089. },
  1090. bc_turn_abort: function (data) {
  1091. // 42["bc_turn_abort","pass","lil cute girl","2c276aa0-dc5e-11ec-9fd3-c3a00b129da4","hammer",null]
  1092. },
  1093. bc_turn_fastout: function (data) {
  1094. // 42["bc_turn_fastout",15000]
  1095. },
  1096. bc_turn_results: function (data) {
  1097. // 42["bc_turn_results",[[1,"Jinx",2,2,"63196790-c7da-11ec-8266-c399f90709b7",0,0],[2,"vale",3,3,"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.xxxxxxxxxxxxx",9248]],"cavern"]
  1098. },
  1099. bc_turn_waitplayers: function (data) {
  1100. // 42["bc_turn_waitplayers",true,-1,6]
  1101. },
  1102. bc_uc_freedrawsession_changedroom: function (data) {
  1103. // console.log(data[2], data[3])
  1104. // 42["bc_uc_freedrawsession_changedroom",[list of drawlines not !important]]
  1105. },
  1106. bc_uc_freedrawsession_start: function (data) {
  1107. //
  1108. },
  1109. bc_votekick: function (data) {
  1110. // 42["bc_votekick","Jinx",22,true]
  1111. },
  1112. bc_votingtimeout: function (data) {
  1113. // 42["bc_votingtimeout",{"votingtype":2,"currentvotes":0,"neededvotes":2,"votingtimeout":null}]
  1114. },
  1115. bcmc_playervote: function (data) {
  1116. // 42["bcmc_playervote","playername",{"votingtype":3,"currentvotes":1,"neededvotes":2,"votingtimeout":1661296731309}]
  1117. },
  1118. bcuc_getfpid: function (data) {
  1119. // 42["bcuc_getfpid"]
  1120. // 42["clientcmd",901,[{"visitorId":"a8923f0870050d4a4e771cd26679ab6e"}]]
  1121. },
  1122. bcuc_itemactivated: function (data) {
  1123. // 42["bcuc_itemactivated",3,63001,[2,[0.5,0.5],0,1,null],1]
  1124. },
  1125. bcuc_itemactivationabort: function (data) {
  1126. //
  1127. },
  1128. bcuc_moderatormsg: function (data) {
  1129. // 42["bcuc_moderatormsg","Kick Player",true]
  1130. },
  1131. bcuc_snapchatmessage: function (data) {
  1132. // 42["uc_snapshot","1671740010120.1.28028"]
  1133. // https://drawaria.online/snapshot/save
  1134. },
  1135. mc_drawcommand: function (data) {
  1136. // 42["mc_drawcommand",0,[0.2958167330677291,0.24970131421744324,0.2958167330677291,0.24970131421744324,true,-12,"#000000",3]]
  1137. },
  1138. mc_moveavatar: function (data) {
  1139. // 42["mc_moveavatar",3,36081456,true]
  1140. },
  1141. mc_moveobj: function (data) {
  1142. // 42["mc_moveobj","1",0.8266237186146181,0.24248391556470414,3,{"movespeed":500}]
  1143. },
  1144. mc_roomplayerschange: function (data) {
  1145. // console.log(data[2])
  1146. // 42["mc_roomplayerschange","join","playername",[{"id":1,"name":"ᴮᴱᴺᴵᴹᴬᴿᵁ","turnscore":0,"roundscore":0,"roundguesstime":0,"avatarid":"81253f20-ff93-11ec-9fd3-c3a00b129da4.1661276848726","account_stats":null,"from":"TR","medals":0,"turnstarcount":0,"statusflags":[]}{"id":3,"name":"playername","turnscore":0,"roundscore":0,"roundguesstime":0,"avatarid":"81253f20-ff93-11ec-9fd3-c3a00b129da4.1661276848726","account_stats":null,"from":"GB","medals":0,"turnstarcount":0,"statusflags":[]}],{"votingtype":2,"currentvotes":0,"neededvotes":0,"votingtimeout":null}false,3]
  1147. },
  1148. mc_rotateobj: function (data) {
  1149. // 42["mc_rotateobj","1",0.2617993877991494,3]
  1150. },
  1151. mc_turn_guessdraw: function (data) {
  1152. // 42["mc_turn_guessdraw",90000,[],"Ǝ̵͍͖͓͒͑͊E̵̠̼̔͘͜͝",{"votingtype":1,"currentvotes":0,"neededvotes":2,"votingtimeout":null}false]
  1153. },
  1154. mc_turn_tip: function (data) {
  1155. // 42["mc_turn_tip","_a_m__"]
  1156. },
  1157. mc_turn_waitselectword: function (data) {
  1158. // 42["mc_turn_waitselectword",11000,"Ǝ̵͍͖͓͒͑͊E̵̠̼̔͘͜͝",6,"c46de8f0-f493-11ec-9fd3-c3a00b129da4",2,5,false]
  1159. },
  1160. mc_turn_wordguessed: function (data) {
  1161. // 42["mc_turn_wordguessed","vale",[[2,3,3,9248],[1,2,2,0]]]
  1162. },
  1163. uc_avatarspawninfo: function (data) {
  1164. // 42["uc_avatarspawninfo","9a2ab5b2-b81e-4690-9af7-475d870d6e20",[[38,75059625,0]]]
  1165. },
  1166. uc_buyitemerror: function (data) {
  1167. //
  1168. },
  1169. uc_canvasobjs: function (data) {
  1170. // 42["uc_canvasobjs","9a2ab5b2-b81e-4690-9af7-475d870d6e20",{}]
  1171. },
  1172. uc_chatmuted: function (data) {
  1173. // 42["uc_chatmuted"]
  1174. },
  1175. uc_coins: function (data) {
  1176. // 42["uc_coins",-50,43]
  1177. },
  1178. uc_inventoryitems: function (data) {
  1179. // 42["uc_inventoryitems",[[100,99,null],[63000,null,null],[86000,null,null]],false,false] list
  1180. },
  1181. uc_resetavatar: function (data) {
  1182. //
  1183. },
  1184. uc_serverserstart: function (data) {
  1185. //
  1186. },
  1187. uc_snapshot: function (data) {
  1188. //
  1189. },
  1190. uc_tokenerror: function (data) {
  1191. // 42["uc_tokenerror",2]
  1192. },
  1193. uc_turn_begindraw: function (data) {
  1194. // 42["uc_turn_begindraw",90000,"arrow"]
  1195. },
  1196. uc_turn_selectword: function (data) {
  1197. // 42["uc_turn_selectword",11000,["vase","cellar","rain"],1,7,false]
  1198. },
  1199. uc_turn_selectword_refreshlist: function (data) {
  1200. // 42["uc_turn_selectword_refreshlist",["crayons","trade","team"]]
  1201. },
  1202. uc_turn_wordguessedlocalThis: function (data) {
  1203. // 42["uc_turn_wordguessedlocalThis","stage",3,[[2,3,3,53938],[1,2,2,0]]]
  1204. },
  1205. };
  1206.  
  1207. globalThis["_io"] = { events, emits };
  1208. })("QBit");
  1209.  
  1210. (function BiggerBrush() {
  1211. const QBit = globalThis[arguments[0]];
  1212.  
  1213. class BiggerBrush extends QBit {
  1214. static dummy1 = QBit.register(this);
  1215. static dummy2 = QBit.bind(this, "CubeEngine");
  1216.  
  1217. active;
  1218. constructor() {
  1219. super("BiggerBrush", '<i class="fas fa-brush"></i>');
  1220. this.active = false;
  1221. this.#onStartup();
  1222. }
  1223.  
  1224. #onStartup() {
  1225. this.#loadInterface();
  1226. this.drawwidthrangeSlider = document.querySelector("#drawwidthrange");
  1227. // this.enable();
  1228. }
  1229.  
  1230. #loadInterface() {
  1231. this.#row1();
  1232. }
  1233.  
  1234. #row1() {
  1235. const row = domMake.Row();
  1236. {
  1237. const enableButton = domMake.Button("Enable");
  1238.  
  1239. enableButton.addEventListener("click", (event) => {
  1240. this.active ? this.disable() : this.enable();
  1241. });
  1242. row.appendChild(enableButton);
  1243. this.htmlElements.toggleStatusButton = enableButton;
  1244. }
  1245. this.htmlElements.section.appendChild(row);
  1246. }
  1247.  
  1248. enable() {
  1249. document.querySelectorAll(".drawcontrols-button").forEach((n) => {
  1250. n.classList.remove("drawcontrols-disabled");
  1251. });
  1252. this.active = true;
  1253.  
  1254. this.htmlElements.toggleStatusButton.classList.add("active");
  1255. this.htmlElements.toggleStatusButton.textContent = "Active";
  1256.  
  1257. this.drawwidthrangeSlider.parentElement.previousElementSibling.lastElementChild.click();
  1258. this.drawwidthrangeSlider.parentElement.style.display = "flex";
  1259. this.drawwidthrangeSlider.max = 48;
  1260. this.drawwidthrangeSlider.min = -2000;
  1261.  
  1262. this.notify("success", `enabled`);
  1263. }
  1264.  
  1265. disable() {
  1266. this.active = false;
  1267.  
  1268. this.htmlElements.toggleStatusButton.classList.remove("active");
  1269. this.htmlElements.toggleStatusButton.textContent = "Inactive";
  1270.  
  1271. this.drawwidthrangeSlider.max = 45;
  1272. this.drawwidthrangeSlider.min = -100;
  1273.  
  1274. this.notify("warning", `disabled`);
  1275. }
  1276. }
  1277. })("QBit");
  1278.  
  1279. (function BetterBrush() {
  1280. const QBit = globalThis[arguments[0]];
  1281.  
  1282. class BetterBrush extends QBit {
  1283. static dummy1 = QBit.register(this);
  1284. static dummy2 = QBit.bind(this, "CubeEngine");
  1285.  
  1286. constructor() {
  1287. super("BetterBrush", '<i class="fas fa-magic"></i>');
  1288. this.#onStartup();
  1289. }
  1290.  
  1291. #onStartup() {
  1292. this.#loadInterface();
  1293.  
  1294. {
  1295. const target = document.querySelector(".drawcontrols-popuplist");
  1296.  
  1297. const visibilityOvserver = new MutationObserver((mutations) => {
  1298. if (this.active)
  1299. if (mutations[0].target.style != "display:none") {
  1300. mutations[0].target.querySelectorAll("div").forEach((n) => {
  1301. n.removeAttribute("style");
  1302. });
  1303. }
  1304. });
  1305.  
  1306. visibilityOvserver.observe(target, {
  1307. attributes: true,
  1308. });
  1309. }
  1310. }
  1311.  
  1312. #loadInterface() {
  1313. this.#row1();
  1314. }
  1315.  
  1316. #row1() {
  1317. const row = domMake.Row();
  1318. {
  1319. const enableButton = domMake.Button("Enable");
  1320.  
  1321. enableButton.addEventListener("click", (event) => {
  1322. this.active ? this.disable() : this.enable();
  1323. });
  1324.  
  1325. row.appendChild(enableButton);
  1326. this.htmlElements.toggleStatusButton = enableButton;
  1327. }
  1328. this.htmlElements.section.appendChild(row);
  1329. }
  1330.  
  1331. enable() {
  1332. this.active = true;
  1333.  
  1334. this.htmlElements.toggleStatusButton.classList.add("active");
  1335. this.htmlElements.toggleStatusButton.textContent = "Active";
  1336.  
  1337. this.notify("success", `enabled`);
  1338. }
  1339.  
  1340. disable() {
  1341. this.active = false;
  1342.  
  1343. this.htmlElements.toggleStatusButton.classList.remove("active");
  1344. this.htmlElements.toggleStatusButton.textContent = "Inactive";
  1345.  
  1346. this.notify("warning", `disabled`);
  1347. }
  1348. }
  1349. })("QBit");
  1350.  
  1351. (function BiggerStencil() {
  1352. const QBit = globalThis[arguments[0]];
  1353.  
  1354. class BiggerStencil extends QBit {
  1355. static dummy1 = QBit.register(this);
  1356. static dummy2 = QBit.bind(this, "CubeEngine");
  1357.  
  1358. active;
  1359.  
  1360. constructor() {
  1361. super("BiggerStencil", '<i class="fas fa-parachute-box"></i>');
  1362. this.active = false;
  1363. this.#onStartup();
  1364. }
  1365.  
  1366. #onStartup() {
  1367. this.#loadInterface();
  1368.  
  1369. {
  1370. const target = document.querySelector(".fa-parachute-box").parentElement;
  1371. const accessabilityObserver = new MutationObserver((mutations) => {
  1372. if (this.active)
  1373. if (mutations[0].target.disabled) {
  1374. mutations[0].target.disabled = "";
  1375. }
  1376. });
  1377.  
  1378. accessabilityObserver.observe(target, {
  1379. attributes: true,
  1380. });
  1381. }
  1382. }
  1383.  
  1384. #loadInterface() {
  1385. this.#row1();
  1386. }
  1387.  
  1388. #row1() {
  1389. const row = domMake.Row();
  1390. {
  1391. const enableButton = domMake.Button("Enable");
  1392.  
  1393. enableButton.addEventListener("click", (event) => {
  1394. this.active ? this.disable() : this.enable();
  1395. });
  1396. row.appendChild(enableButton);
  1397. this.htmlElements.toggleStatusButton = enableButton;
  1398. }
  1399. this.htmlElements.section.appendChild(row);
  1400. }
  1401.  
  1402. enable() {
  1403. this.active = true;
  1404.  
  1405. this.htmlElements.toggleStatusButton.classList.add("active");
  1406. this.htmlElements.toggleStatusButton.textContent = "Active";
  1407.  
  1408. this.notify("success", `enabled`);
  1409. }
  1410.  
  1411. disable() {
  1412. this.active = false;
  1413.  
  1414. this.htmlElements.toggleStatusButton.classList.remove("active");
  1415. this.htmlElements.toggleStatusButton.textContent = "Inactive";
  1416.  
  1417. this.notify("warning", `disabled`);
  1418. }
  1419. }
  1420. })("QBit");
  1421.  
  1422. (function GhostCanvas() {
  1423. const QBit = globalThis[arguments[0]];
  1424. const Await = QBit.findGlobal("Await");
  1425.  
  1426. QBit.Styles.addRule(
  1427. ".ghostimage { position:fixed; top:50%; left:50%; opacity:.6; box-shadow: 0 0 1px 1px cornflowerblue inset; }"
  1428. );
  1429.  
  1430. function getBoundingClientRect(htmlElement) {
  1431. let { top, right, bottom, left, width, height, x, y } = htmlElement.getBoundingClientRect();
  1432.  
  1433. top = Number(top).toFixed();
  1434. right = Number(right).toFixed();
  1435. bottom = Number(bottom).toFixed();
  1436. left = Number(left).toFixed();
  1437. width = Number(width).toFixed();
  1438. height = Number(height).toFixed();
  1439. x = Number(x).toFixed();
  1440. y = Number(y).toFixed();
  1441.  
  1442. return { top, right, bottom, left, width, height, x, y };
  1443. }
  1444.  
  1445. function makeDragable(draggableElement, update) {
  1446. var pos1 = 0,
  1447. pos2 = 0,
  1448. pos3 = 0,
  1449. pos4 = 0;
  1450. draggableElement.onmousedown = dragMouseDown;
  1451.  
  1452. function dragMouseDown(e) {
  1453. e = e || window.event;
  1454. e.preventDefault();
  1455. // get the mouse cursor position at startup:
  1456. pos3 = e.clientX;
  1457. pos4 = e.clientY;
  1458. document.onmouseup = closeDragElement;
  1459. // call a function whenever the cursor moves:
  1460. document.onmousemove = elementDrag;
  1461. }
  1462.  
  1463. function elementDrag(e) {
  1464. e = e || window.event;
  1465. e.preventDefault();
  1466. // calculate the new cursor position:
  1467. pos1 = pos3 - e.clientX;
  1468. pos2 = pos4 - e.clientY;
  1469. pos3 = e.clientX;
  1470. pos4 = e.clientY;
  1471. // set the element's new position:
  1472. draggableElement.style.top = Number(draggableElement.offsetTop - pos2).toFixed() + "px";
  1473. draggableElement.style.left = Number(draggableElement.offsetLeft - pos1).toFixed() + "px";
  1474. update();
  1475. }
  1476.  
  1477. function closeDragElement() {
  1478. /* stop moving when mouse button is released:*/
  1479. document.onmouseup = null;
  1480. document.onmousemove = null;
  1481. }
  1482. }
  1483.  
  1484. const radios = [];
  1485.  
  1486. class GhostCanvas extends QBit {
  1487. static dummy1 = QBit.register(this);
  1488. static dummy2 = QBit.bind(this, "CubeEngine");
  1489. static isFavorite = true;
  1490.  
  1491. GameCanvas;
  1492. DrawCanvas;
  1493. DrawCanvasContext;
  1494. DrawCanvasRect;
  1495. loadedImages;
  1496. drawingManager;
  1497.  
  1498. constructor() {
  1499. super("GhostCanvas", '<i class="fas fa-images"></i>');
  1500. this.GameCanvas = document.body.querySelector("canvas#canvas");
  1501. this.DrawCanvas = document.createElement("canvas");
  1502. this.DrawCanvasRect = {};
  1503. this.loadedImages = [];
  1504. this.DrawCanvasContext = this.DrawCanvas.getContext("2d");
  1505. this.drawingManager = new TaskManager(this);
  1506.  
  1507. this.#onStartup();
  1508. this.resetAllSettings();
  1509. }
  1510.  
  1511. #onStartup() {
  1512. this.#loadInterface();
  1513. this.DrawCanvas.width = this.GameCanvas.width;
  1514. this.DrawCanvas.height = this.GameCanvas.height;
  1515. this.DrawCanvas.style =
  1516. "position:fixed; opacity:.6; box-shadow: 0 0 1px 1px firebrick inset; pointer-events: none;";
  1517.  
  1518. const onResize = new Await(this.alignDrawCanvas.bind(this), 500);
  1519. window.addEventListener("resize", (event) => {
  1520. onResize.call();
  1521. });
  1522.  
  1523. this.htmlElements.input.addEventListener("change", (event) => {
  1524. if (this.htmlElements.input.checked) this.alignDrawCanvas();
  1525. });
  1526. }
  1527.  
  1528. #loadInterface() {
  1529. this.#row1();
  1530. this.#row2();
  1531. this.#row3();
  1532. this.#row4();
  1533. this.#row5();
  1534. }
  1535.  
  1536. #row1() {
  1537. const row = domMake.Row();
  1538. {
  1539. const resetSettingsButton = domMake.Button("Reset");
  1540. const showCanvasInput = domMake.Tree("input", { type: "checkbox", title: "Toggle Canvas", class: "icon" });
  1541. const clearCanvasButton = domMake.Button("Clear");
  1542.  
  1543. resetSettingsButton.title = "Reset Settings";
  1544. clearCanvasButton.title = "Clear GameCanvas";
  1545.  
  1546. resetSettingsButton.addEventListener("click", (event) => {
  1547. this.resetAllSettings();
  1548. });
  1549.  
  1550. showCanvasInput.addEventListener("change", () => {
  1551. this.DrawCanvas.style.display = showCanvasInput.checked ? "block" : "none";
  1552. });
  1553.  
  1554. clearCanvasButton.addEventListener("click", (event) => {
  1555. let data = ["drawcmd", 0, [0.5, 0.5, 0.5, 0.5, !0, -2000, "#FFFFFF", -1, !1]];
  1556. this.findGlobal("BotClientInterface").siblings[0].bot.send(`${42}${JSON.stringify(data)}`);
  1557. });
  1558.  
  1559. document.body.appendChild(this.DrawCanvas);
  1560. row.appendAll(resetSettingsButton, showCanvasInput, clearCanvasButton);
  1561. }
  1562. this.htmlElements.section.appendChild(row);
  1563. }
  1564.  
  1565. #row2() {
  1566. const row = domMake.Row();
  1567. {
  1568. const loadPixelDataButton = domMake.Button("Load");
  1569. const pixelsLeftToDraw = domMake.Tree("input", {
  1570. type: "text",
  1571. readonly: true,
  1572. style: "text-align: center;",
  1573. value: "0",
  1574. });
  1575. const clearPixelListButton = domMake.Button("Clear");
  1576.  
  1577. this.htmlElements.pixelsLeftToDraw = pixelsLeftToDraw;
  1578. loadPixelDataButton.title = "Load Pixels to draw";
  1579. clearPixelListButton.title = "Clear Pixels to draw";
  1580.  
  1581. loadPixelDataButton.addEventListener("click", (event) => {
  1582. this.saveCanvas();
  1583. });
  1584.  
  1585. clearPixelListButton.addEventListener("click", (event) => {
  1586. this.setPixelList([]);
  1587. });
  1588.  
  1589. row.appendAll(loadPixelDataButton, pixelsLeftToDraw, clearPixelListButton);
  1590. }
  1591. this.htmlElements.section.appendChild(row);
  1592. }
  1593.  
  1594. #row3() {
  1595. const row = domMake.Row();
  1596. {
  1597. const startDrawingButton = domMake.Button("Start");
  1598. const stopDrawingButton = domMake.Button("Stop");
  1599.  
  1600. startDrawingButton.addEventListener("click", (event) => {
  1601. this.drawingManager.startDrawing();
  1602. });
  1603. stopDrawingButton.addEventListener("click", (event) => {
  1604. this.drawingManager.stopDrawing();
  1605. });
  1606.  
  1607. row.appendAll(startDrawingButton, stopDrawingButton);
  1608. }
  1609. this.htmlElements.section.appendChild(row);
  1610. }
  1611.  
  1612. #row4() {
  1613. const row = domMake.Row();
  1614. {
  1615. const brushSizeInput = domMake.Tree("input", { type: "number", min: 2, value: 2, max: 200, step: 1 });
  1616. const singleColorModeInput = domMake.Tree("input", { type: "checkbox", class: "icon" });
  1617. const brushColorInput = domMake.Tree("input", { type: "text", value: "blue" });
  1618.  
  1619. brushSizeInput.addEventListener("change", (event) => {
  1620. this.drawingManager.brushSize = Number(brushSizeInput.value);
  1621. });
  1622. singleColorModeInput.addEventListener("change", (event) => {
  1623. this.drawingManager.singleColor = Boolean(singleColorModeInput.checked);
  1624. });
  1625. brushColorInput.addEventListener("change", (event) => {
  1626. this.drawingManager.brushColor = brushColorInput;
  1627. });
  1628.  
  1629. row.appendAll(brushSizeInput, singleColorModeInput, brushColorInput);
  1630. }
  1631. this.htmlElements.section.appendChild(row);
  1632. }
  1633.  
  1634. #row5() {
  1635. const row = domMake.IconList();
  1636. {
  1637. const id = generate.uuidv4();
  1638. const chooseGhostlyImageInput = domMake.Tree("input", { type: "file", id: id, hidden: true });
  1639. const chooseGhostlyImageLabel = domMake.Tree("label", { for: id, class: "icon", title: "Add Image" }, [
  1640. domMake.Tree("i", { class: "fas fa-plus" }),
  1641. ]);
  1642.  
  1643. const localThis = this;
  1644. function onChange() {
  1645. if (!this.files || !this.files[0]) return;
  1646. const myFileReader = new FileReader();
  1647. myFileReader.addEventListener("load", (event) => {
  1648. const base64 = event.target.result.replace("image/gif", "image/png");
  1649. localThis.createGhostImage(base64, row);
  1650. });
  1651. myFileReader.readAsDataURL(this.files[0]);
  1652. }
  1653. chooseGhostlyImageInput.addEventListener("change", onChange);
  1654.  
  1655. row.appendAll(chooseGhostlyImageLabel, chooseGhostlyImageInput);
  1656. }
  1657. {
  1658. const resetImageSelectionLabel = domMake.Tree("div", { class: "icon", title: "Unselect" }, [
  1659. domMake.Tree("i", { class: "fas fa-chevron-left" }),
  1660. ]);
  1661. resetImageSelectionLabel.addEventListener("click", () => {
  1662. document.body.querySelectorAll('input[name="ghostimage"]').forEach((node) => {
  1663. node.checked = false;
  1664. });
  1665. });
  1666. row.appendChild(resetImageSelectionLabel);
  1667. }
  1668. this.htmlElements.section.appendChild(row);
  1669. }
  1670.  
  1671. createGhostImage(imageSource, row) {
  1672. this.alignDrawCanvas();
  1673. const image = this.loadExtension(GhostImage, (reference) => {
  1674. this.loadedImages.push(reference);
  1675. });
  1676. row.appendChild(image.htmlElements.label);
  1677. image.setImageSource(imageSource);
  1678. }
  1679.  
  1680. clearCanvas() {
  1681. this.DrawCanvasContext.clearRect(0, 0, this.DrawCanvas.width, this.DrawCanvas.height);
  1682. }
  1683.  
  1684. saveCanvas() {
  1685. this.getAllPixels();
  1686. }
  1687.  
  1688. resetAllSettings() {
  1689. this.clearCanvas();
  1690. this.loadedImages.forEach((image, index) => {
  1691. setTimeout(() => {
  1692. image.reduceToAtoms();
  1693. }, 10 * index);
  1694. });
  1695. this.drawingManager.stopDrawing();
  1696. this.setPixelList([]);
  1697. this.alignDrawCanvas(true);
  1698. }
  1699.  
  1700. alignDrawCanvas() {
  1701. if (arguments[0]) {
  1702. this.DrawCanvas.width = this.GameCanvas.width;
  1703. this.DrawCanvas.height = this.GameCanvas.height;
  1704. }
  1705.  
  1706. const GameCanvasRect = getBoundingClientRect(this.GameCanvas);
  1707.  
  1708. this.DrawCanvas.style.top = `${GameCanvasRect.top}px`;
  1709. this.DrawCanvas.style.left = `${GameCanvasRect.left}px`;
  1710. this.DrawCanvas.style.width = `${GameCanvasRect.width}px`;
  1711. this.DrawCanvas.style.height = `${GameCanvasRect.height}px`;
  1712.  
  1713. const DrawCanvasRect = getBoundingClientRect(this.DrawCanvas);
  1714.  
  1715. if (DrawCanvasRect.width <= 0 || DrawCanvasRect.height <= 0)
  1716. return Object.assign(this.DrawCanvasRect, DrawCanvasRect);
  1717. // DrawCanvasRect.alignModifierX = Number(this.DrawCanvas.width / DrawCanvasRect.width).toFixed(2);
  1718. // DrawCanvasRect.alignModifierY = Number(this.DrawCanvas.height / DrawCanvasRect.height).toFixed(2);
  1719.  
  1720. DrawCanvasRect.drawModifierX = 100 / DrawCanvasRect.width;
  1721. DrawCanvasRect.drawModifierY = 100 / DrawCanvasRect.height;
  1722. Object.assign(this.DrawCanvasRect, DrawCanvasRect);
  1723. }
  1724.  
  1725. getAllPixels() {
  1726. const image = this.DrawCanvasContext.getImageData(
  1727. 0,
  1728. 0,
  1729. this.DrawCanvasContext.canvas.width,
  1730. this.DrawCanvasContext.canvas.height
  1731. );
  1732. const pixels = [];
  1733.  
  1734. for (let index = 0; index < image.data.length; index += 4) {
  1735. // const x = (index * 0.25) % image.width;
  1736. // const y = Math.floor((index * 0.25) / image.width);
  1737. const x = (index * 0.25) % image.width;
  1738. const y = Math.floor((index * 0.25) / image.width);
  1739.  
  1740. const r = image.data[index + 0];
  1741. const g = image.data[index + 1];
  1742. const b = image.data[index + 2];
  1743. const a = image.data[index + 3];
  1744. // const color = rgbaArrayToHex([r, g, b, a]);
  1745. const color = [r, g, b, a];
  1746. pixels.push({ x1: x, y1: y, x2: x, y2: y, color });
  1747. }
  1748.  
  1749. this.setPixelList(pixels);
  1750. }
  1751.  
  1752. getNoneTransparentPixels() {
  1753. this.getAllPixels();
  1754.  
  1755. const newPixelArray = this.drawingManager.pixelList.filter((pixel) => {
  1756. return pixel.color !== "#000000";
  1757. // return /^#0[0-8]0[0-8]0[0-8]$/g.test(pixel.color);
  1758. });
  1759.  
  1760. this.setPixelList(newPixelArray);
  1761. }
  1762.  
  1763. setPixelList(pixelArray) {
  1764. this.drawingManager.pixelList = pixelArray;
  1765. this.htmlElements.pixelsLeftToDraw.value = pixelArray.length;
  1766. }
  1767. }
  1768.  
  1769. class GhostImage extends QBit {
  1770. image;
  1771. rect;
  1772.  
  1773. constructor() {
  1774. super("GhostImage", '<i class="fas fa-image-polaroid"></i>');
  1775. this.#onStartup();
  1776. }
  1777.  
  1778. #onStartup() {
  1779. this.#loadInterface();
  1780.  
  1781. this.image = domMake.Tree("img", { class: "ghostimage" });
  1782. this.image.addEventListener("mousedown", (event) => {
  1783. this.htmlElements.label.click();
  1784. });
  1785.  
  1786. this.htmlElements.input.type = "radio";
  1787. this.htmlElements.input.name = "ghostimage";
  1788.  
  1789. radios.push(this.htmlElements.input);
  1790. this.htmlElements.input.addEventListener("change", (event) => {
  1791. radios.forEach(function (radio) {
  1792. document.body.querySelector(`label[for="${radio.id}"]`).classList.remove("active");
  1793. });
  1794. this.htmlElements.label.classList.add("active");
  1795. });
  1796.  
  1797. document.body.appendChild(this.image);
  1798. makeDragable(this.image, this.updatePosition.bind(this));
  1799. this.updatePosition();
  1800. }
  1801.  
  1802. #loadInterface() {
  1803. this.#row1();
  1804. this.#row2();
  1805. }
  1806.  
  1807. #row1() {
  1808. const row = domMake.Row();
  1809. {
  1810. const paintCanvasButton = domMake.Button("Place");
  1811.  
  1812. paintCanvasButton.addEventListener("click", (event) => {
  1813. this.drawImage();
  1814. });
  1815.  
  1816. row.appendAll(paintCanvasButton);
  1817. }
  1818. {
  1819. const enableButton = domMake.Button("Delete");
  1820.  
  1821. enableButton.addEventListener("click", (event) => {
  1822. this.reduceToAtoms();
  1823. });
  1824. row.appendChild(enableButton);
  1825. this.htmlElements.toggleStatusButton = enableButton;
  1826. }
  1827. this.htmlElements.section.appendChild(row);
  1828. }
  1829.  
  1830. #row2() {
  1831. const row = domMake.Row();
  1832. {
  1833. const scaleInput = domMake.Tree("input", {
  1834. type: "number",
  1835. title: "rotation",
  1836. min: 0.1,
  1837. max: 10,
  1838. value: 1,
  1839. step: 0.02,
  1840. });
  1841.  
  1842. scaleInput.addEventListener("change", () => {
  1843. this.image.style.scale = scaleInput.value;
  1844. });
  1845.  
  1846. this.htmlElements.scaleInput = scaleInput;
  1847.  
  1848. row.appendAll(scaleInput);
  1849. }
  1850. {
  1851. const rotationInput = domMake.Tree("input", { type: "number", title: "rotation", value: 0, step: 1 });
  1852.  
  1853. rotationInput.addEventListener("change", () => {
  1854. this.image.style.rotate = `${rotationInput.value}deg`;
  1855. });
  1856.  
  1857. this.htmlElements.rotationInput = rotationInput;
  1858.  
  1859. row.appendChild(rotationInput);
  1860. }
  1861. this.htmlElements.section.appendChild(row);
  1862. }
  1863.  
  1864. drawImage() {
  1865. this.updatePosition();
  1866. const ctx = this.parent.DrawCanvasContext;
  1867.  
  1868. const offsetTop = Number(this.rect.top) - Number(this.parent.DrawCanvasRect.top);
  1869. const offsetLeft = Number(this.rect.left) - Number(this.parent.DrawCanvasRect.left);
  1870.  
  1871. // const multiX = Number(this.parent.DrawCanvasRect.alignModifierX);
  1872. // const multiY = Number(this.parent.DrawCanvasRect.alignModifierY);
  1873.  
  1874. const angle = (Math.PI / 180) * Number(this.htmlElements.rotationInput.value);
  1875. const scale = Number(this.htmlElements.scaleInput.value);
  1876.  
  1877. const imageWidth = this.image.width * scale;
  1878. const imageHeight = this.image.height * scale;
  1879. const imgHalfWidth = imageWidth * 0.5;
  1880. const imgHalfHeight = imageHeight * 0.5;
  1881.  
  1882. ctx.save();
  1883. ctx.translate(offsetLeft + imgHalfWidth, offsetTop + imgHalfHeight);
  1884. ctx.rotate(angle);
  1885. ctx.translate(-imgHalfWidth, -imgHalfHeight);
  1886. ctx.drawImage(this.image, 0, 0, imageWidth, imageHeight);
  1887. ctx.restore();
  1888. }
  1889.  
  1890. setImageSource(imageSource) {
  1891. this.image.src = imageSource;
  1892. this.setIcon(`<img src="${this.image.src}">`);
  1893. }
  1894.  
  1895. updatePosition() {
  1896. this.rect = getBoundingClientRect(this.image);
  1897. }
  1898.  
  1899. reduceToAtoms() {
  1900. this.image.remove();
  1901. const pos = radios.indexOf(this.htmlElements.input);
  1902. if (~pos) radios.splice(pos, 1);
  1903.  
  1904. let pos2 = this.parent.loadedImages.indexOf(this);
  1905. if (~pos2) {
  1906. this.parent.loadedImages.splice(pos2, 1);
  1907. }
  1908. this._EXP_destroy(!0);
  1909. }
  1910. }
  1911.  
  1912. class TaskManager {
  1913. isRunning;
  1914. pixelList;
  1915. parent;
  1916. BotClientManager;
  1917. singleColor;
  1918. brushColor;
  1919. brushSize;
  1920.  
  1921. constructor(parent) {
  1922. this.pixelList = [];
  1923. this.singleColor = !1;
  1924. this.brushColor = "blue";
  1925. this.brushSize = 2;
  1926. this.parent = parent;
  1927. }
  1928.  
  1929. startDrawing() {
  1930. this.BotClientManager = this.parent.findGlobal("BotClientManager")?.siblings[0];
  1931. this.isRunning = true;
  1932. this.doTasks();
  1933. this.parent.notify("info", "Started");
  1934. }
  1935.  
  1936. stopDrawing() {
  1937. this.isRunning = false;
  1938. }
  1939.  
  1940. doTasks() {
  1941. if (!this.BotClientManager || this.BotClientManager.children.length <= 0) this.stopDrawing();
  1942. if (!this.isRunning) return this.parent.notify("info", "Stopped");
  1943.  
  1944. this.BotClientManager.children.forEach((botClientInterface, index) => {
  1945. this.parseAndSendPixel(botClientInterface, index);
  1946. });
  1947.  
  1948. setTimeout(() => {
  1949. this.doTasks();
  1950. }, 1);
  1951. }
  1952.  
  1953. parseAndSendPixel(botClientInterface, index) {
  1954. if (this.pixelList.length <= 0) return this.stopDrawing();
  1955. if (!botClientInterface.bot || !botClientInterface.bot.getReadyState()) return;
  1956.  
  1957. const task = index % 2 == 0 ? this.pixelList.shift() : this.pixelList.pop();
  1958. botClientInterface.bot.send(this.convertTasks(task));
  1959. this.parent.htmlElements.pixelsLeftToDraw.value = this.pixelList.length;
  1960. }
  1961.  
  1962. convertTasks(pixel) {
  1963. const playerid = -1;
  1964. const lastx = pixel.x1 * this.parent.DrawCanvasRect.drawModifierX;
  1965. const lasty = pixel.y1 * this.parent.DrawCanvasRect.drawModifierY;
  1966. const x = pixel.x2 * this.parent.DrawCanvasRect.drawModifierX;
  1967. const y = pixel.y2 * this.parent.DrawCanvasRect.drawModifierY;
  1968. const isactive = !0;
  1969. const size = pixel.size ?? this.brushSize;
  1970. const pxColor = pixel.color;
  1971. const color = this.singleColor
  1972. ? this.brushColor
  1973. : `rgba(${pxColor[0]},${pxColor[1]},${pxColor[2]},${parseFloat(pxColor[3] * 0.390625).toFixed(2)})`;
  1974. const ispixel = !1;
  1975.  
  1976. let data = [
  1977. "drawcmd",
  1978. 0,
  1979. [lastx * 0.01, lasty * 0.01, x * 0.01, y * 0.01, isactive, -size, color, playerid, ispixel],
  1980. ];
  1981.  
  1982. return `${42}${JSON.stringify(data)}`;
  1983. }
  1984. }
  1985. })("QBit");
  1986.  
  1987. (function GhostCanvasAlgorithms() {
  1988. const QBit = globalThis[arguments[0]];
  1989.  
  1990. function sortByColor(pixel1, pixel2) {
  1991. const color1 = rgbaArrayToHex(pixel1.color);
  1992. const color2 = rgbaArrayToHex(pixel2.color);
  1993. if (color1 < color2) {
  1994. return -1;
  1995. }
  1996. if (color1 > color2) {
  1997. return 1;
  1998. }
  1999. return 0;
  2000. }
  2001.  
  2002. function intToHex(number) {
  2003. return number.toString(16).padStart(2, "0");
  2004. }
  2005.  
  2006. function rgbaArrayToHex(rgbaArray) {
  2007. const r = intToHex(rgbaArray[0]);
  2008. const g = intToHex(rgbaArray[1]);
  2009. const b = intToHex(rgbaArray[2]);
  2010. const a = intToHex(rgbaArray[3]);
  2011. return "#" + r + g + b + a;
  2012. }
  2013.  
  2014. function areSameColor(colorArray1, colorArray2, allowedDifference = 8) {
  2015. var red = colorArray1[0] - colorArray2[0];
  2016. var green = colorArray1[1] - colorArray2[1];
  2017. var blue = colorArray1[2] - colorArray2[2];
  2018.  
  2019. if (red < 0) red = red * -1;
  2020. if (green < 0) green = green * -1;
  2021. if (blue < 0) blue = blue * -1;
  2022.  
  2023. if (red > allowedDifference || green > allowedDifference || blue > allowedDifference) return false;
  2024. return true;
  2025. }
  2026.  
  2027. class GhostCanvasMinify extends QBit {
  2028. static dummy1 = QBit.register(this);
  2029. static dummy2 = QBit.bind(this, "GhostCanvas");
  2030.  
  2031. constructor() {
  2032. super("Minify", '<i class="fas fa-compress-arrows-alt"></i>');
  2033. this.minOpacity = 20;
  2034. this.maxFuzzyness = 32;
  2035. this.#onStartup();
  2036. }
  2037.  
  2038. #onStartup() {
  2039. this.#loadInterface();
  2040. }
  2041.  
  2042. #loadInterface() {
  2043. this.#row1();
  2044. this.#row2();
  2045. this.#row3();
  2046. this.#row4();
  2047. }
  2048.  
  2049. #row1() {
  2050. const row = domMake.Row();
  2051. {
  2052. const fuzzynessInput = domMake.Tree("input", {
  2053. type: "number",
  2054. title: "Fuzzyness",
  2055. step: 1,
  2056. min: 0,
  2057. max: 255,
  2058. value: 10,
  2059. });
  2060. const opacityInput = domMake.Tree("input", {
  2061. type: "number",
  2062. title: "Opacity",
  2063. step: 1,
  2064. min: 0,
  2065. max: 255,
  2066. value: 30,
  2067. });
  2068.  
  2069. fuzzynessInput.addEventListener("change", () => {
  2070. this.maxFuzzyness = Number(fuzzynessInput.value);
  2071. });
  2072.  
  2073. opacityInput.addEventListener("change", () => {
  2074. this.minOpacity = Number(opacityInput.value);
  2075. });
  2076.  
  2077. row.appendAll(fuzzynessInput, opacityInput);
  2078. }
  2079. this.htmlElements.section.appendChild(row);
  2080. }
  2081. #row2() {
  2082. const row = domMake.Row();
  2083. {
  2084. const minifyPixelsArrayButton = domMake.Button("Minify");
  2085.  
  2086. minifyPixelsArrayButton.addEventListener("click", (event) => {
  2087. this.minifyPixelsArray();
  2088. });
  2089.  
  2090. row.appendAll(minifyPixelsArrayButton);
  2091. }
  2092. this.htmlElements.section.appendChild(row);
  2093. }
  2094. #row3() {}
  2095. #row4() {}
  2096.  
  2097. minifyPixelsArray() {
  2098. const pixelArray = this.parent.drawingManager.pixelList;
  2099. const newPixelArray = [];
  2100.  
  2101. let currentPixel = pixelArray[0];
  2102. let lastPixel = currentPixel;
  2103. let currentLine = currentPixel;
  2104.  
  2105. for (let index = 0; index < pixelArray.length; index++) {
  2106. currentPixel = pixelArray[index];
  2107.  
  2108. if (lastPixel.color[3] < 10 && currentPixel.color[3] >= 10) {
  2109. // From Transparent To Solid
  2110.  
  2111. currentLine = currentPixel;
  2112. } else if (lastPixel.color[3] >= 10 && currentPixel.color[3] < 10) {
  2113. // From Solid To Transparent
  2114.  
  2115. currentLine.x2 = lastPixel.x2;
  2116. newPixelArray.push(currentLine);
  2117. currentLine = currentPixel;
  2118. } else if (currentPixel.color[3] >= 10 && lastPixel.color[3] >= 10) {
  2119. // From Solid To Solid
  2120.  
  2121. if (
  2122. currentLine.y1 !== currentPixel.y1 ||
  2123. lastPixel.x2 !== currentPixel.x1 - 1 ||
  2124. !areSameColor(lastPixel.color, currentPixel.color, this.maxFuzzyness)
  2125. ) {
  2126. currentLine.x2 = lastPixel.x2;
  2127. newPixelArray.push(currentLine);
  2128. currentLine = currentPixel;
  2129. }
  2130. } else {
  2131. // From Transparent To Transparent
  2132. }
  2133.  
  2134. lastPixel = currentPixel;
  2135. }
  2136. // if (currentLine.color[3] >= 10) newPixelArray.push(currentLine);
  2137.  
  2138. this.parent.setPixelList(newPixelArray);
  2139. }
  2140.  
  2141. minifyPixelsArray_alt() {
  2142. const pixelArray = this.parent.drawingManager.pixelList;
  2143. const newPixelArray = [];
  2144. var lastPixel = pixelArray[0];
  2145. var currentLine = lastPixel;
  2146. const stepsize = this.parent.stepsize ?? 1;
  2147.  
  2148. for (let i = 0; i < pixelArray.length; i += stepsize) {
  2149. const currentPixel = pixelArray[i];
  2150.  
  2151. if (currentPixel.y1 !== currentLine.y1 || currentPixel.color !== lastPixel.color) {
  2152. currentLine.x2 = lastPixel.x2;
  2153. if (!/^#[0-9a-fA-F]{6}[0-4]{2}$/.test(lastPixel.color)) newPixelArray.push(currentLine);
  2154. currentLine = currentPixel;
  2155. }
  2156.  
  2157. lastPixel = currentPixel;
  2158. }
  2159. newPixelArray.push(currentLine);
  2160.  
  2161. this.parent.setPixelList(newPixelArray);
  2162. }
  2163. }
  2164.  
  2165. class GhostCanvasSort extends QBit {
  2166. static dummy1 = QBit.register(this);
  2167. static dummy2 = QBit.bind(this, "GhostCanvas");
  2168.  
  2169. constructor() {
  2170. super("Sort", '<i class="fas fa-sort-numeric-down"></i>');
  2171. this.#onStartup();
  2172. }
  2173.  
  2174. #onStartup() {
  2175. this.#loadInterface();
  2176. }
  2177.  
  2178. #loadInterface() {
  2179. this.#row1();
  2180. this.#row2();
  2181. this.#row3();
  2182. this.#row4();
  2183. }
  2184.  
  2185. #row1() {
  2186. const row = domMake.Row();
  2187. {
  2188. const sortPixelsArrayButton = domMake.Button("Sort");
  2189.  
  2190. sortPixelsArrayButton.addEventListener("click", (event) => {
  2191. this.sortPixelsArray();
  2192. });
  2193.  
  2194. row.appendAll(sortPixelsArrayButton);
  2195. }
  2196. this.htmlElements.section.appendChild(row);
  2197. }
  2198. #row2() {}
  2199. #row3() {}
  2200. #row4() {}
  2201.  
  2202. sortPixelsArray() {
  2203. const pixelArray = this.parent.drawingManager.pixelList;
  2204.  
  2205. const newPixelArray = [...pixelArray].sort(sortByColor);
  2206.  
  2207. this.parent.setPixelList(newPixelArray);
  2208. }
  2209. }
  2210. })("QBit");
  2211.  
  2212. (function BotClientInterface() {
  2213. const QBit = globalThis[arguments[0]];
  2214. const BotClient = QBit.findGlobal("BotClient");
  2215.  
  2216. let botcount = 0;
  2217. const radios = [];
  2218.  
  2219. function getMasterId() {
  2220. return document.querySelector(".playerlist-name-self")?.parentElement.dataset.playerid || 0;
  2221. }
  2222.  
  2223. function parseAvatarURL(arr = []) {
  2224. return `https://drawaria.online/avatar/cache/${arr.length > 0 ? arr.join(".") : "default"}.jpg`;
  2225. }
  2226.  
  2227. class BotClientManager extends QBit {
  2228. static dummy1 = QBit.register(this);
  2229. static dummy2 = QBit.bind(this, "CubeEngine");
  2230.  
  2231. constructor() {
  2232. super(`BotClientManager`, '<i class="fas fa-robot"></i>');
  2233. this.#onStartup();
  2234. }
  2235.  
  2236. #onStartup() {
  2237. this.#loadInterface();
  2238. }
  2239.  
  2240. #loadInterface() {
  2241. this.#row1();
  2242. }
  2243.  
  2244. #row1() {
  2245. const row = domMake.IconList();
  2246. {
  2247. const id = generate.uuidv4();
  2248. const createBotClientInterfaceInput = domMake.Tree("input", { type: "button", id: id, hidden: true });
  2249. const createBotClientInterfaceLabel = domMake.Tree("label", { for: id, class: "icon", title: "Add Image" }, [
  2250. domMake.Tree("i", { class: "fas fa-plus" }),
  2251. ]);
  2252.  
  2253. createBotClientInterfaceInput.addEventListener("click", () => {
  2254. this.createBotClientInterface();
  2255. });
  2256.  
  2257. row.appendAll(createBotClientInterfaceLabel);
  2258. row.appendAll(createBotClientInterfaceInput);
  2259. }
  2260. {
  2261. const id = generate.uuidv4();
  2262. const removeBotClientInterfaceInput = domMake.Tree("input", { type: "button", id: id, hidden: true });
  2263. const removeBotClientInterfaceLabel = domMake.Tree("label", { for: id, class: "icon", title: "Add Image" }, [
  2264. domMake.Tree("i", { class: "fas fa-minus" }),
  2265. ]);
  2266.  
  2267. removeBotClientInterfaceInput.addEventListener("click", () => {
  2268. this.deleteBotClientInterface();
  2269. });
  2270.  
  2271. row.appendAll(removeBotClientInterfaceLabel);
  2272. row.appendAll(removeBotClientInterfaceInput);
  2273. }
  2274. this.htmlElements.header.before(row);
  2275. }
  2276.  
  2277. createBotClientInterface() {
  2278. const instance = this.loadExtension(BotClientInterface);
  2279. instance.htmlElements.input.type = "radio";
  2280. instance.htmlElements.input.name = "botClient";
  2281.  
  2282. radios.push(instance.htmlElements.input);
  2283. instance.htmlElements.input.addEventListener("change", (event) => {
  2284. radios.forEach(function (radio) {
  2285. document.body.querySelector(`label[for="${radio.id}"]`).classList.remove("active");
  2286. });
  2287. instance.htmlElements.label.classList.add("active");
  2288. });
  2289.  
  2290. return instance;
  2291. }
  2292.  
  2293. deleteBotClientInterface() {
  2294. const input = document.body.querySelector(`input[name="botClient"]:checked`);
  2295.  
  2296. const matches = this.children.filter((child) => {
  2297. return child.htmlElements.input === input;
  2298. });
  2299. if (matches.length <= 0) return;
  2300.  
  2301. const instance = matches[0];
  2302.  
  2303. instance.bot.disconnect();
  2304.  
  2305. const labelPos = radios.indexOf(instance.htmlElements.input);
  2306. if (~labelPos) radios.splice(labelPos, 1);
  2307.  
  2308. instance._EXP_destroy(!0);
  2309. }
  2310. }
  2311.  
  2312. class BotClientInterface extends QBit {
  2313. static dummy1 = QBit.register(this);
  2314. // static dummy2 = QBit.bind(this, 'CubeEngine');
  2315. // static dummy3 = QBit.bind(this, 'CubeEngine');
  2316.  
  2317. constructor() {
  2318. super(`Bot${botcount}`, '<i class="fas fa-robot"></i>');
  2319. this.bot = new BotClient();
  2320. this.#onStartup();
  2321. }
  2322.  
  2323. #onStartup() {
  2324. this.#loadInterface();
  2325. this.setClientName(this.bot.name);
  2326. this.setClientIcon(this.bot.avatar);
  2327. }
  2328.  
  2329. #loadInterface() {
  2330. this.#row1();
  2331. }
  2332.  
  2333. #row1() {
  2334. const row = domMake.Row();
  2335. {
  2336. let join_button = domMake.Button("Enter");
  2337. let leave_button = domMake.Button("Leave");
  2338.  
  2339. join_button.addEventListener("click", (event) => {
  2340. this.bot.enterRoom(document.querySelector("#invurl").value);
  2341. });
  2342.  
  2343. leave_button.addEventListener("click", (event) => {
  2344. this.bot.disconnect();
  2345. });
  2346.  
  2347. row.appendAll(join_button, leave_button);
  2348. }
  2349. this.htmlElements.section.appendChild(row);
  2350. }
  2351.  
  2352. setClientName(name) {
  2353. this.setName(name);
  2354. this.bot.name = name;
  2355. }
  2356.  
  2357. setClientIcon(icon) {
  2358. this.setIcon(`<img src="${parseAvatarURL(this.bot.avatar)}">`);
  2359. this.bot.avatar = icon;
  2360. }
  2361. }
  2362. })("QBit");
  2363.  
  2364. (function BotClientInteractions() {
  2365. const QBit = globalThis[arguments[0]];
  2366.  
  2367. class BotPersonality extends QBit {
  2368. static dummy1 = QBit.register(this);
  2369. static dummy2 = QBit.bind(this, "BotClientInterface");
  2370.  
  2371. constructor() {
  2372. super("Personality", '<i class="fas fa-user-cog"></i>');
  2373. this.#onStartup();
  2374. }
  2375.  
  2376. #onStartup() {
  2377. this.#loadInterface();
  2378. }
  2379.  
  2380. #loadInterface() {
  2381. this.#row1();
  2382. this.#row2();
  2383. }
  2384.  
  2385. #row1() {
  2386. const row = domMake.Row();
  2387. {
  2388. let botName = domMake.Tree("input", { type: "text", placeholder: "Your Bots name" });
  2389. let botNameAccept = domMake.Tree("button", { class: "icon" }, [domMake.Tree("i", { class: "fas fa-check" })]);
  2390.  
  2391. botNameAccept.addEventListener("click", (event) => {
  2392. this.parent.setClientName(botName.value);
  2393. });
  2394.  
  2395. row.appendAll(botName, botNameAccept);
  2396. }
  2397. this.htmlElements.section.appendChild(row);
  2398. }
  2399.  
  2400. #row2() {
  2401. let id = generate.uuidv4();
  2402. const row = domMake.Row();
  2403. {
  2404. let botAvatarUpload = domMake.Tree("input", { type: "file", id: id, hidden: true });
  2405. let botAvatarAccept = domMake.Tree("label", { for: id, class: "btn btn-outline-secondary" }, [
  2406. "Upload BotAvatar",
  2407. ]);
  2408.  
  2409. const localThis = this;
  2410. function onChange() {
  2411. if (!this.files || !this.files[0]) return;
  2412. let myFileReader = new FileReader();
  2413. myFileReader.addEventListener("load", (e) => {
  2414. let a = e.target.result.replace("image/gif", "image/png");
  2415. fetch("https://drawaria.online/uploadavatarimage", {
  2416. method: "POST",
  2417. body: "imagedata=" + encodeURIComponent(a) + "&fromeditor=true",
  2418. headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
  2419. }).then((res) =>
  2420. res.text().then((body) => {
  2421. localThis.parent.setClientIcon(body.split("."));
  2422. })
  2423. );
  2424. });
  2425. myFileReader.readAsDataURL(this.files[0]);
  2426. }
  2427. botAvatarUpload.addEventListener("change", onChange);
  2428.  
  2429. row.appendAll(botAvatarUpload, botAvatarAccept);
  2430. }
  2431. this.htmlElements.section.appendChild(row);
  2432. }
  2433. }
  2434.  
  2435. class BotSozials extends QBit {
  2436. static dummy1 = QBit.register(this);
  2437. static dummy2 = QBit.bind(this, "BotClientInterface");
  2438.  
  2439. constructor() {
  2440. super("Socialize", '<i class="fas fa-comment-dots"></i>');
  2441. this.#onStartup();
  2442. }
  2443.  
  2444. #onStartup() {
  2445. this.#loadInterface();
  2446. }
  2447.  
  2448. #loadInterface() {
  2449. this.#row1();
  2450. this.#row2();
  2451. }
  2452.  
  2453. #row1() {
  2454. const row = domMake.Row();
  2455. {
  2456. let messageClear_button = domMake.Button('<i class="fas fa-strikethrough"></i>');
  2457. let messageSend_button = domMake.Button('<i class="fas fa-paper-plane"></i>');
  2458. let message_input = domMake.Tree("input", { type: "text", placeholder: "message..." });
  2459.  
  2460. messageClear_button.classList.add("icon");
  2461. messageSend_button.classList.add("icon");
  2462.  
  2463. messageClear_button.addEventListener("click", (event) => {
  2464. message_input.value = "";
  2465. });
  2466.  
  2467. messageSend_button.addEventListener("click", (event) => {
  2468. this.parent.bot.emit("chatmsg", message_input.value);
  2469. });
  2470.  
  2471. message_input.addEventListener("keypress", (event) => {
  2472. if (event.keyCode != 13) return;
  2473. this.parent.bot.emit("chatmsg", message_input.value);
  2474. });
  2475.  
  2476. row.appendAll(messageClear_button, message_input, messageSend_button);
  2477. }
  2478. this.htmlElements.section.appendChild(row);
  2479. }
  2480.  
  2481. #row2() {
  2482. const row = domMake.IconList();
  2483. // row.classList.add('nowrap');
  2484. {
  2485. document
  2486. .querySelectorAll("#gesturespickerselector .gesturespicker-container .gesturespicker-item")
  2487. .forEach((node, index) => {
  2488. let clone = node.cloneNode(true);
  2489. clone.classList.add("icon");
  2490. clone.addEventListener("click", (event) => {
  2491. this.parent.bot.emit("sendgesture", index);
  2492. });
  2493. row.appendChild(clone);
  2494. });
  2495. }
  2496. this.htmlElements.section.appendChild(row);
  2497. }
  2498. }
  2499.  
  2500. class BotTokenGiver extends QBit {
  2501. static dummy1 = QBit.register(this);
  2502. static dummy2 = QBit.bind(this, "BotClientInterface");
  2503.  
  2504. constructor() {
  2505. super("Tokken", '<i class="fas fa-thumbs-up"></i>');
  2506. this.#onStartup();
  2507. }
  2508.  
  2509. #onStartup() {
  2510. this.#loadInterface();
  2511. }
  2512.  
  2513. #loadInterface() {
  2514. this.#row1();
  2515. this.#row2();
  2516. }
  2517.  
  2518. #row1() {
  2519. const row = domMake.IconList();
  2520. // row.classList.add('nowrap');
  2521. {
  2522. let listOfTokens = [
  2523. '<i class="fas fa-thumbs-up"></i>',
  2524. '<i class="fas fa-heart"></i>',
  2525. '<i class="fas fa-paint-brush"></i>',
  2526. '<i class="fas fa-cocktail"></i>',
  2527. '<i class="fas fa-hand-peace"></i>',
  2528. '<i class="fas fa-feather-alt"></i>',
  2529. '<i class="fas fa-trophy"></i>',
  2530. '<i class="fas fa-mug-hot"></i>',
  2531. '<i class="fas fa-gift"></i>',
  2532. ];
  2533. listOfTokens.forEach((token, index) => {
  2534. let tokenSend_button = domMake.Button(token);
  2535. tokenSend_button.classList.add("icon");
  2536. tokenSend_button.addEventListener("click", () => {
  2537. this.parent.bot.room.players.forEach((player) => {
  2538. this.parent.bot.emit("settoken", player.id, index);
  2539. });
  2540. });
  2541. row.appendChild(tokenSend_button);
  2542. });
  2543. }
  2544. this.htmlElements.section.appendChild(row);
  2545. }
  2546.  
  2547. #row2() {
  2548. const row = domMake.Row();
  2549. {
  2550. let toggleStatus_button = domMake.Button("Toggle Status");
  2551. toggleStatus_button.addEventListener("click", () => {
  2552. this.parent.bot.attributes.status = !this.parent.bot.attributes.status;
  2553. let status = this.parent.bot.attributes.status;
  2554. toggleStatus_button.classList[status ? "add" : "remove"]("active");
  2555. this.parent.bot.emit("setstatusflag", 0, status);
  2556. this.parent.bot.emit("setstatusflag", 1, status);
  2557. this.parent.bot.emit("setstatusflag", 2, status);
  2558. this.parent.bot.emit("setstatusflag", 3, status);
  2559. this.parent.bot.emit("setstatusflag", 4, status);
  2560. });
  2561. row.appendChild(toggleStatus_button);
  2562. }
  2563. this.htmlElements.section.appendChild(row);
  2564. }
  2565. }
  2566.  
  2567. class BotCanvasAvatar extends QBit {
  2568. static dummy1 = QBit.register(this);
  2569. static dummy2 = QBit.bind(this, "BotClientInterface");
  2570.  
  2571. constructor() {
  2572. super("SpawnAvatar", '<i class="fas fa-user-circle"></i>');
  2573. this.#onStartup();
  2574. }
  2575.  
  2576. #onStartup() {
  2577. this.#loadInterface();
  2578. }
  2579.  
  2580. #loadInterface() {
  2581. this.#row1();
  2582. }
  2583.  
  2584. #row1() {
  2585. const row = domMake.Row();
  2586. {
  2587. // Spawn && Move Avatar
  2588. let avatarPosition = { x: 0, y: 0 };
  2589.  
  2590. let avatarSpawn_button = domMake.Button('<i class="fas fa-exchange-alt"></i>');
  2591. let avatarChange_button = domMake.Button('<i class="fas fa-retweet"></i>');
  2592. let avatarPositionX_button = domMake.Tree("input", {
  2593. type: "number",
  2594. value: 2,
  2595. min: 2,
  2596. max: 98,
  2597. title: "Left",
  2598. });
  2599. let avatarPositionY_button = domMake.Tree("input", {
  2600. type: "number",
  2601. value: 2,
  2602. min: 2,
  2603. max: 98,
  2604. title: "Top",
  2605. });
  2606.  
  2607. avatarSpawn_button.addEventListener("click", (event) => {
  2608. this.parent.bot.emit("spawnavatar");
  2609. this.parent.bot.attributes.spawned = !this.parent.bot.attributes.spawned;
  2610. });
  2611.  
  2612. avatarChange_button.addEventListener("click", (event) => {
  2613. this.parent.bot.emit("setavatarprop");
  2614. this.parent.bot.attributes.rounded = !this.parent.bot.attributes.rounded;
  2615. });
  2616.  
  2617. avatarPositionX_button.addEventListener("change", (event) => {
  2618. avatarPosition.x = avatarPositionX_button.value;
  2619. this.parent.bot.emit("moveavatar", avatarPosition.x, avatarPosition.y);
  2620. });
  2621.  
  2622. avatarPositionY_button.addEventListener("change", (event) => {
  2623. avatarPosition.y = avatarPositionY_button.value;
  2624. this.parent.bot.emit("moveavatar", avatarPosition.x, avatarPosition.y);
  2625. });
  2626.  
  2627. avatarSpawn_button.title = "Spawn Avatar";
  2628. avatarChange_button.title = "Toggle Round Avatar";
  2629.  
  2630. row.appendAll(avatarSpawn_button, avatarPositionX_button, avatarPositionY_button, avatarChange_button);
  2631. }
  2632. this.htmlElements.section.appendChild(row);
  2633. }
  2634. }
  2635.  
  2636. function getMyId() {
  2637. return document.querySelector(".playerlist-name-this")?.parentElement.dataset.playerid || 0;
  2638. }
  2639.  
  2640. function parseAvatarURL(arr = []) {
  2641. return `https://drawaria.online/avatar/cache/${arr.length > 0 ? arr.join(".") : "default"}.jpg`;
  2642. }
  2643. })("QBit");
  2644.  
  2645. (function AutoTranslate() {
  2646. const QBit = globalThis[arguments[0]];
  2647.  
  2648. const unicodeLanguagePatterns = new Map();
  2649. unicodeLanguagePatterns.set("Common", /\p{Script=Common}+/u); // CommonPattern
  2650. unicodeLanguagePatterns.set("Arabic", /\p{Script=Arabic}+/u); // ArabicPattern
  2651. unicodeLanguagePatterns.set("Armenian", /\p{Script=Armenian}+/u); // ArmenianPattern
  2652. unicodeLanguagePatterns.set("Bengali", /\p{Script=Bengali}+/u); // BengaliPattern
  2653. unicodeLanguagePatterns.set("Bopomofo", /\p{Script=Bopomofo}+/u); // BopomofoPattern
  2654. unicodeLanguagePatterns.set("Braille", /\p{Script=Braille}+/u); // BraillePattern
  2655. unicodeLanguagePatterns.set("Buhid", /\p{Script=Buhid}+/u); // BuhidPattern
  2656. unicodeLanguagePatterns.set("Canadian_Aboriginal", /\p{Script=Canadian_Aboriginal}+/u); // Canadian_AboriginalPattern
  2657. unicodeLanguagePatterns.set("Cherokee", /\p{Script=Cherokee}+/u); // CherokeePattern
  2658. unicodeLanguagePatterns.set("Cyrillic", /\p{Script=Cyrillic}+/u); // CyrillicPattern
  2659. unicodeLanguagePatterns.set("Devanagari", /\p{Script=Devanagari}+/u); // DevanagariPattern
  2660. unicodeLanguagePatterns.set("Ethiopic", /\p{Script=Ethiopic}+/u); // EthiopicPattern
  2661. unicodeLanguagePatterns.set("Georgian", /\p{Script=Georgian}+/u); // GeorgianPattern
  2662. unicodeLanguagePatterns.set("Greek", /\p{Script=Greek}+/u); // GreekPattern
  2663. unicodeLanguagePatterns.set("Gujarati", /\p{Script=Gujarati}+/u); // GujaratiPattern
  2664. unicodeLanguagePatterns.set("Gurmukhi", /\p{Script=Gurmukhi}+/u); // GurmukhiPattern
  2665. unicodeLanguagePatterns.set("Han", /\p{Script=Han}+/u); // HanPattern
  2666. unicodeLanguagePatterns.set("Hangul", /\p{Script=Hangul}+/u); // HangulPattern
  2667. unicodeLanguagePatterns.set("Hanunoo", /\p{Script=Hanunoo}+/u); // HanunooPattern
  2668. unicodeLanguagePatterns.set("Hebrew", /\p{Script=Hebrew}+/u); // HebrewPattern
  2669. unicodeLanguagePatterns.set("Hiragana", /\p{Script=Hiragana}+/u); // HiraganaPattern
  2670. unicodeLanguagePatterns.set("Inherited", /\p{Script=Inherited}+/u); // InheritedPattern
  2671. unicodeLanguagePatterns.set("Kannada", /\p{Script=Kannada}+/u); // KannadaPattern
  2672. unicodeLanguagePatterns.set("Katakana", /\p{Script=Katakana}+/u); // KatakanaPattern
  2673. unicodeLanguagePatterns.set("Khmer", /\p{Script=Khmer}+/u); // KhmerPattern
  2674. unicodeLanguagePatterns.set("Lao", /\p{Script=Lao}+/u); // LaoPattern
  2675. unicodeLanguagePatterns.set("Latin", /\p{Script=Latin}+/u); // LatinPattern
  2676. unicodeLanguagePatterns.set("Limbu", /\p{Script=Limbu}+/u); // LimbuPattern
  2677. unicodeLanguagePatterns.set("Malayalam", /\p{Script=Malayalam}+/u); // MalayalamPattern
  2678. unicodeLanguagePatterns.set("Mongolian", /\p{Script=Mongolian}+/u); // MongolianPattern
  2679. unicodeLanguagePatterns.set("Myanmar", /\p{Script=Myanmar}+/u); // MyanmarPattern
  2680. unicodeLanguagePatterns.set("Ogham", /\p{Script=Ogham}+/u); // OghamPattern
  2681. unicodeLanguagePatterns.set("Oriya", /\p{Script=Oriya}+/u); // OriyaPattern
  2682. unicodeLanguagePatterns.set("Runic", /\p{Script=Runic}+/u); // RunicPattern
  2683. unicodeLanguagePatterns.set("Sinhala", /\p{Script=Sinhala}+/u); // SinhalaPattern
  2684. unicodeLanguagePatterns.set("Syriac", /\p{Script=Syriac}+/u); // SyriacPattern
  2685. unicodeLanguagePatterns.set("Tagalog", /\p{Script=Tagalog}+/u); // TagalogPattern
  2686. unicodeLanguagePatterns.set("Tagbanwa", /\p{Script=Tagbanwa}+/u); // TagbanwaPattern
  2687. unicodeLanguagePatterns.set("Tamil", /\p{Script=Tamil}+/u); // TamilPattern
  2688. unicodeLanguagePatterns.set("Telugu", /\p{Script=Telugu}+/u); // TeluguPattern
  2689. unicodeLanguagePatterns.set("Thaana", /\p{Script=Thaana}+/u); // ThaanaPattern
  2690. unicodeLanguagePatterns.set("Thai", /\p{Script=Thai}+/u); // ThaiPattern
  2691. unicodeLanguagePatterns.set("Tibetan", /\p{Script=Tibetan}+/u); // TibetanPattern
  2692. unicodeLanguagePatterns.set("Yi", /\p{Script=Yi}+/u); // YiPattern
  2693.  
  2694. const observeDOM = (function () {
  2695. const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
  2696. /**
  2697. * @param {HTMLElement} nodeToObserve
  2698. * @param {Function} callback
  2699. */
  2700. return function (nodeToObserve, callback) {
  2701. if (!nodeToObserve || nodeToObserve.nodeType !== 1) return;
  2702.  
  2703. if (MutationObserver) {
  2704. // define a new observer
  2705. var mutationObserver = new MutationObserver(callback);
  2706.  
  2707. // have the observer observe for changes in children
  2708. mutationObserver.observe(nodeToObserve, { childList: true, subtree: !1 });
  2709. return mutationObserver;
  2710. }
  2711.  
  2712. // browser support fallback
  2713. else if (window.addEventListener) {
  2714. nodeToObserve.addEventListener("DOMNodeInserted", callback, false);
  2715. nodeToObserve.addEventListener("DOMNodeRemoved", callback, false);
  2716. }
  2717. };
  2718. })();
  2719.  
  2720. class AutoTranslate extends QBit {
  2721. static dummy1 = QBit.register(this);
  2722. static dummy2 = QBit.bind(this, "CubeEngine");
  2723.  
  2724. active;
  2725.  
  2726. constructor() {
  2727. super("AutoTranslate", '<i class="fas fa-language"></i>');
  2728. this.#onStartup();
  2729. }
  2730.  
  2731. #onStartup() {
  2732. this.#loadInterface();
  2733.  
  2734. this.active = false;
  2735.  
  2736. const observable = document.querySelector("#chatbox_messages");
  2737.  
  2738. observeDOM(observable, (mutation) => {
  2739. if (!this.active) return;
  2740.  
  2741. const addedNodes = [];
  2742. const removedNodes = [];
  2743.  
  2744. mutation.forEach((record) => record.addedNodes.length & addedNodes.push(...record.addedNodes));
  2745. mutation.forEach((record) => record.removedNodes.length & removedNodes.push(...record.removedNodes));
  2746.  
  2747. // console.log('Added:', addedNodes, 'Removed:', removedNodes);
  2748.  
  2749. addedNodes.forEach((node) => {
  2750. if (node.classList.contains("systemchatmessage5")) return;
  2751. if (node.querySelector(".playerchatmessage-selfname")) return;
  2752. if (!node.querySelector(".playerchatmessage-text")) return;
  2753.  
  2754. // console.log(node);
  2755. const message = node.querySelector(".playerchatmessage-text");
  2756. const text = message.textContent;
  2757. const language = this.detectLanguage(text);
  2758.  
  2759. if (language)
  2760. this.translate(text, language, "en", (translation) => {
  2761. applyTitleToChatMessage(translation, message);
  2762. });
  2763. });
  2764.  
  2765. function applyTitleToChatMessage(text, node) {
  2766. node.title = text;
  2767. }
  2768. });
  2769. }
  2770.  
  2771. #loadInterface() {
  2772. this.#row1();
  2773. this.#row2();
  2774. }
  2775.  
  2776. #row1() {
  2777. const row = domMake.Row();
  2778. {
  2779. const enableButton = domMake.Button("Enable");
  2780.  
  2781. enableButton.addEventListener("click", (event) => {
  2782. this.active ? this.disable() : this.enable();
  2783. });
  2784. row.appendChild(enableButton);
  2785. this.htmlElements.toggleStatusButton = enableButton;
  2786. }
  2787. this.htmlElements.section.appendChild(row);
  2788. }
  2789.  
  2790. #row2() {}
  2791.  
  2792. enable() {
  2793. this.active = true;
  2794.  
  2795. this.htmlElements.toggleStatusButton.classList.add("active");
  2796. this.htmlElements.toggleStatusButton.textContent = "Active";
  2797.  
  2798. this.notify("success", `enabled`);
  2799. }
  2800.  
  2801. disable() {
  2802. this.active = false;
  2803.  
  2804. this.htmlElements.toggleStatusButton.classList.remove("active");
  2805. this.htmlElements.toggleStatusButton.textContent = "Inactive";
  2806.  
  2807. this.notify("warning", `disabled`);
  2808. }
  2809.  
  2810. detectLanguage(text) {
  2811. if (unicodeLanguagePatterns.get("Cyrillic").test(text)) return "ru";
  2812. if (unicodeLanguagePatterns.get("Arabic").test(text)) return "ar";
  2813. if (unicodeLanguagePatterns.get("Greek").test(text)) return "el";
  2814. }
  2815.  
  2816. translate(textToTranslate, from = "ru", to = "en", callback) {
  2817. const sourceText = textToTranslate;
  2818. const sourceLang = from;
  2819. const targetLang = to;
  2820.  
  2821. const url =
  2822. "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" +
  2823. sourceLang +
  2824. "&tl=" +
  2825. targetLang +
  2826. "&dt=t&q=" +
  2827. encodeURI(sourceText);
  2828.  
  2829. xhrGetJson(url, log);
  2830.  
  2831. function log(data) {
  2832. callback(data[0][0][0]);
  2833. }
  2834. }
  2835. }
  2836.  
  2837. function xhrGetJson(url, callback) {
  2838. const req = new XMLHttpRequest();
  2839.  
  2840. req.onload = (e) => {
  2841. const response = req.response; // not responseText
  2842. if (!callback) return;
  2843. try {
  2844. callback(JSON.parse(response));
  2845. } catch (error) {
  2846. console.log(error);
  2847. }
  2848. };
  2849. req.open("GET", url);
  2850. req.send();
  2851. }
  2852. })("QBit");
  2853. })();