HaxBall Map Picker

Load and Save maps from haxmaps just using an ID.

  1. // ==UserScript==
  2. // @name HaxBall Map Picker
  3. // @namespace https://gf.qytechs.cn/en/users/165127-hydrosaur
  4. // @version 3.0
  5. // @icon https://www.haxball.com/favicon.ico
  6. // @description Load and Save maps from haxmaps just using an ID.
  7. // @author -Electron-
  8. // @include https://www.haxball.com/FFuuq69i/__cache_static__/g/game.html
  9. // @supportURL https://www.reddit.com/message/compose/?to=-Electron-
  10. // @website https://redd.it/no-post-yet
  11. // @require https://code.jquery.com/jquery-latest.min.js
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17. let pickerPopupIsShown = false;
  18. let gamePageIsShown = false;
  19.  
  20. let haxMap = 0;
  21.  
  22. let favoritesListShown = false;
  23.  
  24. if(!localStorage.getItem("saved_maps")){
  25. localStorage.setItem("saved_maps", "{}");
  26. }
  27.  
  28. setInterval(function(){
  29. if($(".dialog.pick-stadium-view").length){
  30. if(!pickerPopupIsShown) showPicker();
  31. pickerPopupIsShown = true;
  32. } else {
  33. if(pickerPopupIsShown) hidePicker();
  34. pickerPopupIsShown = false;
  35. }
  36.  
  37. if($("button[data-hook='leave-btn']").length){
  38. if(!gamePageIsShown) gamePageShown();
  39. gamePageIsShown = true;
  40. } else {
  41. if(gamePageIsShown) gamePageHidden();
  42. gamePageIsShown = false;
  43. }
  44. }, 250);
  45.  
  46. function showPicker(){
  47. $(".dialog.pick-stadium-view h1").eq(0).append("<img class='loader' style='display: none' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAAIqSURBVDhPdVM9rCFRFB4FeaJQ0ChVEiT7si0iopBotbQUgqh0FKIVPxlvRSEhEXpR7q4NkQiVzXuLRCK6jUTjvWXunTt7zuyY4L39ki8zc+45537nZ7gP8Nnn8/HZbPalVCq9FYvFUygUegH7FzyTPf4DPbAeDocJY0y6RzweF3ieF91u95PiewM0/ABKcKugxMiAZGy5XNJarSbbD4cDA0VfwfcBAy+oA6VAIEC73S6Fm874zGQy1Gq1inhms9nYfr+XpWESl8uFSmRgXSyRSFCAqr1QKAhgl67p9/vFi0+v1zuD7ZHzer18Op0W7uuu1+v0PgEyGo2Sfr9Pm80mge8nDrtdrVb/KHEqOp3OOwUajUaaTCZ0t9tRSIQXLDkc1UcJyuUyNZvNcv0XRiIRqhxL6/UaEwhyglgsRsbjMcUyRFFE+WQ2m4mEEDYcDin2x26300sTEdgLvV5/5uDwp06nY3iDw+GgyWRS2G63ouKnApNiQuVTOp1OzGAwPHNarZa/lgmdVmVeYzQa0cVioSZuNBqv4F8CwihgjBiMNBqNTBCE25EAVqsVTaVSZD6f0+l0SoLB4G/w/wSUgXuuqoAxESVOxmazEWGR1IZaLJY3WKQavKvAVf7udDpJLpejMEJSqVSEdrtNW60WMZlMqkKF34A3q4x4wPUcDAb4M8klHI9HEZp6vVC4PKj23c90jUePx8ODkmcccT6ff4UF+gV2lKzW/A8c9xdfxQlApF7TUgAAAABJRU5ErkJggg==' />");
  48.  
  49. rotateForEver($(".dialog.pick-stadium-view h1 .loader"));
  50.  
  51. $(`<button data-hook="favorites">Favorites</button>`).insertAfter(".dialog.pick-stadium-view .buttons .file-btn");
  52. $(`<button data-hook="haxmapid">HaxMapID</button>`).insertAfter(".dialog.pick-stadium-view .buttons .file-btn");
  53. $(`<button data-hook="searchmaps">Search</button>`).insertAfter(".dialog.pick-stadium-view .buttons .file-btn");
  54. $("button[data-hook='haxmapid']").click(function(){
  55. let mapID = prompt("Map ID:");
  56.  
  57. if(!isNaN(Number(mapID)) && mapID){
  58.  
  59. changeStadium(mapID);
  60. } else {
  61. alert("Invalid Map ID")
  62. }
  63. });
  64.  
  65. $("button[data-hook='searchmaps']").click(function(){
  66. let mapSearch = prompt("Map Search:");
  67.  
  68. if(mapSearch){
  69. $(".dialog.pick-stadium-view .loader").css("display", "inline");
  70. fetch("https://streamlyne.stream:88/haxmaps/" + encodeURIComponent(mapSearch)).then(a => a.json()).then(json => {
  71. favoritesListShown = true;
  72.  
  73. $(".dialog.pick-stadium-view .list.ps").empty();
  74.  
  75. let savedMaps = json.maps;
  76.  
  77. savedMaps.forEach((item, idx) => {
  78. $(".dialog.pick-stadium-view .list.ps").append(`<div class="elem" data-id="${item.id}">DLS:<b>${item.downloads}</b>|${item.name}</div>`);
  79. });
  80.  
  81. $(".dialog.pick-stadium-view .list.ps .elem").click(function(){
  82. $(".selected").removeClass("selected");
  83. $(this).addClass("selected");
  84. $("button[data-hook='pick']").prop("disabled", false);
  85. });
  86.  
  87. $("button[data-hook='pick']").click(function(){
  88. console.log("cliq");
  89. if($(".dialog.pick-stadium-view .list.ps .selected").length){
  90. if(!isNaN(Number($(".dialog.pick-stadium-view .list.ps .selected").attr("data-id")))){
  91. changeStadium($(".dialog.pick-stadium-view .list.ps .selected").attr("data-id"));
  92. }
  93. }
  94. });
  95.  
  96. $(".dialog.pick-stadium-view .loader").hide();
  97. }).catch(function(){
  98. $(".dialog.pick-stadium-view .loader").hide();
  99. });
  100. }
  101. });
  102.  
  103. $("button[data-hook='favorites']").click(function(){
  104. favoritesListShown = true;
  105.  
  106. $(".dialog.pick-stadium-view .list.ps").empty();
  107.  
  108. let savedMaps = JSON.parse(localStorage.getItem("saved_maps"));
  109.  
  110. Object.keys(savedMaps).forEach((item, idx) => {
  111. $(".dialog.pick-stadium-view .list.ps").append(`<div class="elem" data-id="${savedMaps[item]}">${item}</div>`);
  112. });
  113.  
  114. $(".dialog.pick-stadium-view .list.ps .elem").click(function(){
  115. $(".selected").removeClass("selected");
  116. $(this).addClass("selected");
  117. $("button[data-hook='pick']").prop("disabled", false);
  118. });
  119.  
  120. $("button[data-hook='pick']").click(function(){
  121. console.log("cliq");
  122. if($(".dialog.pick-stadium-view .list.ps .selected").length){
  123. if(!isNaN(Number($(".dialog.pick-stadium-view .list.ps .selected").attr("data-id")))){
  124. changeStadium($(".dialog.pick-stadium-view .list.ps .selected").attr("data-id"));
  125. }
  126. }
  127. });
  128. });
  129. }
  130.  
  131. function hidePicker(){
  132. favoritesListShown = false;
  133. }
  134.  
  135. function gamePageShown(){
  136. if(!$("button[data-hook='addfavorites']").length){
  137. $(".settings").append("<button class='admin-only' data-hook='addfavorites' style='width: 100%'>Add Map To Favorites</button>");
  138.  
  139. $("button[data-hook='addfavorites']").click(function(){
  140. if(haxMap){
  141. let saved_maps = JSON.parse(localStorage.getItem("saved_maps"));
  142. let savedMapIDs = Object.values(saved_maps);
  143.  
  144. if(savedMapIDs.includes(Number(haxMap))){
  145. alert("You have already saved this map.");
  146. } else {
  147. saved_maps[$("label[data-hook='stadium-name']").text()] = Number(haxMap);
  148. localStorage.setItem("saved_maps", JSON.stringify(saved_maps));
  149. alert("Saved " + $("label[data-hook='stadium-name']").text());
  150. }
  151. } else {
  152. alert("You can only favorite maps that are uploaded to haxmaps.com");
  153. }
  154. });
  155. }
  156. }
  157.  
  158. function gamePageHidden(){
  159.  
  160. }
  161.  
  162. $("button[data-hook='pick']").click(function(){
  163. haxMap = 0;
  164. })
  165.  
  166. function searchForMaps(query){
  167. fetch("https://streamlyne.stream:88/proxy?link=http://haxmaps.com/hb/rpc").then(a => a.text()).then(text => {
  168. let listElems = $(text);
  169.  
  170. console.log(Array.from(listElems))
  171. });
  172. }
  173.  
  174. function linkToBlob(link){
  175. return new Promise(function(resolve, reject) {
  176. let xhr = new XMLHttpRequest();
  177. xhr.open("GET", link);
  178. xhr.responseType = "blob";//force the HTTP response, response-type header to be blob
  179. xhr.onload = function(){
  180. resolve(xhr.response);
  181. }
  182. xhr.send();
  183. });
  184. }
  185.  
  186. function getHaxBallMapText(id){
  187. return new Promise(function(resolve, reject) {
  188. fetch("https://streamlyne.stream:88/proxy?link=http://haxmaps.com/dl/" + id).then(a => a.text()).then(function(text){
  189. resolve(text);
  190. });
  191. });
  192. }
  193.  
  194. function changeStadium(id){
  195. getHaxBallMapText(id).then(text => {
  196. if(text.length > 2){
  197. changeStadiumFromText(text);
  198. haxMap = Number(id);
  199. } else {
  200. alert("Map ID out of range");
  201. }
  202. });
  203. }
  204.  
  205. function rotateForEver($elem, rotator) {
  206. if (rotator === void(0)) {
  207. rotator = $({deg: 0});
  208. } else {
  209. rotator.get(0).deg = 0;
  210. }
  211.  
  212. return rotator.animate(
  213. {deg: 360},
  214. {
  215. duration: 5000,
  216. easing: 'linear',
  217. step: function(now){
  218. $elem.css({transform: 'rotate(' + now + 'deg)'});
  219. },
  220. complete: function(){
  221. rotateForEver($elem, rotator);
  222. },
  223. }
  224. );
  225. }
  226.  
  227. function changeStadiumFromText(text){
  228. const dT = new ClipboardEvent('').clipboardData || // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
  229. new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
  230. dT.items.add(new File([text], 'programmatically_created.hbs'));
  231. console.log(text);
  232. document.getElementById("stadfile").files = dT.files;
  233. }
  234.  
  235. // Your code here...
  236. })();

QingJ © 2025

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