7Placer+

Pixel place.io bot - an advanced bot that includes image botting, painting, and account management features. (Border drawing feature added)

  1. // ==UserScript==
  2. // @name 7Placer+
  3. // @namespace https://i.imgur.com/n084VLd.png
  4. // @version 1.5.0a
  5. // @description Pixel place.io bot - an advanced bot that includes image botting, painting, and account management features. (Border drawing feature added)
  6. // @author Azti & SamaelWired
  7. // @match https://pixelplace.io/*
  8. // @require https://update.gf.qytechs.cn/scripts/498080/1395134/Hacktimer.js
  9. // @require https://pixelplace.io/js/jquery.min.js?v2=1
  10. // @require https://pixelplace.io/js/jquery-ui.min.js?v2=1
  11. // @grant none
  12. // @run-at document-start
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. "use strict";
  17.  
  18. /* =======================================================================
  19. Canvas Worker - Marks ocean areas (approx #CCCCCC) as -1 when scanning canvas
  20. ========================================================================== */
  21. const cloadercode = `
  22. const canvasworkerTimet = performance.now();
  23. const colors = [
  24. 0xFFFFFF, 0xC4C4C4, 0xA6A6A6, 0x888888, 0x6F6F6F, 0x555555, 0x3A3A3A, 0x222222,
  25. 0x000000, 0x003638, 0x006600, 0x477050, 0x1B7400, 0x22B14C, 0x02BE01, 0x51E119,
  26. 0x94E044, 0x34EB6B, 0x98FB98, 0x75CEA9, 0xCAFF70, 0xFBFF5B, 0xE5D900, 0xFFCC00,
  27. 0xC1A162, 0xE6BE0C, 0xE59500, 0xFF7000, 0xFF3904, 0xE50000, 0xCE2939, 0xFF416A,
  28. 0x9F0000, 0x4D082C, 0x6B0000, 0x440414, 0xFF755F, 0xA06A42, 0x633C1F, 0x99530D,
  29. 0xBB4F00, 0xFFC49F, 0xFFDFCC, 0xFF7EBB, 0xFFA7D1, 0xEC08EC, 0xBB276C, 0xCF6EE4,
  30. 0x7D26CD, 0x820080, 0x591C91, 0x330077, 0x020763, 0x5100FF, 0x0000EA, 0x044BFF,
  31. 0x013182, 0x005BA1, 0x6583CF, 0x36BAFF, 0x0083C7, 0x00D3DD, 0x45FFC8, 0xB5E8EE
  32. ];
  33. const oceanHex = 0xCCCCCC;
  34. function isOceanColor(colornum) {
  35. const r1 = (colornum >> 16) & 0xFF,
  36. g1 = (colornum >> 8) & 0xFF,
  37. b1 = colornum & 0xFF;
  38. const r2 = (oceanHex >> 16) & 0xFF,
  39. g2 = (oceanHex >> 8) & 0xFF,
  40. b2 = oceanHex & 0xFF;
  41. const dr = r1 - r2, dg = g1 - g2, db = b1 - b2;
  42. // Consider it ocean if the sum of squares of differences is less than 100
  43. return (dr*dr + dg*dg + db*db) < 100;
  44. }
  45. self.addEventListener('message', async (event) => {
  46. const imageResponse = await fetch('https://pixelplace.io/canvas/' + event.data + '.png?t200000=' + Date.now());
  47. const imageBlob = await imageResponse.blob();
  48. const imageBitmap = await createImageBitmap(imageBlob);
  49. const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);
  50. const ctx = canvas.getContext('2d');
  51. ctx.drawImage(imageBitmap, 0, 0, imageBitmap.width, imageBitmap.height);
  52. const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  53. const pixelData = imageData.data;
  54. const CanvasArray = Array.from({ length: canvas.width }, () => Array.from({ length: canvas.height }, () => 50));
  55. for (let y = 0; y < canvas.height; y++) {
  56. for (let x = 0; x < canvas.width; x++) {
  57. const pixelIndex = (y * canvas.width + x) * 4;
  58. const a = pixelData[pixelIndex + 3];
  59. if (a < 1) { continue; }
  60. const r = pixelData[pixelIndex];
  61. const g = pixelData[pixelIndex + 1];
  62. const b = pixelData[pixelIndex + 2];
  63. const colornum = (r << 16) | (g << 8) | b;
  64. if (isOceanColor(colornum)) {
  65. CanvasArray[x][y] = -1;
  66. continue;
  67. }
  68. const colorIndex = colors.indexOf(colornum);
  69. CanvasArray[x][y] = colorIndex;
  70. }
  71. }
  72. self.postMessage(CanvasArray);
  73. const canvasworkerendTime = performance.now();
  74. var processingTime = canvasworkerendTime - canvasworkerTimet;
  75. self.postMessage(processingTime);
  76. });
  77. `;
  78. const cloaderblob = new Blob([cloadercode], { type: 'application/javascript' });
  79. const canvasworker = new Worker(URL.createObjectURL(cloaderblob));
  80.  
  81. function loadcanvas(canvas) {
  82. canvasworker.onmessage = function(event) {
  83. if (Array.isArray(event.data)) {
  84. canvas.CanvasArray = event.data;
  85. } else {
  86. console.log("[7placer] Processing took: " + Math.round(event.data) + "ms");
  87. }
  88. };
  89. canvasworker.postMessage(canvas_Canvas.ID);
  90. }
  91.  
  92. /* =======================================================================
  93. Style Settings - Tracker, Drop Area and Canvas Preview
  94. ========================================================================== */
  95. const trackercss = {
  96. top: '0px',
  97. left: '0px',
  98. borderColor: 'rgb(138,43,226)',
  99. color: 'rgb(138,43,226)',
  100. backgroundColor: 'black',
  101. opacity: '60%',
  102. display: 'none',
  103. transition: 'all 0.06s ease-in-out',
  104. pointerEvents: 'none'
  105. };
  106.  
  107. const drop = {
  108. width: 'calc(100% - 2em)',
  109. height: 'calc(100% - 2em)',
  110. position: 'fixed',
  111. left: '0px',
  112. top: '0px',
  113. backgroundColor: 'rgba(0, 0, 0, 0.533)',
  114. zIndex: '9999',
  115. display: 'flex',
  116. color: 'white',
  117. fontSize: '48pt',
  118. justifyContent: 'center',
  119. alignItems: 'center',
  120. border: '3px white dashed',
  121. borderRadius: '18px',
  122. margin: '1em'
  123. };
  124.  
  125. const canvascss = {
  126. position: 'absolute',
  127. pointerEvents: 'none',
  128. left: '0px',
  129. top: '0px',
  130. imageRendering: 'pixelated',
  131. opacity: '50%',
  132. animation: 'blink 3s ease-out infinite'
  133. };
  134.  
  135. const blink = document.createElement("style");
  136. blink.type = "text/css";
  137. blink.innerText = `
  138. @keyframes blink {
  139. 0% { opacity: .30; }
  140. 50% { opacity: .10; }
  141. 100% { opacity: .30; }
  142. }
  143. `;
  144. document.head.appendChild(blink);
  145.  
  146. /* =======================================================================
  147. Canvas Class
  148. ========================================================================== */
  149. class Canvas {
  150. constructor() {
  151. Canvas.ID = this.ParseID();
  152. Canvas.isProcessed = false;
  153. loadcanvas(this);
  154. Canvas.customCanvas = this.createPreviewCanvas();
  155. }
  156. ParseID() {
  157. return parseInt(window.location.href.split("/").slice(-1)[0].split("-")[0]);
  158. }
  159. static get instance() {
  160. if (!Canvas._instance)
  161. Canvas._instance = new Canvas();
  162. return Canvas._instance;
  163. }
  164. set CanvasArray(array) {
  165. this._CanvasArray = array;
  166. Canvas.isProcessed = true;
  167. }
  168. get CanvasArray() {
  169. return this._CanvasArray;
  170. }
  171. getColor(x, y) {
  172. try {
  173. return this._CanvasArray[x][y];
  174. } catch(e) {
  175. return 50;
  176. }
  177. }
  178. updatePixel(x, y, color) {
  179. if (!Canvas.isProcessed)
  180. return;
  181. this.CanvasArray[x][y] = color;
  182. }
  183. createPreviewCanvas() {
  184. const canvas = $(`<canvas width="2500" height="2088">`).css(canvascss);
  185. $('#canvas').ready(function () {
  186. $('#painting-move').append(canvas);
  187. });
  188. const ctx = canvas[0].getContext("2d");
  189. return ctx;
  190. }
  191. }
  192. const canvas_Canvas = Canvas;
  193.  
  194. /* =======================================================================
  195. Palive and Time Functions
  196. ========================================================================== */
  197. function randomString(charList, num) {
  198. return Array.from({ length: num }, () => charList.charAt(Math.floor(Math.random() * charList.length))).join('');
  199. }
  200. function randomString1(num) {
  201. const charList = 'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  202. return randomString(charList, num);
  203. }
  204. function randomString2(num) {
  205. const charList = 'gmbonjklezcfxta1234567890GMBONJKLEZCFXTA';
  206. return randomString(charList, num);
  207. }
  208. function randInt(min, max) {
  209. return Math.floor(Math.random() * (max - min + 1)) + min;
  210. }
  211. const paliveCharmap = {
  212. "0": "g",
  213. "1": "n",
  214. "2": "b",
  215. "3": "r",
  216. "4": "z",
  217. "5": "s",
  218. "6": "l",
  219. "7": "x",
  220. "8": "i",
  221. "9": "o"
  222. };
  223. function getPalive(serverTime, userId) {
  224. const tDelay = getTDelay(serverTime);
  225. const sequenceLengths = [6, 5, 9, 4, 5, 3, 6, 6, 3];
  226. const currentTimestamp = Math.floor(Date.now() / 1000) + tDelay - 5400;
  227. const timestampString = currentTimestamp.toString();
  228. const timestampCharacters = timestampString.split('');
  229. let result = '';
  230. for (let i = 0; i < sequenceLengths.length; i++) {
  231. const sequenceNumber = sequenceLengths[i];
  232. result += randInt(0, 1) == 1 ? randomString2(sequenceNumber) : randomString1(sequenceNumber);
  233. const letter = paliveCharmap[parseInt(timestampCharacters[i])];
  234. result += randInt(0, 1) == 0 ? letter.toUpperCase() : letter;
  235. }
  236. result += userId.toString().substring(0, 1) + (randInt(0, 1) == 1 ? randomString2(randInt(4, 20)) : randomString1(randInt(4, 25)));
  237. return result + "0=";
  238. }
  239. function getTDelay(serverTime) {
  240. const currentTime = new Date().getTime() / 1e3;
  241. return Math.floor(serverTime - currentTime);
  242. }
  243.  
  244. /* =======================================================================
  245. Auth and API Functions
  246. ========================================================================== */
  247. class Auth {
  248. constructor(authObj) {
  249. this.authKey = authObj.authKey;
  250. this.authId = authObj.authId;
  251. this.authToken = authObj.authToken;
  252. }
  253. }
  254. function getCookie(name) {
  255. const value = `; ${document.cookie}`;
  256. const parts = value.split(`; ${name}=`);
  257. if (parts.length === 2)
  258. return parts.pop().split(';').shift();
  259. }
  260. async function getPainting(authId, authKey, authToken) {
  261. const originalAuthId = getCookie('authId');
  262. const originalAuthKey = getCookie('authKey');
  263. const originalAuthToken = getCookie('authToken');
  264. document.cookie = `authId=${authId}; path=/`;
  265. document.cookie = `authKey=${authKey}; path=/`;
  266. document.cookie = `authToken=${authToken}; path=/`;
  267. try {
  268. const response = await fetch(`https://pixelplace.io/api/get-painting.php?id=${canvas_Canvas.ID}&connected=1`, {
  269. headers: { 'Accept': 'application/json, text/javascript, */*; q=0.01' },
  270. credentials: 'include'
  271. });
  272. const json = response.json();
  273. return json;
  274. } finally {
  275. document.cookie = `authId=${originalAuthId}; path=/`;
  276. document.cookie = `authKey=${originalAuthKey}; path=/`;
  277. document.cookie = `authToken=${originalAuthToken}; path=/`;
  278. }
  279. }
  280.  
  281. /* =======================================================================
  282. Account Management and Command Functions
  283. ========================================================================== */
  284. const window2 = window;
  285. var LocalAccounts = new Map();
  286. function storagePush() {
  287. const obj = Object.fromEntries(LocalAccounts);
  288. localStorage.setItem('LocalAccounts', JSON.stringify(obj));
  289. }
  290. function storageGet() {
  291. const storedAccounts = localStorage.getItem('LocalAccounts');
  292. if (storedAccounts) {
  293. const parsedAccounts = JSON.parse(storedAccounts);
  294. LocalAccounts = new Map(Object.entries(parsedAccounts));
  295. } else {
  296. LocalAccounts = new Map();
  297. }
  298. }
  299. async function delay(ms) {
  300. return new Promise(resolve => setTimeout(resolve, ms));
  301. }
  302. function saveAuth(username, authId, authKey, authToken, print = true) {
  303. if (!authId || !authKey || !authToken) {
  304. console.log('[7p] saveAuth usage: saveAuth(username, authId, authKey, authToken)');
  305. return;
  306. }
  307. const account = { authId, authKey, authToken };
  308. LocalAccounts.set(username, account);
  309. storagePush();
  310. if (print)
  311. console.log('Auth saved. Saved list: ', LocalAccounts);
  312. }
  313. async function getAuth(print = true) {
  314. const cookieStore = window2.cookieStore;
  315. const authToken = await cookieStore.get("authToken");
  316. const authKey = await cookieStore.get("authKey");
  317. const authId = await cookieStore.get("authId");
  318. if (authToken == null || authKey == null || authId == null) {
  319. console.log('[7p] Please login first!');
  320. return;
  321. }
  322. if (print)
  323. console.log(`authId = "${authId.value}", authKey = "${authKey.value}", authToken = "${authToken.value}"`);
  324. return { authToken: authToken.value, authKey: authKey.value, authId: authId.value };
  325. }
  326. async function saveAccount() {
  327. storageGet();
  328. const AuthObj = await getAuth(false);
  329. const userinfo = await getPainting(AuthObj.authId, AuthObj.authKey, AuthObj.authToken);
  330. saveAuth(userinfo.user.name, AuthObj.authId, AuthObj.authKey, AuthObj.authToken, false);
  331. console.log('Auth saved. Saved list: ', LocalAccounts);
  332. }
  333. function getAccounts() {
  334. storageGet();
  335. if (!LocalAccounts || LocalAccounts.size == 0) {
  336. console.log('No accounts found');
  337. return;
  338. }
  339. console.log(`Found ${LocalAccounts.size} accounts`);
  340. console.log(LocalAccounts);
  341. }
  342. function deleteAccount(identifier) {
  343. if (identifier == null) {
  344. console.log('deleteAccount usage: deleteAccount(user or index)');
  345. return;
  346. }
  347. storageGet();
  348. if (typeof identifier == 'string') {
  349. if (identifier == 'all') {
  350. LocalAccounts.forEach((value, key) => {
  351. LocalAccounts.delete(key);
  352. });
  353. return;
  354. }
  355. if (!LocalAccounts.has(identifier)) {
  356. console.log(`[7p] Error deleting: No account with name ${identifier}`);
  357. return;
  358. }
  359. LocalAccounts.delete(identifier);
  360. console.log(`[7p] Deleted account ${identifier}.`);
  361. console.log(LocalAccounts);
  362. }
  363. if (typeof identifier == 'number') {
  364. const keys = Array.from(LocalAccounts.keys());
  365. if (identifier > keys.length) {
  366. console.log(`[7p] Error deleting: No account with index ${identifier}`);
  367. return;
  368. }
  369. LocalAccounts.delete(keys[identifier]);
  370. console.log(`Deleted account ${identifier}`);
  371. console.log(LocalAccounts);
  372. }
  373. storagePush();
  374. }
  375. async function connect(username) {
  376. storageGet();
  377. const account = LocalAccounts.get(username);
  378. const connectedbot = window2.seven.bots.find((bot) =>
  379. bot.generalinfo && bot.generalinfo.user && bot.generalinfo.user.name == username
  380. );
  381. if (!username) {
  382. console.log('[7p] Missing bot username, connect("username")');
  383. return;
  384. }
  385. if (username == 'all') {
  386. for (const [username, account] of LocalAccounts) {
  387. const connectedbot = window2.seven.bots.find((bot) =>
  388. bot.generalinfo && bot.generalinfo.user && bot.generalinfo.user.name == username
  389. );
  390. const auth = new Auth(account);
  391. if (connectedbot) {
  392. console.log(`[7p] Account ${username} is already connected.`);
  393. continue;
  394. }
  395. new WSBot(auth, username);
  396. await delay(500);
  397. }
  398. return;
  399. }
  400. if (!account) {
  401. console.log(`[7p] No account found with username ${username}`);
  402. return;
  403. }
  404. if (connectedbot) {
  405. console.log(`[7p] Account ${username} is already connected.`);
  406. return;
  407. }
  408. const auth = new Auth(account);
  409. new WSBot(auth, username);
  410. }
  411. function disconnect(username) {
  412. const bot = window2.seven.bots.find((bot) =>
  413. bot.generalinfo && bot.generalinfo.user && bot.generalinfo.user.name == username
  414. );
  415. if (!username) {
  416. console.log('[7p] disconnect requires a username, disconnect("username")');
  417. return;
  418. }
  419. if (username == 'all') {
  420. if (window2.seven.bots.length == 1) {
  421. console.log('[7p] No bots connected.');
  422. return;
  423. }
  424. for (const bot of window2.seven.bots) {
  425. closeBot(bot);
  426. }
  427. return;
  428. }
  429. if (!bot) {
  430. console.log(`[7p] No bot connected with username ${username}`);
  431. return;
  432. }
  433. closeBot(bot);
  434. }
  435.  
  436. /* =======================================================================
  437. Global Variables
  438. ========================================================================== */
  439. const variables = window.seven = {
  440. bots: [],
  441. pixelspeed: 20,
  442. queue: [],
  443. inprogress: false,
  444. protect: false,
  445. tickspeed: 1000,
  446. order: 'fromCenter',
  447. saveAuth: saveAuth,
  448. getAuth: getAuth,
  449. saveAccount: saveAccount,
  450. getAccounts: getAccounts,
  451. deleteAccount: deleteAccount,
  452. connect: connect,
  453. disconnect: disconnect
  454. };
  455.  
  456. /* =======================================================================
  457. WebSocket and Message Handling
  458. ========================================================================== */
  459. function onClientMessage(event) {
  460. const msg = event.data;
  461. const bot = Client.instance;
  462. if (msg.startsWith("42")) {
  463. const msgData = JSON.parse(event.data.substr(2));
  464. const type = msgData[0];
  465. switch (type) {
  466. case "p":
  467. for (const pixel of msgData[1]) {
  468. const canvas = canvas_Canvas.instance;
  469. const x = pixel[0];
  470. const y = pixel[1];
  471. const color = pixel[2];
  472. canvas.updatePixel(x, y, color);
  473. }
  474. break;
  475. case "canvas":
  476. for (const pixel of msgData[1]) {
  477. const canvas = canvas_Canvas.instance;
  478. const x = pixel[0];
  479. const y = pixel[1];
  480. const color = pixel[2];
  481. canvas.updatePixel(x, y, color);
  482. }
  483. break;
  484. }
  485. }
  486. }
  487. async function onBotMessage(event, bot) {
  488. const message = event.data;
  489. if (message.startsWith("42")) {
  490. const msgData = JSON.parse(event.data.substr(2));
  491. const type = msgData[0];
  492. const botid = bot.generalinfo.user.id;
  493. const botname = bot.username;
  494. switch (type) {
  495. case "server_time":
  496. bot.paliveServerTime = msgData[1];
  497. break;
  498. case "ping.alive":
  499. const hash = getPalive(bot.paliveServerTime, botid);
  500. console.log('[7p]', botname, ': pong =', hash, botid);
  501. bot.emit('pong.alive', `"` + hash + `"`);
  502. break;
  503. case "throw.error":
  504. if (msgData[1] == 49) {
  505. console.log(`[7p] [Bot ${botname}] Error (${msgData[1]}): This auth is not valid! Deleting account from saved accounts...`);
  506. deleteAccount(botname);
  507. closeBot(bot);
  508. return;
  509. }
  510. console.log(`[7p] [Bot ${botname}] Pixelplace WS error: ${msgData[1]}`);
  511. break;
  512. case "canvas":
  513. console.log(`[7p] Successfully connected to bot ${bot.username}`);
  514. variables.bots.push(bot);
  515. break;
  516. }
  517. }
  518. if (message.startsWith("0"))
  519. bot.ws.send('40');
  520. if (message.startsWith("40"))
  521. bot.ws.send(`42["init",{"authKey":"${bot.auth.authKey}","authToken":"${bot.auth.authToken}","authId":"${bot.auth.authId}","boardId":${canvas_Canvas.ID}}]`);
  522. if (message.startsWith("2"))
  523. bot.ws.send('3');
  524. }
  525. const customWS = window.WebSocket;
  526. window.WebSocket = function(url, protocols) {
  527. const client = new Client();
  528. const socket = new customWS(url, protocols);
  529. socket.addEventListener("message", (event) => { onClientMessage(event); });
  530. client.ws = socket;
  531. return socket;
  532. };
  533. async function hookBot(bot) {
  534. console.log(`[7p] Attempting to connect account ${bot.username}`);
  535. const socket = new customWS("wss://pixelplace.io/socket.io/?EIO=4&transport=websocket");
  536. socket.addEventListener("message", (event) => { onBotMessage(event, bot); });
  537. socket.addEventListener("close", () => { Bot.botIndex -= 1; });
  538. return socket;
  539. }
  540. function closeBot(bot) {
  541. if (bot instanceof Client)
  542. return;
  543. if (!bot) {
  544. console.log('[7placer] Cannot close bot that doesn\'t exist.');
  545. return;
  546. }
  547. bot.ws.close();
  548. const result = variables.bots.filter((checkedBot) => checkedBot.botid != bot.botid);
  549. variables.bots = result;
  550. console.log('[7placer] Ended bot ', bot.botid);
  551. }
  552.  
  553. /* =======================================================================
  554. Bot Classes – Bot, WSBot and Client
  555. ========================================================================== */
  556. class Bot {
  557. constructor() {
  558. this.trackeriters = 0;
  559. this.lastplace = Date.now();
  560. this.botid = Bot.botIndex;
  561. Bot.botIndex += 1;
  562. }
  563. emit(event, params) {
  564. this.ws.send(`42["${event}",${params}]`);
  565. }
  566. async placePixel(x, y, color, client = false, tracker = true) {
  567. var tick = 0;
  568. while (true) {
  569. const canvas = canvas_Canvas.instance;
  570. const canvascolor = canvas.getColor(x, y);
  571. if (canvascolor == color || canvascolor == -1)
  572. return true;
  573. if (Date.now() - this.lastplace >= variables.pixelspeed) {
  574. this.emit('p', `[${x},${y},${color},1]`);
  575. this.lastplace = Date.now();
  576. canvas.updatePixel(x, y, color);
  577. if (tracker && this.trackeriters >= 6) {
  578. $(this.tracker).css({ top: y, left: x, display: 'block' });
  579. this.trackeriters = 0;
  580. }
  581. this.trackeriters += 1;
  582. return true;
  583. }
  584. tick += 1;
  585. if (tick == variables.tickspeed) {
  586. tick = 0;
  587. await new Promise(resolve => setTimeout(resolve, 0));
  588. }
  589. }
  590. }
  591. static async findAvailableBot() {
  592. const bots = variables.bots;
  593. var tick = 0;
  594. while (true) {
  595. for (var i = 0; i < bots.length; i++) {
  596. const bot = bots[i];
  597. if (Date.now() - bot.lastplace >= variables.pixelspeed) {
  598. return bot;
  599. }
  600. }
  601. tick += 1;
  602. if (tick == variables.tickspeed) {
  603. tick = 0;
  604. await new Promise(resolve => setTimeout(resolve, 0));
  605. }
  606. }
  607. }
  608. createTracker() {
  609. const tracker = $('<div class="track" id="bottracker">').text(`[7P] ${this.username}`).css(trackercss);
  610. $('#canvas').ready(function () {
  611. $('#painting-move').append(tracker);
  612. });
  613. return tracker;
  614. }
  615. set ws(wss) {
  616. this._ws = wss;
  617. }
  618. get ws() {
  619. return this._ws;
  620. }
  621. }
  622. Bot.botIndex = 0;
  623. class WSBot extends Bot {
  624. constructor(auth, username) {
  625. super();
  626. if (!username || !auth) {
  627. console.error("[7p ERROR]: 'auth' and 'username' should both be provided.");
  628. return;
  629. }
  630. this._auth = auth;
  631. this.username = username;
  632. this.startBot();
  633. }
  634. async startBot() {
  635. this.generalinfo = await getPainting(this.auth.authId, this.auth.authKey, this.auth.authToken);
  636. this.tracker = this.createTracker();
  637. this.ws = await hookBot(this);
  638. }
  639. get auth() {
  640. return this._auth;
  641. }
  642. }
  643. class Client extends Bot {
  644. constructor() {
  645. super();
  646. this.username = 'Client';
  647. Client.instance = this;
  648. this.tracker = this.createTracker();
  649. variables.bots.push(this);
  650. }
  651. static get Client() {
  652. return Client.instance;
  653. }
  654. }
  655.  
  656. /* =======================================================================
  657. Queue Functions (Processing queued pixels and checking canvas state)
  658. ========================================================================== */
  659. class Queue {
  660. constructor() { }
  661. static add(x, y, color) {
  662. variables.queue.push({ x: x, y: y, color: color });
  663. }
  664. static clear() {
  665. variables.queue = [];
  666. }
  667. static async start() {
  668. if (!canvas_Canvas.isProcessed) {
  669. console.log('[7p] Error starting queue: Canvas has not been processed yet.');
  670. Queue.stop();
  671. return;
  672. }
  673. await Queue.sort();
  674. var pos = 0;
  675. var tick = 0;
  676. variables.inprogress = true;
  677. while (variables.inprogress == true && variables.queue.length > 0) {
  678. const pixel = variables.queue[pos];
  679. const currentColor = canvas_Canvas.instance.getColor(pixel.x, pixel.y);
  680. if (currentColor === pixel.color || currentColor === -1) {
  681. pos++;
  682. if (pos >= variables.queue.length) {
  683. if (variables.protect)
  684. pos = 0;
  685. else {
  686. Queue.stop();
  687. break;
  688. }
  689. }
  690. continue;
  691. }
  692. const bot = await Bot.findAvailableBot();
  693. await bot.placePixel(pixel.x, pixel.y, pixel.color);
  694. pos++;
  695. if (!variables.protect && pos == variables.queue.length) {
  696. Queue.stop();
  697. break;
  698. } else if (variables.protect && pos == variables.queue.length) {
  699. pos = 0;
  700. }
  701. await new Promise(resolve => setTimeout(resolve, 0));
  702. if (tick >= variables.tickspeed) {
  703. tick = 0;
  704. await new Promise(resolve => setTimeout(resolve, 0));
  705. }
  706. tick += 1;
  707. }
  708. }
  709. static async sort() {
  710. const array = variables.queue;
  711. switch (variables.order) {
  712. case 'rand':
  713. array.sort(() => Math.random() - 0.5);
  714. break;
  715. case 'colors':
  716. array.sort((a, b) => a.color - b.color);
  717. break;
  718. case 'vertical':
  719. array.sort((a, b) => a.x - b.x);
  720. break;
  721. case 'horizontal':
  722. array.sort((a, b) => a.y - b.y);
  723. break;
  724. default:
  725. case 'circle':
  726. const CX = Math.floor((array[0].x + array[array.length - 1].x) / 2);
  727. const CY = Math.floor((array[0].y + array[array.length - 1].y) / 2);
  728. array.sort((a, b) => {
  729. const distanceA = Math.sqrt((a.x - CX) ** 2 + (a.y - CY) ** 2);
  730. const distanceB = Math.sqrt((b.x - CX) ** 2 + (b.y - CY) ** 2);
  731. return distanceA - distanceB;
  732. });
  733. break;
  734. }
  735. }
  736. static stop() {
  737. variables.inprogress = false;
  738. canvas_Canvas.customCanvas.clearRect(0, 0, 3000, 3000);
  739. Queue.clear();
  740. }
  741. }
  742. const SevenQueue = Queue;
  743.  
  744. /* =======================================================================
  745. Image Processing Tools
  746. ========================================================================== */
  747. const colors = [
  748. 0xFFFFFF, 0xC4C4C4, 0xA6A6A6, 0x888888, 0x6F6F6F, 0x555555, 0x3A3A3A, 0x222222,
  749. 0x000000, 0x003638, 0x006600, 0x477050, 0x1B7400, 0x22B14C, 0x02BE01, 0x51E119,
  750. 0x94E044, 0x34EB6B, 0x98FB98, 0x75CEA9, 0xCAFF70, 0xFBFF5B, 0xE5D900, 0xFFCC00,
  751. 0xC1A162, 0xE6BE0C, 0xE59500, 0xFF7000, 0xFF3904, 0xE50000, 0xCE2939, 0xFF416A,
  752. 0x9F0000, 0x4D082C, 0x6B0000, 0x440414, 0xFF755F, 0xA06A42, 0x633C1F, 0x99530D,
  753. 0xBB4F00, 0xFFC49F, 0xFFDFCC, 0xFF7EBB, 0xFFA7D1, 0xEC08EC, 0xBB276C, 0xCF6EE4,
  754. 0x7D26CD, 0x820080, 0x591C91, 0x330077, 0x020763, 0x5100FF, 0x0000EA, 0x044BFF,
  755. 0x013182, 0x005BA1, 0x6583CF, 0x36BAFF, 0x0083C7, 0x00D3DD, 0x45FFC8, 0xB5E8EE
  756. ];
  757. function getColorDistance(c1, c2) {
  758. const r1 = (c1 >> 16) & 0xFF;
  759. const g1 = (c1 >> 8) & 0xFF;
  760. const b1 = c1 & 0xFF;
  761. const r2 = (c2 >> 16) & 0xFF;
  762. const g2 = (c2 >> 8) & 0xFF;
  763. const b2 = c2 & 0xFF;
  764. return (r1 - r2) ** 2 + (g1 - g2) ** 2 + (b1 - b2) ** 2;
  765. }
  766. function findClosestColor(color) {
  767. let minDistance = Infinity;
  768. let colorNumber;
  769. let index = 0;
  770. for (const pxpColor of colors) {
  771. const distance = getColorDistance(color, pxpColor);
  772. if (distance < minDistance) {
  773. minDistance = distance;
  774. colorNumber = index;
  775. }
  776. index += 1;
  777. }
  778. return colorNumber;
  779. }
  780. function previewCanvasImage(x, y, image) {
  781. const ctx = canvas_Canvas.customCanvas;
  782. const img = new Image();
  783. img.onload = function () {
  784. ctx.drawImage(img, x, y);
  785. };
  786. img.src = URL.createObjectURL(image);
  787. }
  788. async function ImageToPixels(image) {
  789. const result = [];
  790. const canvas = new OffscreenCanvas(image.width, image.height);
  791. const ctx = canvas.getContext('2d');
  792. ctx.drawImage(image, 0, 0, image.width, image.height);
  793. const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  794. const pixelData = imageData.data;
  795. for (let y = 0; y < canvas.height; y++) {
  796. for (let x = 0; x < canvas.width; x++) {
  797. const pixelIndex = (y * canvas.width + x) * 4;
  798. const r = pixelData[pixelIndex];
  799. const g = pixelData[pixelIndex + 1];
  800. const b = pixelData[pixelIndex + 2];
  801. const a = pixelData[pixelIndex + 3];
  802. const colornum = (r << 16) | (g << 8) | b;
  803. if (a < 1) { continue; }
  804. const color = findClosestColor(colornum);
  805. result.push({ x, y, color });
  806. }
  807. }
  808. return result;
  809. }
  810. async function botImage(x, y, image) {
  811. const bitmap = await createImageBitmap(image);
  812. const processed = await ImageToPixels(bitmap);
  813. previewCanvasImage(x, y, image);
  814. processed.forEach((pixel) => SevenQueue.add(pixel.x + x, pixel.y + y, pixel.color));
  815. SevenQueue.start();
  816. }
  817.  
  818. /* =======================================================================
  819. Square Creation Function
  820. ========================================================================== */
  821. function BotSquare(x1, y1, x2, y2, color) {
  822. if (x2 < x1) [x1, x2] = [x2, x1];
  823. if (y2 < y1) [y1, y2] = [y2, y1];
  824. for (let x = x1; x <= x2; x++) {
  825. for (let y = y1; y <= y2; y++) {
  826. SevenQueue.add(x, y, color);
  827. }
  828. }
  829. SevenQueue.start();
  830. }
  831.  
  832. /* =======================================================================
  833. Cursor and Selected Color Information
  834. ========================================================================== */
  835. function getClientMouse() {
  836. const coordinates = $('#coordinates').text();
  837. const [x, y] = coordinates.split(',').map(coord => parseInt(coord.trim()));
  838. const selectedcolor = $('#palette-buttons a.selected').data('id');
  839. return [x, y, selectedcolor];
  840. }
  841.  
  842. /* =======================================================================
  843. Image Botting – Drop Area
  844. ========================================================================== */
  845. function createDropArea() {
  846. const dropobject = $('<div>').text('Drop Image').css(drop);
  847. const [x, y] = getClientMouse();
  848. $('body').append(dropobject);
  849. dropobject.on("click", function () {
  850. dropobject.remove();
  851. });
  852. dropobject.on("drop", async function (event) {
  853. event.preventDefault();
  854. event.stopPropagation();
  855. const image = event.originalEvent.dataTransfer.files[0];
  856. dropobject.remove();
  857. await botImage(x, y, image);
  858. }).on('dragover', false);
  859. }
  860.  
  861. /* =======================================================================
  862. Keyboard Shortcuts
  863. Alt+W: Stop queue
  864. Alt+B: Create drop area
  865. Alt+X: Draw square from two points
  866. Alt+Y: Draw border (1 pixel) around area with ocean and canvas boundaries
  867. ========================================================================== */
  868. var coord1 = null;
  869. var borderCoord1 = null;
  870. $(document).on('keyup', function (event) {
  871. if ($(':input[type="text"]').is(':focus'))
  872. return;
  873. switch (event.which) {
  874. case 87: // Alt+W
  875. if (!event.altKey) return;
  876. SevenQueue.stop();
  877. break;
  878. case 66: // Alt+B
  879. if (!event.altKey) return;
  880. createDropArea();
  881. break;
  882. case 88: // Alt+X: Draw square
  883. {
  884. const [x, y, color] = getClientMouse();
  885. if (coord1 == null) {
  886. coord1 = { x: x, y: y };
  887. return;
  888. }
  889. BotSquare(coord1.x, coord1.y, x, y, color);
  890. coord1 = null;
  891. }
  892. break;
  893. case 89: // Alt+Y: Draw border
  894. if (!event.altKey) return;
  895. {
  896. const [xB, yB, selectedColor] = getClientMouse();
  897. if (borderCoord1 == null) {
  898. borderCoord1 = { x: xB, y: yB };
  899. return;
  900. }
  901. // Second point selected, define rectangle area
  902. let xMin = Math.min(borderCoord1.x, xB);
  903. let xMax = Math.max(borderCoord1.x, xB);
  904. let yMin = Math.min(borderCoord1.y, yB);
  905. let yMax = Math.max(borderCoord1.y, yB);
  906.  
  907. const canvasInstance = canvas_Canvas.instance;
  908. // Check each pixel in the selected area:
  909. for (let i = xMin; i <= xMax; i++) {
  910. for (let j = yMin; j <= yMax; j++) {
  911. // If pixel is not ocean (paintable canvas area)
  912. if (canvasInstance.getColor(i, j) !== -1) {
  913. let isBorder = false;
  914. // Check 4 directional neighbors:
  915. if (i - 1 >= 0 && canvasInstance.getColor(i - 1, j) === -1) isBorder = true;
  916. if (i + 1 < canvasInstance._CanvasArray.length && canvasInstance.getColor(i + 1, j) === -1) isBorder = true;
  917. if (j - 1 >= 0 && canvasInstance.getColor(i, j - 1) === -1) isBorder = true;
  918. if (j + 1 < canvasInstance._CanvasArray[0].length && canvasInstance.getColor(i, j + 1) === -1) isBorder = true;
  919.  
  920. // If border pixel, add to queue (1 pixel border)
  921. if (isBorder) {
  922. SevenQueue.add(i, j, selectedColor);
  923. }
  924. }
  925. }
  926. }
  927. SevenQueue.start();
  928. borderCoord1 = null;
  929. }
  930. break;
  931. }
  932. });
  933.  
  934. console.log('7Placer Loaded! Version: 1.5.0a');
  935. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址