PPPC

Pixel Place Parallel Connections

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/443907/1050383/PPPC.js

  1. // ==UserScript==
  2. // @name PPPC
  3. // @description Pixel Place Parallel Connections
  4. // @version 1.6.2
  5. // @author 0vC4
  6. // @namespace https://greasyfork.org/users/670183
  7. // @match https://pixelplace.io/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=pixelplace.io
  9. // @license MIT
  10. // @grant none
  11. // @run-at document-start
  12. // ==/UserScript==
  13. (() => {
  14. const PPClient = window.PPClient || {modules:{}};
  15. window.PPClient = PPClient;
  16. if ('Connect' in PPClient.modules) return;
  17.  
  18.  
  19.  
  20. const pongAlive = () => {
  21. const {random} = Math;
  22. const word = 'gmbozcfxta';
  23. function hash(size) {
  24. const arr = [];
  25. const str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  26. for (var i = 0; i < size; i++) arr.push(str[random()*str.length | 0]);
  27. return arr.join('');
  28. }
  29. function hash2(size) {
  30. const arr = [];
  31. const str = "gmbonjklezcfxtaGMBONJKLEZCFXTA";
  32. for (var i = 0; i < size; i++) arr.push(str[random()*str.length | 0]);
  33. return arr.join('');
  34. }
  35. let result = '';
  36. const seed = (((new Date().getTime()/1e3|0) + 1678) + '').split('');
  37. const arr = [hash(5),hash(7),hash2(3),hash(8),hash2(6),hash(3),hash(6),hash2(4),hash(7),hash(6)];
  38. for (const i in seed) {
  39. result += arr[i];
  40. result += !(random()*2|0) ? word[+seed[i]].toUpperCase() : word[+seed[i]];
  41. }
  42. result += '0=';
  43. return `42["pong.alive","${result}"]`;
  44. };
  45.  
  46.  
  47.  
  48. const module = {
  49. bots: [],
  50. settings: new Proxy(JSON.parse(localStorage.getItem('settings')||'{}'), {
  51. get(target, key) {
  52. return target[key];
  53. },
  54. set(target, key, value) {
  55. target[key] = value;
  56. localStorage.setItem('settings', JSON.stringify(target));
  57. return true;
  58. },
  59. remove(target, key) {
  60. delete target[key];
  61. localStorage.setItem('settings', JSON.stringify(target));
  62. return true;
  63. }
  64. })
  65. };
  66. module.args = {};
  67. module.config = ({timer}) => Object.assign(module.args, {timer});
  68.  
  69.  
  70.  
  71. const {settings} = module;
  72. Object.assign(module, {
  73. async show() {
  74. return JSON.stringify([
  75. (await cookieStore.get('authId')).value,
  76. (await cookieStore.get('authToken')).value,
  77. (await cookieStore.get('authKey')).value
  78. ]);
  79. },
  80. async add(username, scheme) {
  81. settings.userlist[username] = typeof scheme == 'string' ? JSON.parse(scheme) : scheme;
  82. return true;
  83. },
  84. async remove(username) {
  85. delete settings.userlist[username];
  86. return true;
  87. },
  88. async save() {
  89. settings.current = {
  90. authId: (await cookieStore.get('authId')).value,
  91. authToken: (await cookieStore.get('authToken')).value,
  92. authKey: (await cookieStore.get('authKey')).value
  93. };
  94. },
  95. async load(scheme = null) {
  96. await cookieStore.set('authId', scheme ? scheme[0] : settings.current.authId);
  97. await cookieStore.set('authToken', scheme ? scheme[1] : settings.current.authToken);
  98. await cookieStore.set('authKey', scheme ? scheme[2] : settings.current.authKey);
  99. },
  100. async join(username, server) {
  101. if (!settings.userlist[username]) return null;
  102. const [id, token, key] = settings.userlist[username];
  103. await module.save();
  104. await cookieStore.set('authId', id);
  105. await cookieStore.set('authToken', token);
  106. await cookieStore.set('authKey', key);
  107. await fetch(`https://pixelplace.io/api/get-painting.php?id=${server}&connected=1`);
  108. if (!(await cookieStore.get('authToken'))) {
  109. console.log(
  110. username,
  111. "is banned or it has wrong data, please remove this account using PPClient.remove('",
  112. username,
  113. "');"
  114. );
  115. await module.load();
  116. return null;
  117. }
  118. settings.userlist[username] = [
  119. (await cookieStore.get('authId')).value,
  120. (await cookieStore.get('authToken')).value,
  121. (await cookieStore.get('authKey')).value
  122. ];
  123. await module.load();
  124.  
  125. return settings.userlist[username];
  126. },
  127. async connect(username, boardId) {
  128. const result = await module.join(username, boardId);
  129. if (!result) return null;
  130. if (module.bots.find(ws => ws.username == username)) return null;
  131. const [authId, authToken, authKey] = result;
  132. const restart = () => {
  133. const {timer} = module.args;
  134. const user = new WebSocket('wss://pixelplace.io/socket.io/?EIO=3&transport=websocket');
  135. user.username = username;
  136. user.serverId = boardId;
  137. user.onmessage = ({data}) => {
  138. const [code, msg] = data.split(/(?<=^\d+)(?=[^\d])/);
  139. if (code == '40') user.send('42' + JSON.stringify(
  140. ["init", { authKey, authToken, authId, boardId }]
  141. ));
  142. const message = JSON.parse(msg || '[]');
  143. if (message.pingInterval) user.ping = timer.setInterval(() => user.send('2'), message.pingInterval);
  144. if (!message.length) return arguments;
  145. const [event, json] = message;
  146. if (event == 'throw.error' && ![3].includes(json)) {
  147. user.kick = true;
  148. user.close();
  149. }
  150. if (event == 'canvas.alert' && json.includes('Your account')) {
  151. console.log('Banned, reason: ', json);
  152. user.kick = true;
  153. user.close();
  154. }
  155. if (event == 'ping.alive') user.send(pongAlive());
  156. if (event == 'canvas') {
  157. user.ready = true;
  158. console.log(username, 'bot connected');
  159. }
  160. if (event == 'p') user.count = PPClient.config.packetCount;
  161. };
  162. user.onclose = async () => {
  163. timer.clearInterval(user.ping);
  164. module.bots.splice(module.bots.indexOf(user), 1);
  165. if (!user.kick) {
  166. console.log(username, 'bot restarting');
  167. restart();
  168. } else {
  169. console.log(username, 'bot disconnected');
  170. }
  171. };
  172. user.set = (x,y,p) => user.send(`42["p",[${x},${y},${p},1]]`);
  173. module.bots.push(user);
  174.  
  175. return user;
  176. };
  177. return restart();
  178. },
  179.  
  180. async connectAll(serverId) {
  181. const names = Object.keys(settings.userlist);
  182. const arr = [];
  183.  
  184. let n = 0;
  185. for (let i = 0; i < names.length; i++) {
  186. let ws = null;
  187.  
  188. try {
  189. ws = await module.connect(names[i], serverId);
  190. } catch (e) {
  191. ws = null;
  192. }
  193.  
  194. if (!ws) {
  195. n++;
  196. continue;
  197. }
  198.  
  199. arr[i-n] = ws;
  200. ws.addEventListener('close', e => arr.splice(arr.indexOf(ws), 1));
  201. }
  202.  
  203. console.log(names.length-n, 'bots connected');
  204. return arr;
  205. },
  206.  
  207.  
  208.  
  209. async disconnect(...usernames){
  210. usernames = usernames.flat();
  211. module.bots.filter(Boolean).map(ws => {
  212. if (!ws || !ws.close) return;
  213. ws.ignore = true;
  214. ws.kick = true;
  215. if (!usernames.length) return ws.close();
  216. if (usernames.includes(ws.username)) return ws.close();
  217. });
  218. }
  219. });
  220. if (!settings.userlist) settings.userlist = {};
  221.  
  222.  
  223.  
  224. PPClient.connect = async (username) => await module.connect(username, PPClient.serverId);
  225. PPClient.connectAll = async () => await module.connectAll(PPClient.serverId);
  226. PPClient.disconnect = module.disconnect;
  227. PPClient.link = async (username) => await module.add(username, JSON.parse(await module.show()));
  228. PPClient.show = module.show;
  229. PPClient.add = module.add;
  230. PPClient.remove = module.remove;
  231. Object.defineProperty(PPClient, 'userlist', {enumerable:true,configurable:true,get(){
  232. return settings.userlist;
  233. }});
  234. PPClient.modules.Connect = module;
  235. })();
  236. // 0vC4#7152