BotPlayer

An SubModule for the Definable ModMenu for Drawaria.Online.

  1. // ==UserScript==
  2. // @name BotPlayer
  3. // @namespace Definable
  4. // @version 0.1.1
  5. // @description An SubModule for the Definable ModMenu for Drawaria.Online.
  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 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGRSURBVHhe7dkxbsJAEAXQP3ZJwyWQLOUENKGg5xYRR+AMHAHlFvQUpOEEkSxxCRpKPGmwlIyUxesMMWj+65g12vXXsGsAICIioqjEFqzJZKLfXx+Pxx/vsePW0NfbcauwhWgYgC0QEUWSPCPR41wdWu56w58CyXSQmehsU1eNXNYA5iIY2fG/UMUZwK7QcrVfVrUdb+WsF54dcL35gwgW3jcPACIYiWDRyOUw29SVHe/LLYBGLmsRjG3dmwjG1y5z4RYAgLkt3JHbXG4B3KPtf+M5l1sAzyq5Q+Z4ff9Mfm/39vH24rL28B3AAGwhmpufo65PVo+yB3Rdbyt8BzAAW4iGAdhCNAzAFqJJnpE5HuU5IFf4DmAAthDNzc9R12frR9kDuq63Fb4D3AK4/m7/LzzncgsAwM4W7shtLrcACi1XqjjZujdVnAotV7bel1sA+2VVF1pOVbH1bNGWKs6q2BZaTlN/jeVK7pDosasOLXe9bh1ARPSMkjskOuyqdtwa+no7boU/BRiALRARERFF8QWXXJ5ITbASawAAAABJRU5ErkJggg==
  12. // @grant none
  13. // @license GNU GPLv3
  14. // ==/UserScript==
  15.  
  16. //#region TypeDefinitions
  17. /**
  18. * @typedef {Object} PlayerInstance
  19. * @property {string} name - The name of the player.
  20. * @property {string} uid - The unique identifier for the player.
  21. * @property {string} wt - The weight of the player.
  22. * @property {string} roomID - The room ID the player is in.
  23. * @property {WebSocket} socket - The WebSocket connection for the player.
  24. * @property {Map<string, Function[]>} events - The events map for the player.
  25. * @property {boolean} isConnected - Whether the player is connected.
  26. * @property {(invitelink:string)=>void} connect - Connects the player to a room.
  27. * @property {()=>void} disconnect - Disconnects the player.
  28. * @property {()=>void} reconnect - Reconnects the player.
  29. * @property {(invitelink:string)=>void} enterRoom - Enters a room.
  30. * @property {()=>void} nextRoom - Moves the player to the next room.
  31. * @property {()=>void} leaveRoom - Leaves the current room.
  32. * @property {(payload:string)=>void} send - Sends a message through the WebSocket.
  33. * @property {(event:string,handler:Function)=>void} addEventListener - Adds an event listener.
  34. * @property {(event:string)=>boolean} hasEventListener - Checks if an event listener exists.
  35. * @property {()=>void} __invokeEvent - Invokes an event.
  36. */
  37.  
  38. /**
  39. * @typedef {Object} DrawariaOnlineMessageTypes
  40. * @property {(message: string) => string} chatmsg - Sends a chat message.
  41. * @property {() => string} passturn - Passes the turn.
  42. * @property {(playerid: number|string) => string} pgdrawvote - Votes for a player to draw.
  43. * @property {() => string} pgswtichroom - Switches the room.
  44. * @property {() => string} playerafk - Marks the player as AFK.
  45. * @property {() => string} playerrated - Rates the player.
  46. * @property {(gestureid: number|string) => string} sendgesture - Sends a gesture.
  47. * @property {() => string} sendvote - Sends a vote.
  48. * @property {(playerid: number|string) => string} sendvotekick - Votes to kick a player.
  49. * @property {(wordid: number|string) => string} wordselected - Selects a word.
  50. * @property {Object} clientcmd - Client commands.
  51. * @property {(itemid: number|string, isactive: boolean) => string} clientcmd.activateitem - Activates an item.
  52. * @property {(itemid: number|string) => string} clientcmd.buyitem - Buys an item.
  53. * @property {(itemid: number|string, target: "zindex"|"shared", value: any) => string} clientcmd.canvasobj_changeattr - Changes an attribute of a canvas object.
  54. * @property {() => string} clientcmd.canvasobj_getobjects - Gets canvas objects.
  55. * @property {(itemid: number|string) => string} clientcmd.canvasobj_remove - Removes a canvas object.
  56. * @property {(itemid: number|string, positionX: number|string, positionY: number|string, speed: number|string) => string} clientcmd.canvasobj_setposition - Sets the position of a canvas object.
  57. * @property {(itemid: number|string, rotation: number|string) => string} clientcmd.canvasobj_setrotation - Sets the rotation of a canvas object.
  58. * @property {(value: any) => string} clientcmd.customvoting_setvote - Sets a custom vote.
  59. * @property {(value: any) => string} clientcmd.getfpid - Gets the FPID.
  60. * @property {() => string} clientcmd.getinventory - Gets the inventory.
  61. * @property {() => string} clientcmd.getspawnsstate - Gets the spawn state.
  62. * @property {(positionX: number|string, positionY: number|string) => string} clientcmd.moveavatar - Moves the avatar.
  63. * @property {() => string} clientcmd.setavatarprop - Sets the avatar properties.
  64. * @property {(flagid: number|string, isactive: boolean) => string} clientcmd.setstatusflag - Sets a status flag.
  65. * @property {(playerid: number|string, tokenid: number|string) => string} clientcmd.settoken - Sets a token.
  66. * @property {(playerid: number|string, value: any) => string} clientcmd.snapchatmessage - Sends a Snapchat message.
  67. * @property {() => string} clientcmd.spawnavatar - Spawns an avatar.
  68. * @property {() => string} clientcmd.startrollbackvoting - Starts rollback voting.
  69. * @property {() => string} clientcmd.trackforwardvoting - Tracks forward voting.
  70. * @property {(trackid: number|string) => string} clientcmd.votetrack - Votes for a track.
  71. * @property {(roomID: string, name?: string, uid?: string, wt?: string) => string} startplay - Starts the play.
  72. * @property {Object} clientnotify - Client notifications.
  73. * @property {(playerid: number|string) => string} clientnotify.requestcanvas - Requests a canvas.
  74. * @property {(playerid: number|string, base64: string) => string} clientnotify.respondcanvas - Responds with a canvas.
  75. * @property {(playerid: number|string, imageid: number|string) => string} clientnotify.galleryupload - Uploads to the gallery.
  76. * @property {(playerid: number|string, type: any) => string} clientnotify.warning - Sends a warning.
  77. * @property {(playerid: number|string, targetname: string, mute?: boolean) => string} clientnotify.mute - Mutes a player.
  78. * @property {(playerid: number|string, targetname: string, hide?: boolean) => string} clientnotify.hide - Hides a player.
  79. * @property {(playerid: number|string, reason: string, targetname: string) => string} clientnotify.report - Reports a player.
  80. * @property {Object} drawcmd - Drawing commands.
  81. * @property {(x1: number|string, y1: number|string, x2: number|string, y2: number|string, color: number|string, size?: number|string, ispixel?: boolean, playerid?: number|string) => string} drawcmd.line - Draws a line.
  82. * @property {(x1: number|string, y1: number|string, x2: number|string, y2: number|string, color: number|string, size: number|string, ispixel?: boolean, playerid?: number|string) => string} drawcmd.erase - Erases a part of the drawing.
  83. * @property {(x: number|string, y: number|string, color: number|string, tolerance: number|string, r: number|string, g: number|string, b: number|string, a: number|string) => string} drawcmd.flood - Flood fills an area.
  84. * @property {(playerid: number|string) => string} drawcmd.undo - Undoes the last action.
  85. * @property {() => string} drawcmd.clear - Clears the drawing.
  86. */
  87.  
  88. /**
  89. * @typedef {Object} PlayerClass
  90. * @property {PlayerInstance[]} instances
  91. * @property {PlayerInstance} noConflict
  92. * @property {(inviteLink:string)=>URL} getSocketServerURL
  93. * @property {(inviteLink:string)=>string} getRoomID
  94. * @property {DrawariaOnlineMessageTypes} parseMessage
  95. */
  96.  
  97. /**
  98. * @typedef {Object} UI
  99. * @property {(selectors: string, parentElement?: ParentNode) => Element|null} querySelect - Returns the first element that is a descendant of node that matches selectors.
  100. * @property {(selectors: string, parentElement?: ParentNode) => NodeListOf<Element>} querySelectAll - Returns all element descendants of node that match selectors.
  101. * @property {(tagName: string, properties?: object) => Element} createElement - Creates an element and assigns properties to it.
  102. * @property {(element: Element, attributes: object) => void} setAttributes - Assigns attributes to an element.
  103. * @property {(element: Element, styles: object) => void} setStyles - Assigns styles to an element.
  104. * @property {(name?: string) => HTMLDivElement} createContainer - Creates a container element.
  105. * @property {() => HTMLDivElement} createRow - Creates a row element.
  106. * @property {(name: string) => HTMLElement} createIcon - Creates an icon element.
  107. * @property {(type: string, properties?: object) => HTMLInputElement} createInput - Creates an input element.
  108. * @property {(input: HTMLInputElement, properties?: object) => HTMLLabelElement} createLabelFor - Creates a label for an input element.
  109. * @property {(className?: string) => HTMLElement & { show: Function, hide: Function }} createSpinner - Creates a spinner element.
  110. * @property {(input: HTMLInputElement, addon: HTMLLabelElement|HTMLInputElement|HTMLButtonElement|HTMLElement) => HTMLDivElement} createGroup - Creates an input group element.
  111. * @property {(inputs: Array<HTMLLabelElement|HTMLInputElement|HTMLButtonElement|HTMLElement>) => HTMLDivElement} createInputGroup - Creates an input group element.
  112. */
  113.  
  114. /**
  115. * @typedef {Object} Other
  116. * @property {(message: string, styles?: string, application?: string) => void} log - Logs a message with styles.
  117. * @property {(size?: number) => string} uid - Generates a random UID.
  118. * @property {(byteArray: number[]) => string} toHexString - Converts a byte array to a hex string.
  119. * @property {(key: string, value: string) => void} setCookie - Sets a cookie.
  120. * @property {() => Array<*>&{addEventListener:(event:"delete"|"set",handler:(property:string,value:*)=>void)=>}} makeObservableArray - Creates an observable array.
  121. * @property {(message: string) => (Array<any> | object)} tryParseJSON - Tries to parse a JSON string.
  122. */
  123.  
  124. /**
  125. * @class
  126. * @typedef {Object} DefinableCore
  127. * @property {PlayerClass} Player
  128. * @property {UI} UI
  129. * @property {Other} helper
  130. */
  131.  
  132. /**
  133. * @typedef {Object} Definable
  134. * @property {PlayerClass} Player
  135. * @property {UI} UI
  136. * @property {()=>HTMLElement} createRow
  137. * @property {(submodule:Core)=>void} registerModule
  138. */
  139.  
  140. /**
  141. * @typedef {Object} Position
  142. * @prop {number} x
  143. * @prop {number} y
  144. */
  145.  
  146. /**
  147. * @typedef {Object} Color
  148. * @prop {number} r
  149. * @prop {number} g
  150. * @prop {number} b
  151. * @prop {number} a
  152. */
  153.  
  154. /**
  155. * @typedef {Object} Volume
  156. * @prop {number} width
  157. * @prop {number} height
  158. */
  159.  
  160. /**
  161. * @typedef {Position & Color} Pixel
  162. */
  163.  
  164. /**
  165. * @typedef {Pixel & Volume} Area
  166. */
  167.  
  168. /**
  169. * @typedef {Object} PromiseResponse
  170. * @prop {*} data
  171. * @prop {Error|string|undefined} error
  172. */
  173. //#endregion TypeDefinitions
  174.  
  175. (function () {
  176. "use strict";
  177.  
  178. /**
  179. * @param {Definable} definable
  180. * @param {DefinableCore} $core
  181. */
  182. function initialize(definable, $core) {
  183. /** @type {Definable} */
  184. const botplayer = new $core("Bot Player", "robot");
  185. const ui = $core.UI;
  186. definable.registerModule(botplayer);
  187.  
  188. /* Row 1 */ {
  189. const row = botplayer.createRow();
  190.  
  191. {
  192. const input = ui.createInput("button");
  193. const label = ui.createLabelFor(input, { title: "Enter Room" });
  194. label.appendChild(ui.createIcon("check"));
  195. label.classList.add("col");
  196. label.className = label.className.replace("secondary", "success");
  197. row.appendChild(label);
  198.  
  199. input.addEventListener("click", function () {
  200. $core.Player.noConflict.enterRoom(ui.querySelect("#invurl").value);
  201. });
  202. }
  203.  
  204. {
  205. const input = ui.createInput("button");
  206. const label = ui.createLabelFor(input, { title: "Switch Room" });
  207. label.appendChild(ui.createIcon("exchange-alt"));
  208. label.classList.add("col");
  209. row.appendChild(label);
  210.  
  211. input.addEventListener("click", function () {
  212. $core.Player.noConflict.nextRoom();
  213. });
  214. }
  215.  
  216. {
  217. const input = ui.createInput("button");
  218. const label = ui.createLabelFor(input, { title: "Leave Room" });
  219. label.appendChild(ui.createIcon("times"));
  220. label.classList.add("col");
  221. label.className = label.className.replace("secondary", "danger");
  222. row.appendChild(label);
  223.  
  224. input.addEventListener("click", function () {
  225. $core.Player.noConflict.leaveRoom();
  226. });
  227. }
  228. }
  229.  
  230. /* Row 2 */ {
  231. const row = botplayer.createRow();
  232.  
  233. {
  234. const input = ui.createInput("file", { accept: "image/*" });
  235. const label = ui.createLabelFor(input, { title: "Upload Avatar" });
  236. label.appendChild(ui.createIcon("upload"));
  237. input.addEventListener("input", function () {
  238. loadFileAsImage(input.files[0]).then((response) => {
  239. if (response.data) {
  240. /** @type {HTMLImageElement} */
  241. const image = response.data;
  242.  
  243. $core.helper.setCookie("uid", "_");
  244.  
  245. fetch("https://drawaria.online/uploadavatarimage", {
  246. method: "POST",
  247. body: "imagedata=" + encodeURIComponent(image.src.replace("image/gif", "image/png")) + "&fromeditor=true",
  248. headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
  249. })
  250. .then((res) => {
  251. if (res.status === 200) {
  252. res.text().then((body) => {
  253. const data = body.split(".");
  254. const player = $core.Player.noConflict;
  255. player.uid = data[0];
  256. player.wt = data[1];
  257. if (player.isConnected) {
  258. player.reconnect();
  259. }
  260.  
  261. ui.querySelect("i,img", label).remove();
  262. label.appendChild(
  263. ui.createElement("img", {
  264. src: `https://drawaria.online/avatar/cache/${body}.jpg`,
  265. style: "width: 100%;",
  266. })
  267. );
  268. });
  269. } else {
  270. ui.querySelect("#chatbox_messages").appendChild(ui.createElement("div", { textContent: res.statusText, className: "chatmessage systemchatmessage" }));
  271. }
  272. })
  273. .catch((reason) => {
  274. ui.querySelect("#chatbox_messages").appendChild(ui.createElement("div", { textContent: reason, className: "chatmessage systemchatmessage" }));
  275. });
  276. input.value = null;
  277. }
  278. });
  279. });
  280. row.appendChild(label);
  281. }
  282.  
  283. {
  284. const botNameInput = ui.createInput("text");
  285. const botNameUpdateInput = ui.createInput("button");
  286. const botNameUpdateLabel = ui.createLabelFor(botNameUpdateInput, { title: "Update Name" });
  287. botNameUpdateLabel.appendChild(ui.createIcon("i-cursor"));
  288.  
  289. botNameUpdateInput.addEventListener("click", function () {
  290. const player = $core.Player.noConflict;
  291. player.name = botNameInput.value;
  292. if (player.isConnected) {
  293. player.reconnect();
  294. }
  295. });
  296.  
  297. const group = ui.createInputGroup(botNameInput, botNameUpdateLabel);
  298. group.style.flexGrow = "1";
  299. group.style.width = "min-content";
  300. row.appendChild(group);
  301. }
  302. }
  303.  
  304. window.dispatchEvent(new CustomEvent("definable:playerbot:init", { detail: { main: botplayer, core: $core } }));
  305. }
  306.  
  307. /**
  308. * @param {File} file
  309. * @returns {Promise<PromiseResponse>}
  310. */
  311. function loadFileAsImage(file) {
  312. return new Promise((resolve, reject) => {
  313. if (!(FileReader && file)) {
  314. reject({ data: undefined, error: "Native FileReader not present." });
  315. } else {
  316. const reader = new FileReader();
  317. reader.onload = function () {
  318. const image = new Image();
  319. image.src = reader.result;
  320. image.onload = function () {
  321. resolve({ data: image, error: undefined });
  322. };
  323. };
  324. reader.readAsDataURL(file);
  325. }
  326. });
  327. }
  328.  
  329. window.addEventListener("definable:init", function (event) {
  330. const { main, core } = event.detail;
  331. if (!main || !core) return console.error("main: %o & core: %o", main, core);
  332. initialize(main, core);
  333. });
  334. })();
  335.  
  336. (function () {
  337. "use strict";
  338.  
  339. /**
  340. * @param {Definable} playerbot
  341. * @param {DefinableCore} $core
  342. */
  343. function initialize(playerbot, $core) {
  344. /** @type {Definable} */
  345. const sozials = new $core("Sozials", "comments");
  346. const ui = $core.UI;
  347. playerbot.registerModule(sozials);
  348.  
  349. /* Row 1 */ {
  350. const row = sozials.createRow();
  351.  
  352. const input = ui.createInput("button");
  353. const label = ui.createLabelFor(input, { title: "Send Message" });
  354. const messageInput = ui.createInput("text");
  355. label.appendChild(ui.createIcon("paper-plane"));
  356. input.addEventListener("click", function () {
  357. $core.Player.noConflict.send($core.Player.parseMessage.chatmsg(messageInput.value));
  358. });
  359. const group = ui.createInputGroup(messageInput, label);
  360. row.appendChild(group);
  361. }
  362. /* Row 2 */ {
  363. const row = sozials.createRow();
  364. ["thumbs-up", "heart", "paint-brush", "cocktail", "hand-peace", "feather-alt", "trophy", "mug-hot", "gift"].forEach((token, index) => {
  365. const input = ui.createInput("button");
  366. const label = ui.createLabelFor(input);
  367. label.appendChild(ui.createIcon(token));
  368. input.addEventListener("click", function () {
  369. ui.querySelectAll("#playerlist>.playerlist-row").forEach((player) => {
  370. $core.Player.noConflict.send($core.Player.parseMessage.clientcmd.settoken(Number(player.dataset.playerid), index));
  371. });
  372. });
  373. row.appendChild(label);
  374. });
  375. }
  376.  
  377. /* Row 3 */ {
  378. const row = sozials.createRow();
  379. ui.querySelectAll("#gesturespickerselector .gesturespicker-container .gesturespicker-item img").forEach((node, index) => {
  380. const input = ui.createInput("button");
  381. const label = ui.createLabelFor(input);
  382. label.appendChild(ui.createElement("img", { src: node.src, style: "width: 100%;" }));
  383. input.addEventListener("click", function () {
  384. $core.Player.noConflict.send($core.Player.parseMessage.sendgesture(index));
  385. });
  386. row.appendChild(label);
  387. });
  388. }
  389.  
  390. ui.querySelect("#definableStyles").textContent += "\n#definable .row>label:has(img) { width: 2rem; padding: 0; }";
  391. }
  392.  
  393. window.addEventListener("definable:playerbot:init", function (event) {
  394. const { main, core } = event.detail;
  395. if (!main || !core) return console.error("main: %o & core: %o", main, core);
  396. initialize(main, core);
  397. });
  398. })();