MVPS

MVPS [Multi Visual Piano Script] designed to expand the technical and visual capabilities of the MPP

目前为 2023-02-14 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name MVPS
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.8
  5. // @description MVPS [Multi Visual Piano Script] designed to expand the technical and visual capabilities of the MPP
  6. // @author Hustandant#1917
  7. // @match *://mppclone.com/*
  8. // @include *://www.multiplayerpiano.com/*
  9. // @include *://multiplayerpiano.com/*
  10. // @include *://piano.ourworldofpixels.com/*
  11. // @include *://mppfork.netlify.app/*
  12. // @match *.mpp.hri7566.info/*
  13. // @match *://mpp.autoplayer.xyz/*
  14. // @icon https://github.com/Hustoroff/mpp/blob/main/icon.png?raw=true
  15. // @resource https://raw.githubusercontent.com/Hustoroff/mpp/main/MVPS.js
  16. // @grant none
  17. // @license MIT
  18. // @run-at document-end
  19. // ==/UserScript==
  20. window.addEventListener('load', (event) => {
  21. $("#bottom .relative").append(`<div id="MVPS" class="ugly-button 2_btn">MVPS</div>`);
  22. $("#MVPS").css({position: "absolute", left: "1020px", top: "32px"}).on("click", () => {
  23. MPP.client.emit("notification", {
  24. title: "Multi Visual Piano Script (by Hustandant#1917)",
  25. id:"MVPS_notification",
  26. duration:-1,
  27. target:"#MVPS",
  28. html:`
  29. <div id="visual_block" style="border-radius: 10px; background-color: #171115; border: 2px solid #333; padding: 4px 12px">
  30. <h3>Visual:</h3></p>
  31. <div id="chtClr" class="ugly-button">Clear chat</div>
  32. <div id="nmsHdn" class="ugly-button">Hide names</div>
  33. <input type="text" id="inpBack" placeholder="New backround (Image URL)"><button id="back">Background</button></input></br>
  34. Load background file:<input type="file" id="inpBackimg"></input>
  35. </div></br>
  36. <div id="drawBlock" style="border-radius: 10px; background-color: #171115; border: 2px solid #333; padding: 4px 12px">
  37. <h3>Drawing:</h3></p>
  38. <div id="clearBtn" class="ugly-button">Clear Drawings</div>
  39. <div id="drwbrdHdn" class="ugly-button">Drawboard hide</div>
  40. <div id="rnbwMd" class="ugly-button">Rainbow lines</div>
  41. <input id="lineTime" type="range" min="1" max="250" title="line lifetime"></input>
  42. <input id="clrChng" type="color"><button id="clrBtn">Select color</button></input>
  43. <input id="lineSize"type="range" min="1" max="10" title="brush size"></input></br>
  44. </div></br>
  45. <div id="otherBlock" style="border-radius: 10px; background-color: #171115; border: 2px solid #333; padding: 4px 12px">
  46. <h3>Other settings:</h3>
  47. <div id="rnbw" class="ugly-button" title="ANIME!?!?!??!?!?!??!?!??!?!">Rainbow room</div>
  48. <div id="rnbwNt" class="ugly-button">Rainbow notes</div>
  49. <div id="rnbwNick" class="ugly-button">Rainbow nick</div>
  50. <div id="pnoSpn" class="ugly-button">Spin piano</div>
  51. <input type="text" id="inpImg" placeholder="Paste image (Image URL)"><button id="pasteImg">Paste image</button></input></br>
  52. Load image file:</br><input type="file" id="inpPastImg"></input>
  53. </div>`
  54. });
  55. document.getElementById("chtClr").addEventListener("click", () => { chat_clear() });
  56. document.getElementById("nmsHdn").addEventListener("click", () => { names_hide = !names_hide; namesHde() });
  57. document.getElementById("inpBack").addEventListener("input", () => { url_back = document.getElementById("inpBack").value });
  58. document.getElementById("back").addEventListener("click", () => { backg = !backg; background_del(); });
  59. document.getElementById("inpBackimg").addEventListener("input", () => { showpreview1(document.getElementById("inpBackimg")) });
  60. document.getElementById("clearBtn").addEventListener("click", () => { MPP.addons.draw.lines = [[0,0,0,0,0,0,"#0"]] });
  61. document.getElementById("drwbrdHdn").addEventListener("click", () => { drawboard_hide = !drawboard_hide; drawboard_hde() });
  62. document.getElementById("rnbwMd").addEventListener("click", () => { rainbowmodename = !rainbowmodename });
  63. document.getElementById("lineTime").addEventListener("input", () => { MPP.addons.draw.lineLife = document.getElementById("lineTime").value });
  64. document.getElementById("clrBtn").addEventListener("click", () => { MPP.addons.draw.customColor=document.getElementById("clrChng").value });
  65. document.getElementById("lineSize").addEventListener("input", () => { MPP.addons.draw.brushSize = document.getElementById("lineSize").value });
  66. document.getElementById("rnbw").addEventListener("click", () => { rainbowmode = !rainbowmode });
  67. document.getElementById("rnbwNt").addEventListener("click", () => { rainbowmodenote = !rainbowmodenote });
  68. document.getElementById("rnbwNick").addEventListener("click", () => { rainbownick = !rainbownick });
  69. document.getElementById("pnoSpn").addEventListener("click", () => { pianospinbool = !pianospinbool; pianospn() });
  70. document.getElementById("inpImg").addEventListener("input", () => { url_past_img = document.getElementById("inpImg").value });
  71. document.getElementById("pasteImg").addEventListener("click", () => { paste_image(url_past_img) });
  72. document.getElementById("inpPastImg").addEventListener("input", () => { showpreview2(document.getElementById("inpPastImg")) });
  73. var pianospinbool = false,
  74. backimg = false,
  75. rainbowmodename = false,
  76. rainbowmodenote = false,
  77. rainbowmode = false,
  78. backg = false,
  79. piano = true,
  80. chat_hide = false,
  81. names_hide = false,
  82. drawboard_hide = true,
  83. rainbownick = false,
  84. url_past_img = "https://mpp.terrium.net/meow64.png",
  85. url_back = "https://steamuserimages-a.akamaihd.net/ugc/878625026160084538/0399E81B0D1CF96C853CFCC1288D3E0A3D708049/?imw=1024&imh=819&ima=fit&impolicy=Letterbox&imcolor=%23000000&letterbox=true";
  86. //MPP draw image script by Ledlamp [https://gist.github.com/ledlamp/ef0d4db05a49fb795ec59cf96bedbf26] (thx a lot :3)
  87. function paste_image(){
  88. function getRandomColor() {
  89. var letters = '0123456789ABCDEF';
  90. var color = '#';
  91. for (var i = 0; i < 6; i++) {
  92. color += letters[Math.floor(Math.random() * 16)];
  93. }
  94. return color;
  95. }
  96.  
  97. function drawPixel(x, y, color) {
  98. MPP.addons.draw.mkline(x-1,y,x,y,10,color)
  99. }
  100.  
  101. function componentToHex(c) {
  102. var hex = c.toString(16);
  103. return hex.length == 1 ? "0" + hex : hex;
  104. }
  105.  
  106. function rgbToHex(r, g, b) {
  107. return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
  108. }
  109. var img = document.createElement("img");
  110. img.crossOrigin = "Anonymous";
  111. img.addEventListener('load', function(){
  112. console.log(img);
  113. var canvas = document.createElement('canvas');
  114. canvas.width = img.width;
  115. canvas.height = img.height;
  116. var c = canvas.getContext('2d');
  117. c.drawImage(img, 0, 0, img.width, img.height);
  118. console.log(canvas);
  119. var pos1 = [128-img.width/2,128-img.height/2], pos2 = [128+img.width/2,128+img.height/2];
  120. var ii=0;
  121. for (let x = pos1[0], xo = 0; x < pos2[0]; x++, xo++)
  122. for (let y = pos1[1], yo = 0; y < pos2[1]; y++, yo++) {
  123. setTimeout(()=>{
  124. var rgb = c.getImageData(xo,yo, 1, 1).data;
  125. drawPixel(x,y, rgbToHex(rgb[0], rgb[1], rgb[2]));
  126. } ,++ii * 10);
  127. }
  128. });
  129. img.src = url_past_img;
  130. };
  131.  
  132. function showpreview1(e) {
  133. var reader = new FileReader();
  134. reader.onload = function (e) {
  135. url_back = e.target.result;
  136. background_del();
  137. };
  138. reader.readAsDataURL(e.files[0]);
  139. }
  140.  
  141. function showpreview2(e) {
  142. var reader = new FileReader();
  143. reader.onload = function (e) {
  144. url_past_img = e.target.result;
  145. };
  146. reader.readAsDataURL(e.files[0]);
  147. }
  148.  
  149. // DRAW script by Hri7566 [https://github.com/Hri7566] (thx a lot :3)
  150. let authenicated = false;
  151. EXT = window.EXT || {_initfunc: []};
  152.  
  153. setInterval(()=>{
  154. if(Object.entries(MPP.client.ppl).length !== 0 && !authenicated) {
  155. MPP.client.sendArray([{m:"+custom"}]);
  156.  
  157. MPP = MPP || {};
  158. MPP.addons = EXT;
  159. for(var x = EXT._initfunc.length; x--;)
  160. EXT._initfunc[x]();
  161. EXT.__proto__ = null;
  162. authenicated = true;
  163. }
  164. }, 100);
  165. /* By ming, v3 */
  166. EXT._initfunc.push(function(){
  167. var addon = EXT.draw = {__proto__: null};
  168. addon.lineLife = 25;
  169. var p = document.createElement("canvas");
  170. p.id = "drawboard";
  171. p.style = "position: absolute; top: 0; left: 0; z-index: 400; pointer-events: none;";
  172. p.width = window.innerWidth;
  173. p.height = window.innerHeight;
  174. document.body.appendChild(p);
  175. var dbctx = p.getContext("2d");
  176. var shifted = false;
  177. var clicking = false;
  178. $(document).on('mousedown', (e)=>{ if(e.shiftKey){ clicking = true; draw(); e.preventDefault(); }});
  179. $(document).on('mouseup', (e)=>{ clicking = false; });
  180. $(document).on('keyup keydown', (e)=>{ shifted = e.shiftKey; });
  181.  
  182. addon.enabled = true;
  183. addon.customColor = null;
  184. addon.ctx = dbctx;
  185. addon.onrefresh = [];
  186. addon.brushSize = 8;
  187. addon.mutes = [];
  188. addon.lines = [];
  189. addon.buf = [{n: "ldraw", v: 0}];
  190. function resize(){
  191. p.width = window.innerWidth;
  192. p.height = window.innerHeight;
  193. }
  194. window.addEventListener('resize', resize, false);
  195. addon.flushloop = setInterval(()=>{
  196. var t = Date.now();
  197. if(addon.buf.length != 1){
  198. if(addon.buf.length>1)
  199. MPP.client.sendArray([{m: "custom", data: {m: 'draw', t: t, n: addon.buf}, target: { mode: 'subscribed' } }]);
  200. addon.buf = [{n: "ldraw", v: 0}];
  201. }
  202. }, 1000/60/16);
  203. addon.onrefresh.push(function(t){
  204. if(addon.lines.length){
  205. dbctx.clearRect(0,0,window.innerWidth, window.innerHeight);
  206. for(var l = 0; l<addon.lines.length;l++){
  207. dbctx.globalAlpha = 1;
  208. var c=addon.lines[l];
  209. dbctx.strokeStyle = c[6];
  210. dbctx.lineWidth = c[5];
  211. var d = addon.lineLife - (t - c[4]) / 1000;
  212. if(d <= 0){
  213. addon.lines.splice(l--, 1);
  214. continue;
  215. }
  216. dbctx.globalAlpha = 0.3 * d;
  217. dbctx.beginPath();
  218. dbctx.moveTo(c[0], c[1]);
  219. dbctx.lineTo(c[2], c[3]);
  220. dbctx.stroke();
  221. }
  222. }
  223. });
  224. function redraw(){
  225. if(addon.enabled){
  226. var t = Date.now();
  227. for(var x = 0; x < addon.onrefresh.length; x++){
  228. addon.onrefresh[x](t);
  229. }
  230. }
  231. /*window.requestAnimationFrame(redraw);*/
  232. }
  233. /*window.requestAnimationFrame(redraw);*/
  234. setInterval(redraw, 1000/60/16);
  235. /* https://stackoverflow.com/a/8639991 */
  236. function stringToBytesFaster(str) {
  237. var ch, st, re = [], j=0;
  238. for (var i = 0; i < str.length; i++ ) {
  239. ch = str.charCodeAt(i);
  240. if(ch < 127){
  241. re[j++] = ch & 0xFF;
  242. } else {
  243. st = [];
  244. do {
  245. st.push(ch & 0xFF);
  246. ch = ch >> 8;
  247. } while (ch);
  248. st = st.reverse();
  249. for(var k=0;k<st.length; ++k)
  250. re[j++] = st[k];
  251. }
  252. }
  253. return re;
  254. }
  255. function parseLine(str, color, size){
  256. var vector = [0, 0, 0, 0, Date.now(), 1, color];
  257. var bytes = stringToBytesFaster(str);
  258. vector[0] = Math.round(((100 / 255) * bytes[0]/100) * window.innerWidth);
  259. vector[1] = Math.round(((100 / 255) * bytes[1]/100) * window.innerHeight);
  260. vector[2] = Math.round(((100 / 255) * bytes[2]/100) * window.innerWidth);
  261. vector[3] = Math.round(((100 / 255) * bytes[3]/100) * window.innerHeight);
  262. vector[5] = size;
  263. addon.lines.push(vector);
  264. }
  265. function draw(){
  266. var u = MPP.client.getOwnParticipant();
  267. u.y = Math.max(Math.min(100,u.y), 0);
  268. u.x = Math.max(Math.min(100,u.x), 0);
  269. var lastpos = [u.x, u.y];
  270. var b = new ArrayBuffer(4);
  271. var dv = new DataView(b);
  272. dv.setUint8(0, Math.round(u.x/100 * 255));
  273. dv.setUint8(1, Math.round(u.y/100 * 255));
  274. function poll(){
  275. if(lastpos[0] != u.x || lastpos[1] != u.y){
  276. u.y = Math.max(Math.min(100,u.y), 0);
  277. u.x = Math.max(Math.min(100,u.x), 0);
  278. dv.setUint8(2, Math.round(u.x/100 * 255));
  279. dv.setUint8(3, Math.round(u.y/100 * 255));
  280. var s = String.fromCharCode.apply(null, new Uint8Array(b));
  281. var clr = addon.customColor || MPP.client.getOwnParticipant().color;
  282. addon.buf.push({n: s, v: Math.min(addon.brushSize, 5), d: parseInt(clr.slice(1), 16)});
  283. dv.setUint8(0, Math.round(u.x/100 * 255));
  284. dv.setUint8(1, Math.round(u.y/100 * 255));
  285. lastpos = [u.x, u.y];
  286. parseLine(s, clr, Math.min(addon.brushSize, 5));
  287. }
  288. if(clicking)
  289. setTimeout(poll, 1);
  290. }
  291. setTimeout(poll, 1);
  292. }
  293.  
  294. addon.mkline = function(x, y, x2, y2, s, color){
  295. if(x<0||y<0||x2<0||y2<0||x>255||y>255||x2>255||y2>255)return;
  296. var b = new ArrayBuffer(4);
  297. var dv = new DataView(b);
  298. dv.setUint8(0, x);
  299. dv.setUint8(1, y);
  300. dv.setUint8(2, x2);
  301. dv.setUint8(3, y2);
  302. var str = String.fromCharCode.apply(null, new Uint8Array(b));
  303. var clr = color || addon.customColor || MPP.client.getOwnParticipant().color;
  304. addon.buf.push({n: str, v: Math.min(s||1, 5), d: parseInt(clr.slice(1), 16)});
  305. parseLine(str, clr, Math.min(s||1, 5));
  306. }
  307. addon.tohtml = function(c) {
  308. c = c.toString(16);
  309. return '#' + ('000000' + c).substring(c.length);
  310. };
  311. MPP.client.on('custom', (msg) => {
  312. if (msg.data.m !== 'draw') return;
  313. if(msg.data.n[0].n == "ldraw" && addon.mutes.indexOf(MPP.client.findParticipantById(msg.data.p)._id) === -1){
  314. msg.data.n.reduce(function(a, b){
  315. if(b.n.length == 4){
  316. var clr = (b.d !== undefined && addon.tohtml(b.d)) || MPP.client.findParticipantById(msg.data.p).color;
  317. parseLine(b.n, clr, Math.min(b.v,5));
  318. }
  319. });
  320. }
  321. });
  322. MPP.client.on('c', ()=>{
  323. addon.lines = [[0,0,0,0,0,0,"#0"]];
  324. });
  325. });
  326. function background_del(){
  327. if(backg) {
  328. var d=document.createElement('div');
  329. d.style.width = '1280px';
  330. d.style.height = '913px';
  331. d.style.position = 'absolute';
  332. d.style.top= '0px';
  333. d.style.left= '0px';
  334. d.id='backgdiv'
  335. document.body.appendChild(d);
  336. $("#backgdiv").css({width: window.innerWidth, height: window.innerHeight, "background-position": "25% 25%", "background-size": "cover", "backdrop-effect": "blur(4px)", "background-image": "url("+url_back+")"})
  337. console.log(url_back)
  338. } else $("#backgdiv").remove();
  339. }
  340.  
  341. function chat_clear(){ $('ul').empty() }
  342.  
  343. function namesHde(){
  344. if(names_hide) $("#names").css({opacity: "0"});
  345. else $("#names").css({opacity: "1"});
  346. }
  347.  
  348. function drawboard_hde(){
  349. if(drawboard_hide) $("#drawboard").css({opacity: "1"});
  350. else $("#drawboard").css({opacity: "0"});
  351. }
  352.  
  353. function pianospn(){ $("#piano").toggleClass("spin", pianospinbool) }
  354. //Rainbow room mode script
  355. var count = 0;
  356. var size = 100;
  357. var rainbow = new Array(size);
  358.  
  359. for (var i = 0; i < size; i++) {
  360. var red = sin_to_hex(i, 0 * Math.PI * 2 / 3); // 0 deg
  361. var blue = sin_to_hex(i, 1 * Math.PI * 2 / 3); // 120 deg
  362. var green = sin_to_hex(i, 2 * Math.PI * 2 / 3); // 240 deg
  363. rainbow[i] = "#" + red + green + blue;
  364. }
  365.  
  366. function sin_to_hex(i, phase) {
  367. var sin = Math.sin(Math.PI / size * 2 * i + phase);
  368. var int = Math.floor(sin * 127) + 128;
  369. var hex = int.toString(16);
  370. return hex.length === 1 ? "0" + hex : hex;
  371. }
  372.  
  373. setInterval(function() {
  374. if (count > rainbow.length) count = 0;
  375. if(rainbowmodename)
  376. MPP.addons.draw.customColor = rainbow[count]
  377. if(rainbowmodenote){
  378. id = MPP.client.getOwnParticipant();
  379. id.color = rainbow[count];
  380. }
  381. if(rainbownick)
  382. $("#namediv-"+MPP.client.getOwnParticipant().id).css({"background-color": rainbow[count]})
  383. count++;
  384. }, 33);
  385.  
  386. setInterval(function() {
  387. if (rainbowmode && MPP.client.isOwner()) {
  388. if (count > rainbow.length) count = 0;
  389. MPP.client.sendArray([{ m: "chset", set: { color: rainbow[count] } }]);
  390. }
  391. count++;
  392. }, 500);
  393. });
  394. });