Geoguessr Location Resolver (Works in all modes)

Features: Automatically score 5000 Points | Score randomly between 4500 and 5000 points | Open in Google Maps

当前为 2024-01-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Geoguessr Location Resolver (Works in all modes)
  3. // @namespace http://tampermonkey.net/
  4. // @version 12
  5. // @description Features: Automatically score 5000 Points | Score randomly between 4500 and 5000 points | Open in Google Maps
  6. // @author 0x978
  7. // @match https://www.geoguessr.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
  9. // @grant GM_webRequest
  10. // ==/UserScript==
  11.  
  12.  
  13. // =================================================================================================================
  14. // 'An idiot admires complexity, a genius admires simplicity'
  15. // Learn how I made this script: https://github.com/0x978/GeoGuessr_Resolver/blob/master/howIMadeTheScript.md
  16. // Contribute things you think will be cool once you learn: https://github.com/0x978/GeoGuessr_Resolver/pulls
  17. // ================================================================================================================
  18.  
  19. let globalCoordinates = { // keep this stored globally, and we'll keep updating it for each API call.
  20. lat: 0,
  21. lng: 0
  22. }
  23.  
  24. let globalPanoID = undefined
  25.  
  26. // Below, I intercept the API call to Google Street view and view the result before it reaches the client.
  27. // Then I simply do some regex over the response string to find the coordinates, which Google gave to us in the response data
  28. // I then update a global variable above, with the correct coordinates, each time we receive a response from Google.
  29. // This needs further testing - but initial tests look promising
  30.  
  31. var originalOpen = XMLHttpRequest.prototype.open;
  32. XMLHttpRequest.prototype.open = function(method, url) {
  33. if (url.startsWith('https://maps.googleapis.com')) {
  34.  
  35. this.addEventListener('load', function () {
  36. let interceptedResult = this.responseText
  37. const pattern = /-?\d+\.\d+,-?\d+\.\d+/g;
  38. let match = interceptedResult.match(pattern)[0];
  39. let split = match.split(",")
  40.  
  41. let lat = Number.parseFloat(split[0])
  42. let lng = Number.parseFloat(split[1])
  43.  
  44. // Geoguessr now calls the Google Maps API multiple times each round, with subsequent requests overwriting
  45. // the saved coordinates. We can just take the first instance of coordinates each round.
  46. // We can use the PanoID to see if the round changed.
  47. let localPanoID = getPanoID()
  48. if(localPanoID !== globalPanoID){
  49. globalCoordinates.lat = lat
  50. globalCoordinates.lng = lng
  51. globalPanoID = localPanoID
  52. }
  53. });
  54. }
  55. // Call the original open function
  56. return originalOpen.apply(this, arguments);
  57. };
  58.  
  59.  
  60. // ====================================Placing Marker====================================
  61.  
  62. function placeMarker(safeMode){
  63. let {lat,lng} = globalCoordinates
  64.  
  65. if (safeMode) { // applying random values to received coordinates.
  66. const sway = [Math.random() > 0.5,Math.random() > 0.5]
  67. const multiplier = Math.random() * 4
  68. const horizontalAmount = Math.random() * multiplier
  69. const verticalAmount = Math.random() * multiplier
  70. sway[0] ? lat += verticalAmount : lat -= verticalAmount
  71. sway[1] ? lng += horizontalAmount : lat -= horizontalAmount
  72. }
  73.  
  74. // Okay well played Geoguessr u got me there for a minute, but below should work.
  75. // Below is the only intentionally complicated part of the code - it won't be simplified or explained for good reason.
  76. let element = document.getElementsByClassName("guess-map_canvas__JAHHT")[0]
  77. if(!element){
  78. placeMarkerStreaks()
  79. return
  80. }
  81. const keys = Object.keys(element)
  82. const key = keys.find(key => key.startsWith("__reactFiber$"))
  83. const props = element[key]
  84. const x = props.return.return.memoizedProps.map.__e3_.click
  85. const y = Object.keys(x)[0]
  86.  
  87. const z = {
  88. latLng:{
  89. lat: () => lat,
  90. lng: () => lng,
  91. }
  92. }
  93. x[y].em(z)
  94. }
  95.  
  96. // similar idea as above, but with special considerations for the streaks modes.
  97. // again - will not be explained.
  98. function placeMarkerStreaks(){
  99. let {lat,lng} = globalCoordinates
  100. let element = document.getElementsByClassName("region-map_mapCanvas__R95Ki")[0]
  101. if(!element){
  102. return
  103. }
  104. const keys = Object.keys(element)
  105. const key = keys.find(key => key.startsWith("__reactFiber$"))
  106. const props = element[key]
  107. const x = props.return.return.memoizedProps.map.__e3_.click
  108. const y = Object.keys(x)
  109. const w = "(e.latLng.lat(),e.latLng.lng())}"
  110. const z = y.find(a => x[a].xe.toString().slice(5) === w)
  111. const v = {
  112. latLng:{
  113. lat: () => lat,
  114. lng: () => lng,
  115. }
  116. }
  117. x[z].em(v)
  118. }
  119.  
  120. // ====================================Open In Google Maps====================================
  121.  
  122. function mapsFromCoords() { // opens new Google Maps location using coords.
  123.  
  124. const {lat,lng} = globalCoordinates
  125. if (!lat || !lng) {
  126. return;
  127. }
  128.  
  129. // Reject any attempt to call an overridden window.open, or fail .
  130. if(nativeOpen && nativeOpen.toString().indexOf('native code') === 19){
  131. nativeOpen(`https://maps.google.com/?output=embed&q=${lat},${lng}&ll=${lat},${lng}&z=5`);
  132. }
  133. }
  134.  
  135. // ====================================Utility stuff====================================
  136.  
  137. // Gets the current panorama ID
  138. // There is multiple ways to get this, in case this one is patched
  139. function getPanoID(){
  140. let panoElement = document.querySelectorAll('[data-qa="panorama"]')[0]
  141. const keys = Object.keys(panoElement)
  142. const reactKey = keys.find(key => key.startsWith("__reactFiber$"))
  143. const reactProps = panoElement[reactKey]
  144. const panoID = reactProps.return.memoizedProps.panoId
  145.  
  146. return panoID
  147. }
  148.  
  149. // ====================================Controls,setup, etc.====================================
  150.  
  151.  
  152. let onKeyDown = (e) => {
  153. if (e.keyCode === 49) {
  154. e.stopImmediatePropagation(); // tries to prevent the key from being hijacked by geoguessr
  155. placeMarker(true)
  156. }
  157. if (e.keyCode === 50) {
  158. e.stopImmediatePropagation();
  159. placeMarker(false)
  160. }
  161. if (e.keyCode === 51) {
  162. e.stopImmediatePropagation();
  163. mapsFromCoords(false)
  164. }
  165. }
  166.  
  167. document.addEventListener("keydown", onKeyDown);