CheatGuessr | GeoGuessr Cheat

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

安装此脚本?
作者推荐脚本

您可能也喜欢CheatGuessr | WorldGuessr Cheat

安装此脚本
  1. // ==UserScript==
  2. // @name CheatGuessr | GeoGuessr Cheat
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Extremely customizable GeoGuessr cheating client. Click 3 to open the settings menu.
  6. // @author CheatGuessr
  7. // @match https://www.geoguessr.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
  9. // @grant GM_webRequest
  10. // @license GNU AGPLv3
  11. // ==/UserScript==
  12.  
  13. let globalCoordinates = {
  14. lat: 0,
  15. lng: 0
  16. };
  17.  
  18. let googleMapsIframe = null;
  19. let settingsModal = null;
  20.  
  21. const DEFAULT_SETTINGS = {
  22. keybinds: {
  23. toggleMap: '1',
  24. newTab: '2',
  25. settings: '3',
  26. detailedLocation: '4',
  27. pinpoint: '5',
  28. nearbypinpoint: '6'
  29. },
  30. mapPosition: 'top-left',
  31. mapSize: {
  32. width: 400,
  33. height: 300
  34. },
  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. let settings = null;
  137.  
  138. function loadSettings() {
  139. try {
  140. const saved = localStorage.getItem('geoGuessrHelper');
  141. settings = saved ? JSON.parse(saved) : DEFAULT_SETTINGS;
  142. } catch (e) {
  143. settings = DEFAULT_SETTINGS;
  144. }
  145. }
  146.  
  147. function saveSettings() {
  148. localStorage.setItem('geoGuessrHelper', JSON.stringify(settings));
  149. }
  150.  
  151. var originalOpen = XMLHttpRequest.prototype.open;
  152. XMLHttpRequest.prototype.open = function(method, url) {
  153. if (method.toUpperCase() === 'POST' &&
  154. (url.startsWith('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata') ||
  155. url.startsWith('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/SingleImageSearch'))) {
  156.  
  157. this.addEventListener('load', function () {
  158. let interceptedResult = this.responseText;
  159. const pattern = /-?\d+\.\d+,-?\d+\.\d+/g;
  160. let match = interceptedResult.match(pattern)[0];
  161. let split = match.split(",");
  162.  
  163. let lat = Number.parseFloat(split[0]);
  164. let lng = Number.parseFloat(split[1]);
  165.  
  166. globalCoordinates.lat = lat;
  167. globalCoordinates.lng = lng;
  168. });
  169. }
  170. return originalOpen.apply(this, arguments);
  171. };
  172.  
  173. async function fetchLocationDetails(lat, lng) {
  174. try {
  175. const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`);
  176. if (!response.ok) {
  177. throw new Error('Failed to fetch location details');
  178. }
  179. const data = await response.json();
  180. const { address } = data;
  181. const locationDetails = `
  182. Area: ${address.neighbourhood || address.suburb || address.hamlet || 'N/A'}
  183. City: ${address.city || address.town || address.village || 'N/A'}
  184. State: ${address.state || 'N/A'}
  185. Country: ${address.country || 'N/A'}
  186. `;
  187. alert(locationDetails);
  188. } catch (error) {
  189. alert('Could not fetch location details: ' + error.message);
  190. }
  191. }
  192.  
  193. function placeMarker(safeMode) {
  194. let { lat, lng } = globalCoordinates;
  195.  
  196. if (safeMode) {
  197. const sway = [Math.random() > 0.5, Math.random() > 0.5];
  198. const multiplier = Math.random() * 4;
  199. const horizontalAmount = Math.random() * multiplier;
  200. const verticalAmount = Math.random() * multiplier;
  201. sway[0] ? lat += verticalAmount : lat -= verticalAmount;
  202. sway[1] ? lng += horizontalAmount : lat -= horizontalAmount;
  203. }
  204.  
  205. let element = document.querySelectorAll('[class^="guess-map_canvas__"]')[0];
  206. if (!element) {
  207. placeMarkerStreaks();
  208. return;
  209. }
  210.  
  211. const latLngFns = {
  212. latLng: {
  213. lat: () => lat,
  214. lng: () => lng,
  215. }
  216. };
  217.  
  218. const reactKeys = Object.keys(element);
  219. const reactKey = reactKeys.find(key => key.startsWith("__reactFiber$"));
  220. const elementProps = element[reactKey];
  221. const mapElementClick = elementProps.return.return.memoizedProps.map.__e3_.click;
  222. const mapElementPropKey = Object.keys(mapElementClick)[0];
  223. const mapClickProps = mapElementClick[mapElementPropKey];
  224. const mapClickPropKeys = Object.keys(mapClickProps);
  225.  
  226. for (let i = 0; i < mapClickPropKeys.length; i++) {
  227. if (typeof mapClickProps[mapClickPropKeys[i]] === "function") {
  228. mapClickProps[mapClickPropKeys[i]](latLngFns);
  229. }
  230. }
  231. }
  232.  
  233. function placeMarkerStreaks() {
  234. let { lat, lng } = globalCoordinates;
  235. let element = document.getElementsByClassName("region-map_mapCanvas__0dWlf")[0];
  236. if (!element) {
  237. return;
  238. }
  239. const reactKeys = Object.keys(element);
  240. const reactKey = reactKeys.find(key => key.startsWith("__reactFiber$"));
  241. const elementProps = element[reactKey];
  242. const mapElementClick = elementProps.return.return.memoizedProps.map.__e3_.click;
  243. const mapElementClickKeys = Object.keys(mapElementClick);
  244. const functionString = "(e.latLng.lat(),e.latLng.lng())}";
  245. const latLngFn = {
  246. latLng: {
  247. lat: () => lat,
  248. lng: () => lng,
  249. }
  250. };
  251.  
  252. for (let i = 0; i < mapElementClickKeys.length; i++) {
  253. const curr = Object.keys(mapElementClick[mapElementClickKeys[i]]);
  254. let func = curr.find(l => typeof mapElementClick[mapElementClickKeys[i]][l] === "function");
  255. let prop = mapElementClick[mapElementClickKeys[i]][func];
  256. if (prop && prop.toString().slice(5) === functionString) {
  257. prop(latLngFn);
  258. }
  259. }
  260. }
  261.  
  262. function mapsFromCoords() {
  263. const { lat, lng } = globalCoordinates;
  264. if (!lat || !lng) {
  265. return;
  266. }
  267.  
  268. window.open(`https://maps.google.com/?output=embed&q=${lat},${lng}&ll=${lat},${lng}&z=5`);
  269. }
  270.  
  271. function toggleSettingsModal() {
  272. if (settingsModal) {
  273. settingsModal.backdrop.remove();
  274. settingsModal.modal.remove();
  275. settingsModal = null;
  276. return;
  277. }
  278.  
  279. const backdrop = document.createElement('div');
  280. backdrop.className = 'settings-backdrop';
  281.  
  282. const modal = document.createElement('div');
  283. modal.className = 'settings-modal';
  284. modal.innerHTML = `
  285. <h2 style="margin-bottom: 20px">GeoGuessr Helper Settings</h2>
  286. <div class="settings-grid">
  287. <div class="settings-section">
  288. <h3>Keybinds</h3>
  289. <div class="settings-row">
  290. <label>Toggle Map Key</label>
  291. <input type="text" class="settings-input" id="toggleMapKey" value="${settings.keybinds.toggleMap}">
  292. </div>
  293. <div class="settings-row">
  294. <label>New Tab Key</label>
  295. <input type="text" class="settings-input" id="newTabKey" value="${settings.keybinds.newTab}">
  296. </div>
  297. <div class="settings-row">
  298. <label>Settings Key</label>
  299. <input type="text" class="settings-input" id="settingsKey" value="${settings.keybinds.settings}">
  300. </div>
  301. <div class="settings-row">
  302. <label>Detailed Location Key</label>
  303. <input type="text" class="settings-input" id="detailedLocationKey" value="${settings.keybinds.detailedLocation}">
  304. </div>
  305. <div class="settings-row">
  306. <label>Score 5000 Points</label>
  307. <input type="text" class="settings-input" id="pinpointKey" value="${settings.keybinds.pinpoint}">
  308. </div>
  309. <div class="settings-row">
  310. <label>Score Between 4500-5000 Points</label>
  311. <input type="text" class="settings-input" id="nearbyPinpointKey" value="${settings.keybinds.nearbypinpoint}">
  312. </div>
  313. </div>
  314. <div class="settings-section">
  315. <h3>Map Settings</h3>
  316. <div class="settings-row">
  317. <label>Map Position</label>
  318. <select class="settings-input" id="mapPosition">
  319. <option value="top-left" ${settings.mapPosition === 'top-left' ? 'selected' : ''}>Top Left</option>
  320. <option value="top-right" ${settings.mapPosition === 'top-right' ? 'selected' : ''}>Top Right</option>
  321. <option value="bottom-left" ${settings.mapPosition === 'bottom-left' ? 'selected' : ''}>Bottom Left</option>
  322. <option value="bottom-right" ${settings.mapPosition === 'bottom-right' ? 'selected' : ''}>Bottom Right</option>
  323. </select>
  324. </div>
  325. <div class="settings-row">
  326. <label>Map Width (px)</label>
  327. <input type="number" class="settings-input" id="mapWidth" value="${settings.mapSize.width}">
  328. </div>
  329. <div class="settings-row">
  330. <label>Map Height (px)</label>
  331. <input type="number" class="settings-input" id="mapHeight" value="${settings.mapSize.height}">
  332. </div>
  333. </div>
  334. </div>
  335. <div class="settings-section" style="margin-top: 20px">
  336. <h3>Additional Settings</h3>
  337. <div class="settings-row">
  338. <label>
  339. <input type="checkbox" id="blockAds" ${settings.blockAds ? 'checked' : ''}>
  340. Block Advertisements
  341. </label>
  342. </div>
  343. </div>
  344. <div style="text-align: right; margin-top: 20px">
  345. <button class="settings-button" id="closeSettings">Cancel</button>
  346. <button class="settings-button" id="saveSettings">Save</button>
  347. </div>
  348. `;
  349.  
  350. document.body.appendChild(backdrop);
  351. document.body.appendChild(modal);
  352.  
  353. settingsModal = { backdrop, modal };
  354.  
  355. document.getElementById('saveSettings').onclick = () => {
  356. settings.keybinds.toggleMap = document.getElementById('toggleMapKey').value;
  357. settings.keybinds.newTab = document.getElementById('newTabKey').value;
  358. settings.keybinds.settings = document.getElementById('settingsKey').value;
  359. settings.keybinds.detailedLocation = document.getElementById('detailedLocationKey').value;
  360. settings.keybinds.pinpoint = document.getElementById('pinpointKey').value;
  361. settings.keybinds.nearbypinpoint = document.getElementById('nearbyPinpointKey').value;
  362. settings.mapPosition = document.getElementById('mapPosition').value;
  363. settings.mapSize.width = parseInt(document.getElementById('mapWidth').value);
  364. settings.mapSize.height = parseInt(document.getElementById('mapHeight').value);
  365. settings.blockAds = document.getElementById('blockAds').checked;
  366.  
  367. saveSettings();
  368. toggleSettingsModal();
  369. };
  370.  
  371. document.getElementById('closeSettings').onclick = toggleSettingsModal;
  372. }
  373.  
  374. function toggleGoogleMapsIframe(location) {
  375. if (!location) return;
  376.  
  377. if (googleMapsIframe) {
  378. googleMapsIframe.remove();
  379. googleMapsIframe = null;
  380. return;
  381. }
  382.  
  383. try {
  384. const container = document.createElement('div');
  385. container.className = 'google-maps-iframe';
  386.  
  387. const closeBtn = document.createElement('button');
  388. closeBtn.className = 'close-button';
  389. closeBtn.textContent = '×';
  390. closeBtn.onclick = () => {
  391. container.remove();
  392. googleMapsIframe = null;
  393. };
  394.  
  395. const iframe = document.createElement('iframe');
  396. iframe.width = '100%';
  397. iframe.height = '100%';
  398. iframe.style.border = 'none';
  399. iframe.src = "https://www.google.com/maps?q=" + location.lat + "," + location.lng + "&z=18&output=embed";
  400.  
  401. container.appendChild(closeBtn);
  402. container.appendChild(iframe);
  403. document.body.appendChild(container);
  404. googleMapsIframe = container;
  405. updateMapPosition();
  406. } catch (error) {
  407. console.error('Error creating iframe:', error);
  408. }
  409. }
  410.  
  411. function updateMapPosition() {
  412. if (!googleMapsIframe) return;
  413.  
  414. const pos = settings.mapPosition.split('-');
  415. googleMapsIframe.style.top = pos[0] === 'top' ? '10px' : 'auto';
  416. googleMapsIframe.style.bottom = pos[0] === 'bottom' ? '10px' : 'auto';
  417. googleMapsIframe.style.left = pos[1] === 'left' ? '10px' : 'auto';
  418. googleMapsIframe.style.right = pos[1] === 'right' ? '10px' : 'auto';
  419. googleMapsIframe.style.width = settings.mapSize.width + 'px';
  420. googleMapsIframe.style.height = settings.mapSize.height + 'px';
  421. }
  422.  
  423. document.addEventListener("keydown", function(event) {
  424. event.stopPropagation();
  425.  
  426. const location = globalCoordinates;
  427. if (!location) return;
  428.  
  429. if (event.key === settings.keybinds.toggleMap) {
  430. toggleGoogleMapsIframe(location);
  431. } else if (event.key === settings.keybinds.newTab) {
  432. mapsFromCoords();
  433. } else if (event.key === settings.keybinds.settings) {
  434. toggleSettingsModal();
  435. } else if (event.key === settings.keybinds.detailedLocation) {
  436. const { lat, lng } = location;
  437. if (!lat || !lng) {
  438. alert('Coordinates not yet available!');
  439. } else {
  440. fetchLocationDetails(lat, lng);
  441. }
  442. } else if (event.key === settings.keybinds.pinpoint) {
  443. placeMarker(true);
  444. } else if (event.key === settings.keybinds.nearbypinpoint) {
  445. placeMarker(false);
  446. }
  447. }, true);
  448.  
  449. loadSettings();

QingJ © 2025

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