CheatGuessr | WorldGuessr Cheat

Extremely customizable WorldGuessr cheating client. Click 3 to open the settings menu.

目前为 2025-01-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name CheatGuessr | WorldGuessr Cheat
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Extremely customizable WorldGuessr cheating client. Click 3 to open the settings menu.
  6. // @author CheatGuessr
  7. // @match https://www.worldguessr.com/*
  8. // @grant none
  9. // @license GNU AGPLv3
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. let googleMapsIframe = null;
  16. let lastLocation = null;
  17. let loadingIndicator = null;
  18. let dotInterval = null;
  19. let settings = null;
  20. let settingsModal = null;
  21.  
  22. const DEFAULT_SETTINGS = {
  23. keybinds: {
  24. toggleMap: '1',
  25. newTab: '2',
  26. settings: '3'
  27. },
  28. mapPosition: 'top-left',
  29. mapSize: {
  30. width: 400,
  31. height: 300
  32. },
  33. loadingPosition: 'bottom',
  34. refreshInterval: 1000,
  35. blockAds: true
  36. };
  37.  
  38. const style = document.createElement('style');
  39. style.textContent = `
  40. .google-maps-iframe {
  41. position: fixed;
  42. z-index: 9999;
  43. border: 2px solid #333;
  44. border-radius: 4px;
  45. }
  46. .close-button {
  47. position: absolute;
  48. top: -15px;
  49. right: -15px;
  50. width: 30px;
  51. height: 30px;
  52. background: red;
  53. border: 2px solid white;
  54. border-radius: 50%;
  55. color: white;
  56. font-weight: bold;
  57. cursor: pointer;
  58. display: flex;
  59. align-items: center;
  60. justify-content: center;
  61. z-index: 10000;
  62. }
  63. .loading-indicator {
  64. position: fixed;
  65. left: 10px;
  66. padding: 5px 10px;
  67. background: rgba(0,0,0,0.7);
  68. color: white;
  69. border-radius: 4px;
  70. z-index: 9999;
  71. }
  72. .settings-modal {
  73. position: fixed;
  74. top: 50%;
  75. left: 50%;
  76. transform: translate(-50%, -50%);
  77. background: #1f2937;
  78. padding: 20px;
  79. border-radius: 8px;
  80. z-index: 10001;
  81. width: 600px;
  82. max-height: 80vh;
  83. overflow-y: auto;
  84. color: white;
  85. }
  86. .settings-backdrop {
  87. position: fixed;
  88. top: 0;
  89. left: 0;
  90. right: 0;
  91. bottom: 0;
  92. background: rgba(0,0,0,0.5);
  93. z-index: 10000;
  94. }
  95. .settings-grid {
  96. display: grid;
  97. grid-template-columns: 1fr 1fr;
  98. gap: 20px;
  99. }
  100. .settings-section {
  101. background: #374151;
  102. padding: 15px;
  103. border-radius: 6px;
  104. }
  105. .settings-row {
  106. margin: 10px 0;
  107. }
  108. .settings-row label {
  109. display: block;
  110. margin-bottom: 5px;
  111. color: #e5e7eb;
  112. }
  113. .settings-input {
  114. width: 100%;
  115. padding: 8px;
  116. border: 1px solid #4b5563;
  117. border-radius: 4px;
  118. background: #1f2937;
  119. color: white;
  120. }
  121. .settings-button {
  122. padding: 8px 16px;
  123. border: none;
  124. border-radius: 4px;
  125. cursor: pointer;
  126. margin: 5px;
  127. background: #3b82f6;
  128. color: white;
  129. }
  130. .settings-button:hover {
  131. background: #2563eb;
  132. }
  133. `;
  134. document.head.appendChild(style);
  135.  
  136. function loadSettings() {
  137. try {
  138. const saved = localStorage.getItem('worldGuessrHelper');
  139. settings = saved ? JSON.parse(saved) : DEFAULT_SETTINGS;
  140. } catch (e) {
  141. settings = DEFAULT_SETTINGS;
  142. }
  143. }
  144.  
  145. function saveSettings() {
  146. localStorage.setItem('worldGuessrHelper', JSON.stringify(settings));
  147. }
  148.  
  149. function blockAds() {
  150. if (!settings.blockAds) return;
  151.  
  152. const adSelectors = [
  153. '[id^="google_ads_iframe"]',
  154. '[id^="worldguessr-com_"]',
  155. '.video-ad',
  156. '[class*="banner"]',
  157. '[id*="banner"]'
  158. ];
  159.  
  160. const removeAds = () => {
  161. adSelectors.forEach(selector => {
  162. document.querySelectorAll(selector).forEach(ad => {
  163. ad.remove();
  164. });
  165. });
  166. };
  167.  
  168. removeAds();
  169.  
  170. const observer = new MutationObserver(removeAds);
  171. observer.observe(document.body, {
  172. childList: true,
  173. subtree: true
  174. });
  175. }
  176.  
  177. function createLoadingIndicator() {
  178. loadingIndicator = document.createElement('div');
  179. loadingIndicator.className = 'loading-indicator';
  180. loadingIndicator.style.display = 'none';
  181. document.body.appendChild(loadingIndicator);
  182.  
  183. let dots = 0;
  184. if (dotInterval) clearInterval(dotInterval);
  185.  
  186. dotInterval = setInterval(() => {
  187. dots = (dots + 1) % 4;
  188. if (loadingIndicator) {
  189. loadingIndicator.textContent = 'Loading location' + '.'.repeat(dots);
  190. }
  191. }, 500);
  192. }
  193.  
  194. function toggleSettingsModal() {
  195. if (settingsModal) {
  196. settingsModal.backdrop.remove();
  197. settingsModal.modal.remove();
  198. settingsModal = null;
  199. return;
  200. }
  201.  
  202. const backdrop = document.createElement('div');
  203. backdrop.className = 'settings-backdrop';
  204.  
  205. const modal = document.createElement('div');
  206. modal.className = 'settings-modal';
  207. modal.innerHTML = `
  208. <h2 style="margin-bottom: 20px">WorldGuessr Helper Settings</h2>
  209. <div class="settings-grid">
  210. <div class="settings-section">
  211. <h3>Keybinds</h3>
  212. <div class="settings-row">
  213. <label>Toggle Map Key</label>
  214. <input type="text" class="settings-input" id="toggleMapKey" value="${settings.keybinds.toggleMap}">
  215. </div>
  216. <div class="settings-row">
  217. <label>New Tab Key</label>
  218. <input type="text" class="settings-input" id="newTabKey" value="${settings.keybinds.newTab}">
  219. </div>
  220. <div class="settings-row">
  221. <label>Settings Key</label>
  222. <input type="text" class="settings-input" id="settingsKey" value="${settings.keybinds.settings}">
  223. </div>
  224. </div>
  225. <div class="settings-section">
  226. <h3>Map Settings</h3>
  227. <div class="settings-row">
  228. <label>Map Position</label>
  229. <select class="settings-input" id="mapPosition">
  230. <option value="top-left" ${settings.mapPosition === 'top-left' ? 'selected' : ''}>Top Left</option>
  231. <option value="top-right" ${settings.mapPosition === 'top-right' ? 'selected' : ''}>Top Right</option>
  232. <option value="bottom-left" ${settings.mapPosition === 'bottom-left' ? 'selected' : ''}>Bottom Left</option>
  233. <option value="bottom-right" ${settings.mapPosition === 'bottom-right' ? 'selected' : ''}>Bottom Right</option>
  234. </select>
  235. </div>
  236. <div class="settings-row">
  237. <label>Map Width (px)</label>
  238. <input type="number" class="settings-input" id="mapWidth" value="${settings.mapSize.width}">
  239. </div>
  240. <div class="settings-row">
  241. <label>Map Height (px)</label>
  242. <input type="number" class="settings-input" id="mapHeight" value="${settings.mapSize.height}">
  243. </div>
  244. </div>
  245. </div>
  246. <div class="settings-section" style="margin-top: 20px">
  247. <h3>Additional Settings</h3>
  248. <div class="settings-row">
  249. <label>
  250. <input type="checkbox" id="blockAds" ${settings.blockAds ? 'checked' : ''}>
  251. Block Advertisements
  252. </label>
  253. </div>
  254. </div>
  255. <div style="text-align: right; margin-top: 20px">
  256. <button class="settings-button" id="closeSettings">Cancel</button>
  257. <button class="settings-button" id="saveSettings">Save</button>
  258. </div>
  259. `;
  260.  
  261. document.body.appendChild(backdrop);
  262. document.body.appendChild(modal);
  263.  
  264. settingsModal = { backdrop, modal };
  265.  
  266. document.getElementById('saveSettings').onclick = () => {
  267. settings.keybinds.toggleMap = document.getElementById('toggleMapKey').value;
  268. settings.keybinds.newTab = document.getElementById('newTabKey').value;
  269. settings.keybinds.settings = document.getElementById('settingsKey').value;
  270. settings.mapPosition = document.getElementById('mapPosition').value;
  271. settings.mapSize.width = parseInt(document.getElementById('mapWidth').value);
  272. settings.mapSize.height = parseInt(document.getElementById('mapHeight').value);
  273. settings.blockAds = document.getElementById('blockAds').checked;
  274.  
  275. saveSettings();
  276. blockAds();
  277. toggleSettingsModal();
  278. };
  279.  
  280. document.getElementById('closeSettings').onclick = toggleSettingsModal;
  281. }
  282.  
  283. function showLoadingIndicator() {
  284. if (loadingIndicator) {
  285. loadingIndicator.style.display = 'block';
  286. loadingIndicator.style.bottom = settings.loadingPosition === 'bottom' ? '10px' : 'auto';
  287. loadingIndicator.style.top = settings.loadingPosition === 'top' ? '10px' : 'auto';
  288. }
  289. }
  290.  
  291. function hideLoadingIndicator() {
  292. if (loadingIndicator) {
  293. loadingIndicator.style.display = 'none';
  294. }
  295. }
  296.  
  297. function extractLocationFromIframe() {
  298. showLoadingIndicator();
  299. const iframe = document.querySelector('iframe[src^="/svEmbed"]');
  300. if (!iframe) {
  301. hideLoadingIndicator();
  302. return null;
  303. }
  304.  
  305. const urlParams = new URLSearchParams(iframe.src.split('?')[1]);
  306. const lat = parseFloat(urlParams.get('lat'));
  307. const long = parseFloat(urlParams.get('long'));
  308.  
  309. if (!isNaN(lat) && !isNaN(long)) {
  310. hideLoadingIndicator();
  311. return { lat, long, timestamp: new Date() };
  312. }
  313. hideLoadingIndicator();
  314. return null;
  315. }
  316.  
  317. function updateMapPosition() {
  318. if (!googleMapsIframe) return;
  319.  
  320. const pos = settings.mapPosition.split('-');
  321. googleMapsIframe.style.top = pos[0] === 'top' ? '10px' : 'auto';
  322. googleMapsIframe.style.bottom = pos[0] === 'bottom' ? '10px' : 'auto';
  323. googleMapsIframe.style.left = pos[1] === 'left' ? '10px' : 'auto';
  324. googleMapsIframe.style.right = pos[1] === 'right' ? '10px' : 'auto';
  325. googleMapsIframe.style.width = settings.mapSize.width + 'px';
  326. googleMapsIframe.style.height = settings.mapSize.height + 'px';
  327. }
  328.  
  329. function toggleGoogleMapsIframe(location) {
  330. if (!location) return;
  331.  
  332. if (googleMapsIframe) {
  333. googleMapsIframe.remove();
  334. googleMapsIframe = null;
  335. return;
  336. }
  337.  
  338. try {
  339. const container = document.createElement('div');
  340. container.className = 'google-maps-iframe';
  341.  
  342. const closeBtn = document.createElement('button');
  343. closeBtn.className = 'close-button';
  344. closeBtn.textContent = '×';
  345. closeBtn.onclick = () => {
  346. container.remove();
  347. googleMapsIframe = null;
  348. };
  349.  
  350. const iframe = document.createElement('iframe');
  351. iframe.width = '100%';
  352. iframe.height = '100%';
  353. iframe.style.border = 'none';
  354. iframe.src = "https://www.google.com/maps?q=" + location.lat + "," + location.long + "&z=18&output=embed";
  355.  
  356. container.appendChild(closeBtn);
  357. container.appendChild(iframe);
  358. document.body.appendChild(container);
  359. googleMapsIframe = container;
  360. updateMapPosition();
  361. } catch (error) {
  362. console.error('Error creating iframe:', error);
  363. }
  364. }
  365.  
  366. window.addEventListener('keydown', function(event) {
  367. event.stopPropagation();
  368.  
  369. const location = extractLocationFromIframe();
  370. if (!location) return;
  371.  
  372. if (lastLocation && (lastLocation.lat !== location.lat || lastLocation.long !== location.long)) {
  373. if (googleMapsIframe) {
  374. toggleGoogleMapsIframe(location);
  375. toggleGoogleMapsIframe(location);
  376. }
  377. }
  378. lastLocation = location;
  379.  
  380. if (event.key === settings.keybinds.toggleMap) {
  381. toggleGoogleMapsIframe(location);
  382. } else if (event.key === settings.keybinds.newTab) {
  383. window.open("https://www.google.com/maps?q=" + location.lat + "," + location.long, "_blank");
  384. } else if (event.key === settings.keybinds.settings) {
  385. if (googleMapsIframe) {
  386. toggleGoogleMapsIframe(location);
  387. }
  388. toggleSettingsModal();
  389. }
  390. }, true);
  391.  
  392. loadSettings();
  393. createLoadingIndicator();
  394. blockAds();
  395.  
  396. setInterval(() => {
  397. const location = extractLocationFromIframe();
  398. if (!location || !lastLocation) return;
  399.  
  400. if (lastLocation.lat !== location.lat || lastLocation.long !== location.long) {
  401. if (googleMapsIframe) {
  402. toggleGoogleMapsIframe(location);
  403. toggleGoogleMapsIframe(location);
  404. }
  405. lastLocation = location;
  406. }
  407. }, settings.refreshInterval);
  408.  
  409. const observer = new MutationObserver(() => {
  410. if (!document.querySelector('iframe[src^="/svEmbed"]') && googleMapsIframe) {
  411. googleMapsIframe.remove();
  412. googleMapsIframe = null;
  413. }
  414. });
  415.  
  416. observer.observe(document.body, { childList: true, subtree: true });
  417. })();

QingJ © 2025

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