Geoguessr Unity Script with Duels

Play Geoguessr with Yandex, Baidu, Kakao streetviews, Aris coverage (with good movement), and avoid the gaps in official coverage. Credit to kommu, MrAmericanMike (Yandex) and xsanda (check location after movement) scripts. Thanks to Alok, Mapper for advise for map making.

目前为 2021-12-15 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Geoguessr Unity Script with Duels
  3. // @description Play Geoguessr with Yandex, Baidu, Kakao streetviews, Aris coverage (with good movement), and avoid the gaps in official coverage. Credit to kommu, MrAmericanMike (Yandex) and xsanda (check location after movement) scripts. Thanks to Alok, Mapper for advise for map making.
  4. // @version 3.2.0b
  5. // @include https://www.geoguessr.com/*
  6. // @run-at document-start
  7. // @license MIT
  8. // @namespace https://greasyfork.org/users/838374
  9. // ==/UserScript==
  10.  
  11. // API Keys
  12.  
  13. var YANDEX_API_KEY = "b704b5a9-3d67-4d19-b702-ec7807cecfc6";
  14. var BAIDU_API_KEY = "8dQ9hZPGEQnqg9r0O1C8Ate2N6P8Zk92";
  15. var KAKAO_API_KEY = "cbacbe41e3a223d794f321de4f3e247b";
  16. const MAPS_API_URL = "https://maps.googleapis.com/maps/api/js"; // removed "?" from the link
  17.  
  18. myLog("Geoguessr Unity Script");
  19.  
  20. // Store each player instance
  21.  
  22. let YandexPlayer, BaiduPlayer, KakaoPlayer;
  23. let YANDEX_INJECTED = false;
  24. let BAIDU_INJECTED = false;
  25. let KAKAO_INJECTED = false;
  26.  
  27. // Game mode detection
  28.  
  29. let isBattleRoyale = false;
  30. let isDuel = false;
  31.  
  32. // Player detection and coordinate conversion
  33.  
  34. let nextPlayer = "Google";
  35. let global_lat = 0;
  36. let global_lng = 0;
  37. let global_panoID = null;
  38.  
  39. let krCoordinates = [38.75292321084364, 124.2804539232574, 33.18509676203202, 129.597381999198]
  40. let global_radi = 100
  41.  
  42. // Callback variables
  43.  
  44. let eventListenerAttached = false;
  45. let povListenerAttached = false;
  46. let playerLoaded = false;
  47. let teleportLoaded = false;
  48. let syncLoaded = false;
  49.  
  50. // Minimize Yandex API use
  51.  
  52. let yandex_map = false;
  53.  
  54. // Handle Yandex compass
  55.  
  56. let COMPASS = null;
  57.  
  58. // Handle undo
  59.  
  60. let locHistory = [];
  61. let defaultPanoIdChange = true;
  62.  
  63. // Round check
  64.  
  65. let ROUND = 0;
  66. let CURRENT_ROUND_DATA = null;
  67.  
  68.  
  69. // let NEW_ROUND_LOADED = false;
  70.  
  71. /**
  72. * Helper Functions
  73. */
  74.  
  75. // Pretty print
  76.  
  77. function myLog(...args) {
  78. console.log(...args);
  79. }
  80. function myHighlight(...args) {
  81. console.log(`%c${[...args]}`, "color: dodgerblue; font-size: 24px;");
  82. }
  83.  
  84. // Hex to number conversion for Baidu coordinate conversion
  85.  
  86. function hex2a(hexx) {
  87. var hex = hexx.toString();
  88. var str = '';
  89. for (var i = 0; i < hex.length; i += 2)
  90. str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
  91. return str;
  92. }
  93.  
  94. // Coordinate computation given heading, distance and current coordinates for teleport
  95.  
  96. function FindPointAtDistanceFrom(lat, lng, initialBearingRadians, distanceKilometres) {
  97. const radiusEarthKilometres = 6371.01;
  98. var distRatio = distanceKilometres / radiusEarthKilometres;
  99. var distRatioSine = Math.sin(distRatio);
  100. var distRatioCosine = Math.cos(distRatio);
  101.  
  102. var startLatRad = DegreesToRadians(lat);
  103. var startLonRad = DegreesToRadians(lng);
  104.  
  105. var startLatCos = Math.cos(startLatRad);
  106. var startLatSin = Math.sin(startLatRad);
  107.  
  108. var endLatRads = Math.asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.cos(initialBearingRadians)));
  109.  
  110. var endLonRads = startLonRad
  111. + Math.atan2(
  112. Math.sin(initialBearingRadians) * distRatioSine * startLatCos,
  113. distRatioCosine - startLatSin * Math.sin(endLatRads));
  114.  
  115. return { lat: RadiansToDegrees(endLatRads), lng: RadiansToDegrees(endLonRads) };
  116. }
  117.  
  118. function DegreesToRadians(degrees) {
  119. const degToRadFactor = Math.PI / 180;
  120. return degrees * degToRadFactor;
  121. }
  122.  
  123. function RadiansToDegrees(radians) {
  124. const radToDegFactor = 180 / Math.PI;
  125. return radians * radToDegFactor;
  126. }
  127.  
  128. // Script injection
  129.  
  130. function runAsClient(f) {
  131. var s = document.createElement("script");
  132. s.type = "text/javascript";
  133. s.text = "(async () => { try { await (" + f.toString() + ")(); } catch (e) { console.error(e); }})();";
  134. document.body.appendChild(s);
  135. }
  136.  
  137. window.runAsClient = runAsClient;
  138.  
  139. /**
  140. * Resolves succesfully after detecting that Google Maps API was loaded in a page
  141. *
  142. * @returns Promise
  143. */
  144.  
  145. function gmp() {
  146. return new Promise((resolve, reject) => {
  147. let scriptObserver = new MutationObserver((mutations, observer) => {
  148. for (let mutation of mutations) {
  149. for (let node of mutation.addedNodes) {
  150. if (node.tagName === "SCRIPT" && node.src.startsWith(MAPS_API_URL)) {
  151. scriptObserver.disconnect();
  152. scriptObserver = undefined;
  153. myLog("Detected Google Maps API");
  154. node.onload = () => resolve();
  155. }
  156. }
  157. }
  158. });
  159.  
  160. let bodyDone = false;
  161. let headDone = false;
  162.  
  163. let injectorObserver = new MutationObserver((mutations, observer) => {
  164. if (!bodyDone && document.body) {
  165. bodyDone = true;
  166. myLog("Body Observer Injected");
  167. scriptObserver && scriptObserver.observe(document.body, {
  168. childList: true
  169. });
  170. }
  171. if (!headDone && document.head) {
  172. headDone = true;
  173. myLog("Head Observer Injected");
  174. scriptObserver && scriptObserver.observe(document.head, {
  175. childList: true
  176. });
  177. }
  178. if (headDone && bodyDone) {
  179. myLog("Body and Head Observers Injected");
  180. observer.disconnect();
  181. }
  182. });
  183.  
  184. injectorObserver.observe(document.documentElement, {
  185. childList: true,
  186. subtree: true
  187. });
  188. });
  189. }
  190.  
  191. /**
  192. * Creates teleportation and Kakao switch button
  193. *
  194. * @returns Promise
  195. */
  196.  
  197. function ArisKakao() {
  198. runAsClient(() => {
  199.  
  200. // let radi = 100;
  201. const google = window.google;
  202. // console.log(google);
  203. let curPosition, mapPlayer;
  204. let kakao_enabled = true;
  205.  
  206. const isGamePage = () => location.pathname.startsWith("/challenge/") || location.pathname.startsWith("/results/") || location.pathname.startsWith("/game/")|| location.pathname.startsWith("/battle-royale/") || location.pathname.startsWith("/duels/") || location.pathname.startsWith("/team-duels/");
  207.  
  208. const getPosition = sv => (
  209. {
  210. lat: sv.position.lat(),
  211. lng: sv.position.lng(),
  212. heading: sv.pov.heading,
  213. });
  214.  
  215. // Handle the street view being navigated
  216. const onMove = (sv) => {
  217. try {
  218. if (!isGamePage()) return;
  219. const position = getPosition(sv);
  220. curPosition = position;
  221. if (googleKakaoButton.useGoogle)
  222. {
  223. googleKakaoButton.lng = position.lng;
  224. googleKakaoButton.lat = position.lat;
  225. googleKakaoButton.heading = position.heading;
  226. }
  227. googleKakaoButton.useGoogle = true;
  228. teleportButton.google = true;
  229. // googleKakaoButton.heading = position.lat;
  230. // console.log(position.heading);
  231. // console.log(googleKakaoButton.lng);
  232. }
  233. catch (e) {
  234. console.error("GeoGuessr Path Logger Error:", e);
  235. }
  236. };
  237.  
  238. // Helper Functions
  239.  
  240. function FindPointAtDistanceFrom(startPoint, initialBearingRadians, distanceKilometres) {
  241. const radiusEarthKilometres = 6371.01;
  242. var distRatio = distanceKilometres / radiusEarthKilometres;
  243. var distRatioSine = Math.sin(distRatio);
  244. var distRatioCosine = Math.cos(distRatio);
  245.  
  246. var startLatRad = DegreesToRadians(startPoint.lat);
  247. var startLonRad = DegreesToRadians(startPoint.lng);
  248.  
  249. var startLatCos = Math.cos(startLatRad);
  250. var startLatSin = Math.sin(startLatRad);
  251.  
  252. var endLatRads = Math.asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.cos(initialBearingRadians)));
  253.  
  254. var endLonRads = startLonRad
  255. + Math.atan2(
  256. Math.sin(initialBearingRadians) * distRatioSine * startLatCos,
  257. distRatioCosine - startLatSin * Math.sin(endLatRads));
  258.  
  259. return { lat: RadiansToDegrees(endLatRads), lng: RadiansToDegrees(endLonRads) };
  260. }
  261.  
  262. function DegreesToRadians(degrees) {
  263. const degToRadFactor = Math.PI / 180;
  264. return degrees * degToRadFactor;
  265. }
  266.  
  267. function RadiansToDegrees(radians) {
  268. const radToDegFactor = 180 / Math.PI;
  269. return radians * radToDegFactor;
  270. }
  271.  
  272. function svCheck(data, status) {
  273. if (status === 'OK') {
  274. // console.log("OK for " + data.location.latLng + " at ID " + data.location.pano);
  275. let l = data.location.latLng.toString().split(',');
  276. let lat = l[0].replaceAll('(', '')
  277. let lng = l[1].replaceAll(')', '')
  278. if (lat == curPosition.lat && lng == curPosition.lng)
  279. {
  280. console.log("Trying more distance");
  281. teleportButton.distance += 100;
  282. teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
  283. }
  284. else
  285. {
  286. console.log("Teleport Success");
  287. mapPlayer.setPosition(data.location.latLng);
  288. mapPlayer.setPov({
  289. heading: googleKakaoButton.heading,
  290. pitch: 0,
  291. })
  292. // console.log(teleportButton.distance);
  293. if (teleportButton.distance > 150)
  294. {
  295. teleportButton.distance = 100;
  296. teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
  297. }
  298. }
  299. }
  300. else {
  301. console.log("STATUS NOT OK");
  302. teleportButton.distance += 100;
  303. teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
  304. }
  305. }
  306.  
  307. // When a StreetViewPanorama is constructed, add a listener for moving
  308.  
  309. const oldSV = google.maps.StreetViewPanorama;
  310. const svService = new google.maps.StreetViewService();
  311.  
  312. google.maps.StreetViewPanorama = Object.assign(function (...args) {
  313. const res = oldSV.apply(this, args);
  314. this.addListener('position_changed', () => onMove(this));
  315. mapPlayer = this;
  316. return res;
  317. }, {
  318. prototype: Object.create(oldSV.prototype)
  319. });
  320.  
  321. var showButtons = document.createElement("Button");
  322. showButtons.id = "Show Buttons"
  323. showButtons.innerHTML = "Script Buttons";
  324. showButtons.style =
  325. "top:6em;right:0.5em;width:6em;height:4.5em;position:absolute;z-index:99999;background-color: #4CAF50;border: none;color: white;padding: none;text-align: center;vertical-align: text-top;text-decoration: none;display: inline-block;font-size: 16px;";
  326. document.body.appendChild(showButtons);
  327. showButtons.addEventListener("click", () => {
  328. if (hide) {
  329. teleportButton.style.visibility = "";
  330. plusButton.style.visibility = "";
  331. minusButton.style.visibility = "";
  332. resetButton.style.visibility = "";
  333. googleKakaoButton.style.visibility = "";
  334. hide = false;
  335. }
  336. else {
  337. teleportButton.style.visibility = "hidden";
  338. plusButton.style.visibility = "hidden";
  339. minusButton.style.visibility = "hidden";
  340. resetButton.style.visibility = "hidden"
  341. googleKakaoButton.style.visibility = "hidden";
  342. hide = true;
  343. }
  344. });
  345.  
  346. var teleportButton = document.createElement("Button");
  347. teleportButton.id = "Main Button";
  348. teleportButton.distance = 100;
  349. teleportButton.google = true;
  350. teleportButton.innerHTML = "Teleport 100m";
  351. teleportButton.style =
  352. "visibility:hidden;top:6em;right:9.5em;width:10em;height:2em;position:absolute;z-index:99999;background-color: #4CAF50;border: none;color: white;padding: none;text-align: center;vertical-align: text-top;text-decoration: none;display: inline-block;font-size: 16px;";
  353. document.body.appendChild(teleportButton);
  354. teleportButton.addEventListener("click", () => {
  355. // console.log("Google Teleport");
  356. if (teleportButton.google && mapPlayer != null)
  357. {
  358. let heading = mapPlayer.getPov().heading;
  359. let place = FindPointAtDistanceFrom(curPosition, DegreesToRadians(heading), teleportButton.distance * 0.001)
  360. svService.getPanorama({ location: place, radius: 1000 }, svCheck);
  361. }
  362. });
  363.  
  364. var plusButton = document.createElement("Button");
  365. plusButton.id = "plus"
  366. plusButton.innerHTML = "+";
  367. plusButton.style =
  368. "visibility:hidden;top:6em;right:7em;width:2em;height:2em;position:absolute;z-index:99999;background-color: #4CAF50;border: none;color: white;padding: none;text-align: center;vertical-align: text-top;text-decoration: none;display: inline-block;font-size: 16px;";
  369. document.body.appendChild(plusButton);
  370. plusButton.addEventListener("click", () => {
  371. if (teleportButton.distance > 21 && teleportButton.distance < 149) {
  372. teleportButton.distance = teleportButton.distance + 25;
  373. }
  374. teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
  375. });
  376.  
  377. var minusButton = document.createElement("Button");
  378. minusButton.id = "minus"
  379. minusButton.innerHTML = "-";
  380. minusButton.style =
  381. "visibility:hidden;top:6em;right:20em;width:2em;height:2em;position:absolute;z-index:99999;background-color: #4CAF50;border: none;color: white;padding: none;text-align: center;vertical-align: text-top;text-decoration: none;display: inline-block;font-size: 16px;";
  382. document.body.appendChild(minusButton);
  383. minusButton.addEventListener("click", () => {
  384. if (teleportButton.distance > 26) {
  385. teleportButton.distance = teleportButton.distance - 25;
  386. }
  387. teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
  388. });
  389.  
  390. var resetButton = document.createElement("Button");
  391. resetButton.id = "reset"
  392. resetButton.innerHTML = "Reset";
  393. resetButton.style =
  394. "visibility:hidden;top:8.5em;right:17.5em;width:4.5em;height:2em;position:absolute;z-index:99999;background-color: #4CAF50;border: none;color: white;padding: none;text-align: center;vertical-align: text-top;text-decoration: none;display: inline-block;font-size: 16px;";
  395. document.body.appendChild(resetButton);
  396. resetButton.addEventListener("click", () => {
  397. teleportButton.distance = 100;
  398. teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
  399. });
  400.  
  401. var googleKakaoButton = document.createElement("Button");
  402. googleKakaoButton.id = "switch";
  403. googleKakaoButton.init = true;
  404. googleKakaoButton.nextPlayer = "Google";
  405. googleKakaoButton.useGoogle = false;
  406. googleKakaoButton.lng = 0
  407. googleKakaoButton.lat = 0
  408. googleKakaoButton.heading = 0
  409. googleKakaoButton.innerHTML = "Switch coverage";
  410. googleKakaoButton.style =
  411. "visibility:hidden;top:8.5em;right:7em;width:10em;height:2em;position:absolute;z-index:99999;background-color: #4CAF50;border: none;color: white;padding: none;text-align: center;vertical-align: text-top;text-decoration: none;display: inline-block;font-size: 16px;";
  412. document.body.appendChild(googleKakaoButton);
  413. googleKakaoButton.addEventListener("click", () => {
  414. let GOOGLE_MAPS_CANVAS1 = document.querySelector(".game-layout__panorama-canvas");
  415. let GOOGLE_MAPS_CANVAS2 = document.querySelector(".br-game-layout__panorama-canvas");
  416. let GOOGLE_MAPS_CANVAS3 = document.querySelector(".inactive");
  417. let duel = false;
  418.  
  419. let GOOGLE_MAPS_CANVAS = null;
  420. if (GOOGLE_MAPS_CANVAS1 !== null)
  421. {
  422. GOOGLE_MAPS_CANVAS = GOOGLE_MAPS_CANVAS1;
  423. }
  424. else if (GOOGLE_MAPS_CANVAS2 !== null)
  425. {
  426. GOOGLE_MAPS_CANVAS = GOOGLE_MAPS_CANVAS2;
  427. }
  428.  
  429.  
  430. if (GOOGLE_MAPS_CANVAS3 !== null)
  431. {
  432. duel = true;
  433. }
  434.  
  435. let KAKAO_MAPS_CANVAS = document.getElementById("roadview");
  436. let YANDEX_MAPS_CANVAS = document.querySelector(".ymaps-2-1-79-panorama-screen");
  437. if (googleKakaoButton.useGoogle == false) {
  438. if (duel)
  439. {
  440. document.getElementById("default_player").className = "game-panorama_panoramaCanvas__patp9";
  441. if (googleKakaoButton.nextPlayer == "Kakao")
  442. {
  443. document.getElementById("roadview").className = "inactive";
  444. }
  445. }
  446. else
  447. {
  448. GOOGLE_MAPS_CANVAS.style.visibility = "";
  449. if (googleKakaoButton.nextPlayer == "Kakao")
  450. {
  451. KAKAO_MAPS_CANVAS.style.visibility = "hidden";
  452. }
  453. else if (googleKakaoButton.nextPlayer == "Yandex")
  454. {
  455. YANDEX_MAPS_CANVAS.style.visibility = "hidden";
  456. }
  457. }
  458. svService.getPanorama({ location: { lat: googleKakaoButton.lat, lng: googleKakaoButton.lng }, radius: 1000 }, svCheck);
  459. googleKakaoButton.useGoogle = true;
  460. teleportButton.google = true;
  461. console.log("use Google");
  462. }
  463. else {
  464. if (duel)
  465. {
  466. document.getElementById("default_player").className = "inactive";
  467. if (googleKakaoButton.nextPlayer == "Kakao")
  468. {
  469. document.getElementById("roadview").className = "game-panorama_panorama__3b2wI";
  470. }
  471. }
  472. else
  473. {
  474. GOOGLE_MAPS_CANVAS.style.visibility = "hidden";
  475. if (googleKakaoButton.nextPlayer == "Kakao")
  476. {
  477. KAKAO_MAPS_CANVAS.style.visibility = "";
  478. }
  479. else if (googleKakaoButton.nextPlayer == "Yandex")
  480. {
  481. YANDEX_MAPS_CANVAS.style.visibility = "";
  482. }
  483. }
  484. googleKakaoButton.useGoogle = false;
  485. teleportButton.google = false;
  486. console.log("use Others");
  487. }
  488. });
  489.  
  490. // Battle Royale UI optimization
  491.  
  492. let hide = true;
  493.  
  494. console.log("Buttons Loaded");
  495. });
  496. }
  497.  
  498. /**
  499. * Handle Keyboard inputs
  500. */
  501.  
  502. function kBoard()
  503. {
  504. document.addEventListener('keydown', logKey);
  505. }
  506.  
  507. function logKey(e) {
  508. // myLog(e.code);
  509. if (e.code == "Space")
  510. {
  511. setHidden(true);
  512. }
  513. if (e.code == "Digit1")
  514. {
  515. setHidden(false);
  516. document.getElementById("Show Buttons").click();
  517. }
  518. else if (e.code == "Digit3")
  519. {
  520. document.getElementById("Main Button").click();
  521. }
  522. else if (e.code == "Digit2")
  523. {
  524. document.getElementById("minus").click();
  525. }
  526. else if (e.code == "Digit4")
  527. {
  528. document.getElementById("plus").click();
  529.  
  530. }
  531. }
  532.  
  533.  
  534. /**
  535. * Hide or reveal the buttons, and disable buttons if such feature is not available
  536. */
  537.  
  538. function setHidden(cond)
  539. {
  540. if (cond)
  541. {
  542. if (document.getElementById("Show Buttons") != null)
  543. {
  544. document.getElementById("Show Buttons").style.visibility = "hidden";
  545. if (document.getElementById("Main Button") != null)
  546. {
  547. document.getElementById("plus").style.visibility = "hidden";
  548. document.getElementById("minus").style.visibility = "hidden";
  549. document.getElementById("reset").style.visibility = "hidden";
  550. document.getElementById("Main Button").style.visibility = "hidden";
  551. document.getElementById("switch").style.visibility = "hidden";
  552. }
  553. }
  554. }
  555. else
  556. {
  557. if (document.getElementById("Show Buttons") != null)
  558. {
  559. document.getElementById("Show Buttons").style.visibility = "";
  560. }
  561. }
  562. }
  563.  
  564. function setDisable(cond)
  565. {
  566. if (cond !== "Google")
  567. {
  568. if (document.getElementById("Main Button") != null)
  569. {
  570. if (cond === "Baidu")
  571. {
  572. document.getElementById("switch").disabled = true;
  573. document.getElementById("switch").style.backgroundColor = "red";
  574. }
  575. else
  576. {
  577. document.getElementById("switch").disabled = false;
  578. document.getElementById("switch").style.backgroundColor = "#4CAF50";
  579. }
  580. }
  581. }
  582. else
  583. {
  584. if (document.getElementById("Main Button") != null)
  585. {
  586. document.getElementById("switch").disabled = true;
  587. document.getElementById("switch").style.backgroundColor = "red";
  588. }
  589. }
  590. }
  591.  
  592. /**
  593. * This observer stays alive while the script is running
  594. */
  595.  
  596. function launchObserver() {
  597. ArisKakao();
  598. BYKTeleport();
  599. SyncListener();
  600. kBoard();
  601. myHighlight("Main Observer");
  602. const OBSERVER = new MutationObserver((mutations, observer) => {
  603. detectGamePage();
  604. });
  605. OBSERVER.observe(document.head, { attributes: true, childList: true, subtree: true });
  606. }
  607.  
  608. /**
  609. * Once the Google Maps API was loaded we can do more stuff
  610. */
  611.  
  612. gmp().then(() => {
  613. launchObserver();
  614. });
  615.  
  616.  
  617. /**
  618. * Check whether the current page is a game, if so which game mode
  619. */
  620.  
  621. function detectGamePage() {
  622. let toLoad = !playerLoaded && !YandexPlayer && !BaiduPlayer && !KakaoPlayer && !YANDEX_INJECTED && !BAIDU_INJECTED && !KAKAO_INJECTED
  623. const PATHNAME = window.location.pathname;
  624. //myLog(PATHNAME);
  625. if (PATHNAME.startsWith("/game/") || PATHNAME.startsWith("/challenge/")) {
  626. // myLog("Game page");
  627. isBattleRoyale = false;
  628. isDuel = false;
  629. if (toLoad) {
  630. loadPlayers();
  631. }
  632. waitLoad();
  633. }
  634. else if (PATHNAME.startsWith("/battle-royale/")) {
  635. if (document.querySelector(".br-game-layout") == null) {
  636. // myLog("Battle Royale Lobby");
  637. setHidden(true);
  638. }
  639. else {
  640. // myLog("Battle Royale");
  641. isBattleRoyale = true;
  642. isDuel = false;
  643. if (toLoad) {
  644. loadPlayers();
  645. }
  646. waitLoad();
  647. }
  648. }
  649. else if (PATHNAME.startsWith("/duels/") || PATHNAME.startsWith("/team-duels/")) {
  650. if (document.querySelector(".game_layout__1TqBM") == null) {
  651. // myLog("Battle Royale Lobby");
  652. setHidden(true);
  653. }
  654. else {
  655. // myLog("Duels");
  656. isBattleRoyale = true;
  657. isDuel = true;
  658. if (toLoad) {
  659. loadPlayers();
  660. }
  661. waitLoad();
  662. }
  663. }
  664. else {
  665. //myLog("Not a Game page");
  666.  
  667. ROUND = 0;
  668. YandexPlayer = null;
  669. BaiduPlayer = null;
  670. KakaoPlayer = null;
  671.  
  672. BAIDU_INJECTED = false;
  673. YANDEX_INJECTED = false;
  674. KAKAO_INJECTED = false;
  675.  
  676. nextPlayer = "Google"
  677. global_lat = 0;
  678. global_lng = 0;
  679. global_panoID = null;
  680.  
  681. COMPASS = null;
  682. eventListenerAttached = false;
  683. povListenerAttached = false;
  684. playerLoaded = false;
  685. locHistory = [];
  686. setHidden(true);
  687. yandex_map = false;
  688. CURRENT_ROUND_DATA = null;
  689. }
  690. }
  691.  
  692. /**
  693. * Wait for various players to load
  694. */
  695.  
  696. function waitLoad() {
  697. if (!YandexPlayer || !BaiduPlayer || !KakaoPlayer || !YANDEX_INJECTED || !BAIDU_INJECTED || !KAKAO_INJECTED) {
  698. let teleportButton = document.getElementById("Main Button");
  699. let plusButton = document.getElementById("plus");
  700. let minusButton = document.getElementById("minus");
  701. let resetButton = document.getElementById("reset");
  702. let googleKakaoButton = document.getElementById("switch");
  703. let showButtons = document.getElementById("Show Buttons");
  704. if (document.querySelector(".br-game-layout__panorama-canvas") != null)
  705. {
  706. teleportButton.style.top = "2px";
  707. plusButton.style.top = "2px";
  708. minusButton.style.top = "2px";
  709. resetButton.style.top = "calc(2.5em + 2px)";
  710. googleKakaoButton.style.top = "calc(2.5em + 2px)";
  711. showButtons.style.top = "2px";
  712.  
  713. teleportButton.style.right = "calc(9.5em + 300px)";
  714. plusButton.style.right = "calc(7em + 300px)";
  715. minusButton.style.right = "calc(20em + 300px)";
  716. resetButton.style.right = "calc(17.5em + 300px)";
  717. googleKakaoButton.style.right = "calc(7em + 300px)";
  718. showButtons.style.right = "300px";
  719. }
  720.  
  721.  
  722. if (document.querySelector(".game-panorama_panorama__3b2wI") != null)
  723. {
  724. teleportButton.style.top = "8em";
  725. plusButton.style.top = "8em";
  726. minusButton.style.top = "8em";
  727. resetButton.style.top = "10.5em";
  728. googleKakaoButton.style.top = "10.5em";
  729. showButtons.style.top = "8em";
  730.  
  731. }
  732.  
  733. setTimeout(waitLoad, 250);
  734. } else {
  735. checkRound();
  736. }
  737. }
  738.  
  739. /**
  740. * Checks for round changes
  741. */
  742.  
  743. function checkRound() {
  744. // myLog("Check Round");
  745. if (!isBattleRoyale) {
  746. let currentRound = getRoundFromPage();
  747. if (ROUND != currentRound) {
  748. myHighlight("New round");
  749. ROUND = currentRound;
  750. // NEW_ROUND_LOADED = true;
  751. COMPASS = null;
  752. locHistory = [];
  753. getMapData();
  754. nextButtonCallback();
  755. }
  756. }
  757. else {
  758. getMapData();
  759. }
  760. }
  761.  
  762. /**
  763. * Add listeners if buttons have been created
  764. */
  765.  
  766. function nextButtonCallback()
  767. {
  768. let nextButton = document.querySelector("button[data-qa='close-round-result']");
  769. if (nextButton != null)
  770. {
  771. nextButton.addEventListener("click", (e) => {
  772. if (document.getElementById("Show Buttons") != null)
  773. {
  774. myLog("try to hide show buttons")
  775. document.getElementById("Show Buttons").style.visibility = "";
  776. }
  777. })
  778. }
  779. else
  780. {
  781. setTimeout(nextButtonCallback, 500);
  782. }
  783. }
  784.  
  785. function guessButtonCallback()
  786. {
  787. let guessButton = document.querySelector("button[data-qa='perform-guess']");
  788. if (guessButton != null)
  789. {
  790.  
  791. guessButton.addEventListener("click", (e) => {
  792. if (document.getElementById("Show Buttons") != null)
  793. {
  794. myLog("try to hide show buttons")
  795. document.getElementById("Show Buttons").style.visibility = "hidden";
  796. setHidden(true);
  797. }
  798. })
  799. }
  800. else
  801. {
  802. setTimeout(guessButtonCallback, 500);
  803. }
  804. }
  805.  
  806. /**
  807. * Load different streetview players
  808. */
  809.  
  810. function injectYandex()
  811. {
  812. injectYandexScript().then(() => {
  813. myLog("Ready to inject Yandex player");
  814. injectYandexPlayer();
  815. }).catch((error) => {
  816. myLog(error);
  817. });
  818. }
  819.  
  820. function loadPlayers() {
  821. playerLoaded = true;
  822. if (!isBattleRoyale)
  823. {
  824. getSeed().then((data) => {
  825. // myLog(data);
  826. if (data.mapName.includes("A United World") || data.mapName.includes("byk"))
  827. {
  828. myLog("A United World");
  829. injectYandex();
  830. }
  831. else if (data.mapName.includes("Yandex"))
  832. {
  833. yandex_map = true;
  834. myLog("Is Yandex Map");
  835. injectYandex();
  836. }
  837. else{
  838. // YANDEX_API_KEY = "";
  839. YANDEX_INJECTED = true;
  840. YandexPlayer = "YD";
  841. myLog("Not a Yandex map");
  842. }
  843. setHidden(false);
  844.  
  845. }).catch((error) => {
  846. myLog(error);
  847. });
  848. }
  849. else
  850. {
  851. injectYandex();
  852. }
  853.  
  854. initializeCanvas();
  855.  
  856.  
  857.  
  858.  
  859. }
  860.  
  861. /**
  862. * Handles Return to start and undo
  863. */
  864.  
  865. function handleReturnToStart() {
  866. let rtsButton = document.querySelector("button[data-qa='return-to-start']");
  867. if (rtsButton != null) {
  868. myLog("handleReturnToStart listener attached");
  869. rtsButton.addEventListener("click", (e) => {
  870. goToLocation();
  871. const elementClicked = e.target;
  872. elementClicked.setAttribute('listener', 'true');
  873. myLog("Return to start");
  874. });
  875. guessButtonCallback();
  876. setTimeout(function () {goToLocation();}, 1000);
  877. }
  878. else
  879. {
  880. setTimeout(handleReturnToStart, 500);
  881. }
  882. }
  883.  
  884. function handleUndo() {
  885. let undoButton = document.querySelector("button[data-qa='undo-move']");
  886. if (undoButton != null)
  887. {
  888. myLog("Attach undo");
  889. undoButton.addEventListener("click", (e) => {
  890. if (locHistory.length > 0) {
  891. goToUndoMove();
  892. myLog("Undo Move");
  893. }
  894. })
  895. }
  896. else
  897. {
  898. setTimeout(handleUndo, 500);
  899. }
  900.  
  901. }
  902.  
  903. /**
  904. * Load game information
  905. */
  906.  
  907. function getMapData() {
  908. getSeed().then((data) => {
  909. // myHighlight("Seed data");
  910. // myLog(data);
  911. if (isBattleRoyale) {
  912. if (document.querySelector(".br-game-layout") == null && document.querySelector(".version3-in-game_layout__13T8U") == null) {
  913. // myLog("Battle Royale Lobby");
  914. }
  915. else
  916. {
  917. let origin = false;
  918. if (!CURRENT_ROUND_DATA) {
  919. CURRENT_ROUND_DATA = data
  920. origin = true;
  921. }
  922.  
  923. if (origin || !(data.currentRoundNumber === CURRENT_ROUND_DATA.currentRoundNumber)) {
  924. myHighlight("Battle Royale New round");
  925. // NEW_ROUND_LOADED = true;
  926. COMPASS = null;
  927. locHistory = [];
  928. setHidden(false);
  929. if (!origin) {
  930. CURRENT_ROUND_DATA = data;
  931. }
  932. locationCheck(data);
  933. // myLog(data);
  934. //setTimeout(function () {goToLocation();}, 1000);
  935. handleReturnToStart();
  936. if (isDuel)
  937. {
  938. handleUndo();
  939. hideButtons();
  940. }
  941.  
  942. }
  943. }
  944. }
  945. else {
  946. locationCheck(data);
  947. //setTimeout(function () { goToLocation();}, 1000);
  948. handleReturnToStart();
  949. handleUndo();
  950. hideButtons();
  951. }
  952. }).catch((error) => {
  953. myLog(error);
  954. });
  955. }
  956.  
  957. /**
  958. * Hide unnecessary buttons for non-Google coverages
  959. */
  960.  
  961. function hideButtons() {
  962. let CHECKPOINT = document.querySelector("button[data-qa='set-checkpoint']");
  963. let ZOOM_IN = document.querySelector("button[data-qa='pano-zoom-in']");
  964. let ZOOM_OUT = document.querySelector("button[data-qa='pano-zoom-out']");
  965.  
  966. if (CHECKPOINT != null)
  967. {
  968. if (nextPlayer === "Google") {
  969.  
  970. CHECKPOINT.style.visibility = "";
  971. ZOOM_IN.style.visibility = "";
  972. ZOOM_OUT.style.visibility = "";
  973. myLog("Buttons Unhidden");
  974.  
  975. }
  976. else {
  977.  
  978. CHECKPOINT.style.visibility = "hidden";
  979. ZOOM_IN.style.visibility = "hidden";
  980. ZOOM_OUT.style.visibility = "hidden";
  981. myLog("Buttons Hidden");
  982.  
  983. }
  984. }
  985. else
  986. {
  987. setTimeout(hideButtons, 250);
  988. }
  989. }
  990.  
  991. /**
  992. * Check which player to use for the next location
  993. */
  994.  
  995. function locationCheck(data) {
  996. // console.log(data);
  997. if (isBattleRoyale) {
  998. if (isDuel)
  999. {
  1000. global_lat = data.rounds[data.currentRoundNumber - 1].panorama.lat;
  1001. global_lng = data.rounds[data.currentRoundNumber - 1].panorama.lng;
  1002. global_panoID = data.rounds[data.currentRoundNumber - 1].panorama.panoId;
  1003. }
  1004. else
  1005. {
  1006. global_lat = data.rounds[data.currentRoundNumber - 1].lat;
  1007. global_lng = data.rounds[data.currentRoundNumber - 1].lng;
  1008. global_panoID = data.rounds[data.currentRoundNumber - 1].panoId;
  1009. }
  1010. }
  1011. else {
  1012. global_lat = data.rounds[data.round - 1].lat;
  1013. global_lng = data.rounds[data.round - 1].lng;
  1014. global_panoID = data.rounds[data.round - 1].panoId;
  1015. }
  1016. // myLog(global_lat);
  1017. // myLog(global_lng);
  1018. // myLog(krCoordinates);
  1019.  
  1020. nextPlayer = "Google";
  1021.  
  1022. if ( krCoordinates[0] > global_lat && krCoordinates[2] < global_lat && krCoordinates[1] < global_lng && krCoordinates[3] > global_lng)
  1023. {
  1024. nextPlayer = "Kakao";
  1025. }
  1026. else if (yandex_map)
  1027. {
  1028. nextPlayer = "Yandex";
  1029. }
  1030. else
  1031. {
  1032. if (global_panoID) {
  1033. let locInfo = hex2a(global_panoID);
  1034. let mapType = locInfo.substring(0, 5);
  1035. if (mapType === "BDMAP") {
  1036. nextPlayer = "Baidu";
  1037. let coord = locInfo.substring(5);
  1038. global_lat = coord.split(",")[0];
  1039. global_lng = coord.split(",")[1];
  1040. // myLog(global_lat);
  1041. }
  1042. else if (mapType === "YDMAP" ) {
  1043. nextPlayer = "Yandex";
  1044. }
  1045. }
  1046. }
  1047.  
  1048. // Disable buttons if NM, NMPZ
  1049.  
  1050. if(!isBattleRoyale)
  1051. {
  1052. if (data.forbidMoving || data.forbidRotating || data.forbidZooming)
  1053. {
  1054. setDisable("NMPZ");
  1055. }
  1056. else
  1057. {
  1058. setDisable(nextPlayer);
  1059. }
  1060. }
  1061. else
  1062. {
  1063. if (data.movementOptions.forbidMoving || data.movementOptions.forbidRotating || data.movementOptions.forbidZooming)
  1064. {
  1065. setDisable("NMPZ");
  1066. }
  1067. else
  1068. {
  1069. setDisable(nextPlayer);
  1070. }
  1071. }
  1072.  
  1073. myLog(nextPlayer);
  1074. injectCanvas();
  1075. }
  1076.  
  1077.  
  1078. /**
  1079. * setID for canvas
  1080. */
  1081.  
  1082. function initializeCanvas() {
  1083. let GAME_CANVAS = "";
  1084. let DUEL_CANVAS = "";
  1085. //myLog("Is duels");
  1086. //myLog(duels);
  1087.  
  1088. if (isBattleRoyale) {
  1089. if (isDuel) {
  1090. GAME_CANVAS = document.querySelector(".game-panorama_panorama__3b2wI");
  1091. DUEL_CANVAS = document.querySelector(".game-panorama_panoramaCanvas__patp9");
  1092. }
  1093. else
  1094. {
  1095. GAME_CANVAS = document.querySelector(".br-game-layout__canvas");
  1096. DUEL_CANVAS = "dummy";
  1097. }
  1098. }
  1099. else {
  1100. GAME_CANVAS = document.querySelector(".game-layout__canvas");
  1101. DUEL_CANVAS = "dummy";
  1102. }
  1103. if (GAME_CANVAS && DUEL_CANVAS)
  1104. {
  1105. myLog("Canvas injected");
  1106. GAME_CANVAS.id = "player";
  1107. if (isDuel) {
  1108. DUEL_CANVAS.id = "default_player";
  1109. }
  1110. injectBaiduPlayer();
  1111. injectKakaoScript().then(() => {
  1112. myLog("Ready to inject Kakao player");
  1113. }).catch((error) => {
  1114. myLog(error);
  1115. });
  1116. }
  1117. else
  1118. {
  1119. setTimeout(initializeCanvas, 250);
  1120. }
  1121.  
  1122. }
  1123.  
  1124. /**
  1125. * Hide or show players based on where the next location is
  1126. */
  1127.  
  1128. function injectCanvas() {
  1129. if (isDuel)
  1130. {
  1131. canvasSwitch();
  1132. }
  1133. else
  1134. {
  1135. Google();
  1136. Baidu();
  1137. Kakao();
  1138. Yandex();
  1139. }
  1140. ZoomControls();
  1141. }
  1142.  
  1143. // for duels (class ID change)
  1144.  
  1145. function canvasSwitch()
  1146. {
  1147. let GOOGLE_MAPS_CANVAS = document.querySelector(".game-panorama_panoramaCanvas__patp9");
  1148. if (nextPlayer === "Google") {
  1149. document.getElementById("default_player").className = "game-panorama_panoramaCanvas__patp9";
  1150. document.getElementById("PanoramaMap").className = "inactive";
  1151. document.getElementById("roadview").className = "inactive";
  1152. document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "hidden";
  1153. document.getElementById("Main Button").google = true;
  1154. document.getElementById("switch").nextPlayer = "Google";
  1155. document.getElementById("switch").useGoogle = true;
  1156. myLog("Google Duel Canvas loaded");
  1157. }
  1158. else if (nextPlayer === "Baidu")
  1159. {
  1160. document.getElementById("default_player").className = "inactive";
  1161. document.getElementById("PanoramaMap").className = "game-panorama_panorama__3b2wI";
  1162. document.getElementById("roadview").className = "inactive";
  1163. document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "hidden";
  1164. document.getElementById("Main Button").google = false;
  1165. document.getElementById("switch").nextPlayer = "Baidu";
  1166. document.getElementById("switch").useGoogle = false;
  1167. myLog("Baidu Duel Canvas loaded");
  1168. }
  1169. else if (nextPlayer === "Kakao")
  1170. {
  1171. document.getElementById("default_player").className = "inactive";
  1172. document.getElementById("PanoramaMap").className = "inactive";
  1173. document.getElementById("roadview").className = "game-panorama_panorama__3b2wI";
  1174. document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "hidden";
  1175. document.getElementById("Main Button").google = false;
  1176. document.getElementById("switch").nextPlayer = "Kakao";
  1177. document.getElementById("switch").useGoogle = false;
  1178. myLog("Kakao Duel Canvas loaded");
  1179. }
  1180. else if (nextPlayer === "Yandex")
  1181. {
  1182. document.getElementById("default_player").className = "inactive";
  1183. document.getElementById("PanoramaMap").className = "inactive";
  1184. document.getElementById("roadview").className = "inactive";
  1185. document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "";
  1186. document.getElementById("Main Button").google = false;
  1187. document.getElementById("switch").nextPlayer = "Yandex";
  1188. document.getElementById("switch").useGoogle = false;
  1189. myLog("Yandex Duel Canvas loaded");
  1190. }
  1191. }
  1192.  
  1193. // for Battle Royale and classic (change visibility)
  1194.  
  1195. function Google() {
  1196. let GOOGLE_MAPS_CANVAS = ""
  1197. if (isBattleRoyale) {
  1198. GOOGLE_MAPS_CANVAS = document.querySelector(".br-game-layout__panorama-canvas");
  1199. }
  1200. else {
  1201. GOOGLE_MAPS_CANVAS = document.querySelector(".game-layout__panorama-canvas");
  1202. }
  1203. if (nextPlayer === "Google") {
  1204. GOOGLE_MAPS_CANVAS.style.visibility = "";
  1205. document.getElementById("Main Button").google = true;
  1206. document.getElementById("switch").nextPlayer = "Google";
  1207. document.getElementById("switch").useGoogle = true;
  1208. myLog("Google Canvas loaded");
  1209. }
  1210. else {
  1211. GOOGLE_MAPS_CANVAS.style.visibility = "hidden";
  1212. document.getElementById("Main Button").google = false;
  1213. myLog("Google Canvas hidden");
  1214. }
  1215.  
  1216. }
  1217.  
  1218. function Baidu() {
  1219. let BAIDU_MAPS_CANVAS = document.getElementById("PanoramaMap");
  1220. myLog("Baidu canvas");
  1221. if (nextPlayer === "Baidu") {
  1222. BAIDU_MAPS_CANVAS.style.visibility = "";
  1223. document.getElementById("switch").nextPlayer = "Baidu";
  1224. document.getElementById("switch").useGoogle = false;
  1225. myLog("Baidu Canvas loaded");
  1226. }
  1227. else {
  1228. BAIDU_MAPS_CANVAS.style.visibility = "hidden";
  1229. myLog("Baidu Canvas hidden");
  1230. }
  1231.  
  1232. }
  1233.  
  1234. function Kakao() {
  1235. let KAKAO_MAPS_CANVAS = document.getElementById("roadview");
  1236. myLog("Kakao canvas");
  1237. if (nextPlayer === "Kakao") {
  1238. KAKAO_MAPS_CANVAS.style.visibility = "";
  1239. document.getElementById("switch").nextPlayer = "Kakao";
  1240. document.getElementById("switch").useGoogle = false;
  1241. myLog("Kakao Canvas loaded");
  1242. }
  1243. else {
  1244. KAKAO_MAPS_CANVAS.style.visibility = "hidden";
  1245. myLog("Kakao Canvas hidden");
  1246. }
  1247.  
  1248. }
  1249.  
  1250. function Yandex() {
  1251. let YANDEX_MAPS_CANVAS = document.querySelector(".ymaps-2-1-79-panorama-screen");
  1252. if (YANDEX_MAPS_CANVAS != null)
  1253. {
  1254. // myLog("Yandex canvas");
  1255. /* myLog(YANDEX_MAPS_CANVAS); */
  1256. if (nextPlayer === "Yandex") {
  1257. YANDEX_MAPS_CANVAS.style.visibility = "";
  1258. document.getElementById("switch").nextPlayer = "Yandex";
  1259. document.getElementById("switch").useGoogle = false;
  1260. myLog("Yandex Canvas loaded");
  1261. }
  1262. else {
  1263. YANDEX_MAPS_CANVAS.style.visibility = "hidden";
  1264. myLog("Yandex Canvas hidden");
  1265. }
  1266. }
  1267.  
  1268. }
  1269.  
  1270. /**
  1271. * Adjust button placement
  1272. */
  1273.  
  1274. function ZoomControls() {
  1275. let style = `
  1276. .ymaps-2-1-79-panorama-gotoymaps {display: none !important;}
  1277. .game-layout__controls {bottom: 8rem !important; left: 1rem !important;}
  1278. `;
  1279.  
  1280. let style_element = document.createElement("style");
  1281. style_element.innerHTML = style;
  1282. document.body.appendChild(style_element);
  1283. }
  1284.  
  1285. /**
  1286. * Updates the compass to match Yandex Panorama facing
  1287. */
  1288. function updateCompass() {
  1289. if (!COMPASS) {
  1290. let compass = document.querySelector("img.compass__indicator");
  1291. if (compass != null) {
  1292. COMPASS = compass;
  1293. let direction = YandexPlayer.getDirection()[0] * -1;
  1294. COMPASS.setAttribute("style", `transform: rotate(${direction}deg);`);
  1295. }
  1296. }
  1297. else {
  1298. let direction = YandexPlayer.getDirection()[0] * -1;
  1299. COMPASS.setAttribute("style", `transform: rotate(${direction}deg);`);
  1300. }
  1301. }
  1302.  
  1303. /**
  1304. * Open next location in streetview player given next player and next coordinate
  1305. */
  1306.  
  1307. function goToLocation() {
  1308. myLog("Going to location");
  1309. if (nextPlayer === "Yandex") {
  1310. let options = {};
  1311. YandexPlayer.moveTo([global_lat, global_lng], options);
  1312. YandexPlayer.setDirection([0, 16]);
  1313. YandexPlayer.setSpan([10, 67]);
  1314. }
  1315. else if (nextPlayer === "Baidu") {
  1316. let a = new BMap.Point(global_lng, global_lat);
  1317. BaiduPlayer.setPov({ heading: -40, pitch: 6 });
  1318. BaiduPlayer.setPosition(a);
  1319. }
  1320. else if (nextPlayer === "Kakao") {
  1321. var roadviewClient = new kakao.maps.RoadviewClient();
  1322. var position = new kakao.maps.LatLng(global_lat, global_lng);
  1323. roadviewClient.getNearestPanoId(position, 500, function (panoId) {
  1324. KakaoPlayer.setPanoId(panoId, position);
  1325. });
  1326. }
  1327. document.getElementById("switch").lat = global_lat;
  1328. document.getElementById("switch").lng = global_lng;
  1329. }
  1330.  
  1331. /**
  1332. * Handle undo using the location history of the current round
  1333. */
  1334.  
  1335. function goToUndoMove(data) {
  1336. /* myLog(global_lat);
  1337. myLog(global_lng); */
  1338. let options = {};
  1339. let prevStep = null;
  1340. if (locHistory.length === 1) {
  1341. prevStep = locHistory[0];
  1342. }
  1343. else {
  1344. prevStep = locHistory.pop();
  1345. }
  1346. // myLog(prevStep);
  1347. // myLog(locHistory)
  1348. if (nextPlayer === "Yandex") {
  1349. defaultPanoIdChange = false;
  1350. YandexPlayer.moveTo([prevStep[0], prevStep[1]], options);
  1351. YandexPlayer.setDirection([prevStep[2], prevStep[3]]);
  1352. YandexPlayer.setSpan([10, 67]);
  1353. document.getElementById("switch").lat = prevStep[0];
  1354. document.getElementById("switch").lng = prevStep[1];
  1355. }
  1356. else if (nextPlayer === "Kakao") {
  1357. let btn = document.querySelector("button[data-qa='undo-move']");
  1358. btn.disabled = false;
  1359. btn.classList.remove('styles_disabled__W_k45');
  1360. defaultPanoIdChange = false;
  1361. let position = new kakao.maps.LatLng(prevStep[0], prevStep[1]);
  1362. KakaoPlayer.setPanoId(prevStep[2], position);
  1363. document.getElementById("switch").lat = prevStep[0];
  1364. document.getElementById("switch").lng = prevStep[1];
  1365. document.getElementById("switch").useGoogle = false;
  1366. document.getElementById("Main Button").google = false;
  1367. // myLog("Undo 1 step");
  1368. // myLog(locHistory);
  1369. }
  1370. else if (nextPlayer === "Baidu") {
  1371. // myLog(prevStep[1]);
  1372. let position = new BMap.Point(prevStep[1], prevStep[0]);
  1373. let pov = { heading: prevStep[2], pitch: prevStep[3] };
  1374. BaiduPlayer.setPosition(position);
  1375. BaiduPlayer.setPov(pov);
  1376. document.getElementById("switch").lat = prevStep[1];
  1377. document.getElementById("switch").lng = prevStep[0];
  1378. }
  1379.  
  1380. }
  1381.  
  1382. function BYKTeleport()
  1383. {
  1384. let teleportButtonBYK = document.getElementById("Main Button");
  1385. if (teleportButtonBYK)
  1386. {
  1387. teleportButtonBYK.addEventListener("click", () => {
  1388. if (!teleportButtonBYK.google)
  1389. {
  1390. // myLog("non-Google Teleport");
  1391. let prevStep = null;
  1392. if (locHistory.length === 1) {
  1393. prevStep = locHistory[0];
  1394. }
  1395. else {
  1396. prevStep = locHistory[locHistory.length - 1];
  1397. }
  1398. // myLog(prevStep);
  1399. let options = {};
  1400. let place, position, pID;
  1401. if (nextPlayer === "Yandex") {
  1402. place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[2]), teleportButtonBYK.distance * 0.001);
  1403. YandexPlayer.setDirection([prevStep[2], prevStep[3]]);
  1404. YandexPlayer.moveTo([place.lat, place.lng], options);
  1405. YandexPlayer.setSpan([10, 67]);
  1406. // locHistory.push([place.lat, place.lng, prevStep[2], prevStep[3]]);
  1407. }
  1408. else if (nextPlayer === "Kakao") {
  1409. // place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[3]), teleportButtonBYK.distance * 0.001);
  1410. // position = new kakao.maps.LatLng(place.lat, place.lng);
  1411. // pID = KakaoPlayer.getViewpointWithPanoId();
  1412. // KakaoPlayer.setPanoId(pID.panoId, position);
  1413. // locHistory.push([place.lat, place.lng, pID.panoId, prevStep[3]]);
  1414. var roadviewClient = new kakao.maps.RoadviewClient();
  1415. place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[3]), teleportButtonBYK.distance * 0.001);
  1416. position = new kakao.maps.LatLng(place.lat, place.lng);
  1417. roadviewClient.getNearestPanoId(position, 500, function (panoId) {
  1418. KakaoPlayer.setPanoId(panoId, position);
  1419. // myLog("Teleport 1 step");
  1420. // myLog(locHistory);
  1421. // locHistory.push([place.lat, place.lng, panoId, prevStep[3]]);
  1422. });
  1423. }
  1424. else if (nextPlayer === "Baidu") {
  1425. place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[2]), teleportButtonBYK.distance * 0.001);
  1426. position = new BMap.Point(place.lng, place.lat);
  1427. let pov = { heading: prevStep[2], pitch: prevStep[3] };
  1428. BaiduPlayer.setPosition(position);
  1429. BaiduPlayer.setPov(pov);
  1430. // locHistory.push([place.lat, place.lng, prevStep[2], prevStep[3]]);
  1431. }
  1432. document.getElementById("switch").lat = place.lat;
  1433. document.getElementById("switch").lng = place.lng;
  1434. if (teleportButtonBYK.distance > 150)
  1435. {
  1436. teleportButtonBYK.distance = 100;
  1437. teleportButtonBYK.innerHTML = "Teleport " + teleportButtonBYK.distance + " m";
  1438. }
  1439. }
  1440. });
  1441. }
  1442. else
  1443. {
  1444. }
  1445. }
  1446.  
  1447. function SyncListener()
  1448. {
  1449. let googleKakaoButton = document.getElementById("switch");
  1450. googleKakaoButton.addEventListener("click", () => {
  1451. if (googleKakaoButton.useGoogle == false) {
  1452. // googleKakaoButton.useGoogle = true;
  1453. if (googleKakaoButton.nextPlayer === "Yandex") {
  1454. let options = {};
  1455. YandexPlayer.moveTo([googleKakaoButton.lat, googleKakaoButton.lng], options);
  1456. YandexPlayer.setDirection([document.getElementById("switch").heading, 0]);
  1457.  
  1458. // document.getElementById("switch").nextPlayer = "Yandex";
  1459. }
  1460. else if (googleKakaoButton.nextPlayer === "Kakao") {
  1461. let roadviewClient = new kakao.maps.RoadviewClient();
  1462. // myLog(googleKakaoButton.lat);
  1463. let position = new kakao.maps.LatLng(googleKakaoButton.lat, googleKakaoButton.lng);
  1464. roadviewClient.getNearestPanoId(position, 500, function (panoId) {
  1465. KakaoPlayer.setPanoId(panoId, position);
  1466. });
  1467. KakaoPlayer.setViewpoint({
  1468. pan: document.getElementById("switch").heading,
  1469. tilt: 0,
  1470. zoom: 0
  1471. });
  1472. // document.getElementById("switch").nextPlayer = "Kakao";
  1473. }
  1474. }
  1475. });
  1476.  
  1477. }
  1478.  
  1479.  
  1480.  
  1481.  
  1482. /**
  1483. * Gets the seed data for the current game
  1484. *
  1485. * @returns Promise with seed data as object
  1486. */
  1487. function getSeed() {
  1488. // myLog("getSeed called");
  1489. return new Promise((resolve, reject) => {
  1490. let token = getToken();
  1491. let URL;
  1492. let cred = ""
  1493.  
  1494. const PATHNAME = window.location.pathname;
  1495.  
  1496. if (PATHNAME.startsWith("/game/")) {
  1497. URL = `https://www.geoguessr.com/api/v3/games/${token}`;
  1498. }
  1499. else if (PATHNAME.startsWith("/challenge/")) {
  1500. URL = `https://www.geoguessr.com/api/v3/challenges/${token}/game`;
  1501. }
  1502. else if (PATHNAME.startsWith("/battle-royale/")) {
  1503. URL = `https://game-server.geoguessr.com/api/battle-royale/${token}`;
  1504. }
  1505. else if (PATHNAME.startsWith("/duels/") || PATHNAME.startsWith("/team-duels/")) {
  1506. URL = `https://game-server.geoguessr.com/api/duels/${token}`;
  1507. }
  1508. if (isBattleRoyale) {
  1509. fetch(URL, {
  1510. // Include credentials to GET from the endpoint
  1511. credentials: 'include'
  1512. })
  1513. .then((response) => response.json())
  1514. .then((data) => {
  1515. resolve(data);
  1516. })
  1517. .catch((error) => {
  1518. reject(error);
  1519. });
  1520. }
  1521. else {
  1522. fetch(URL)
  1523. .then((response) => response.json())
  1524. .then((data) => {
  1525. resolve(data);
  1526. })
  1527. .catch((error) => {
  1528. reject(error);
  1529. });
  1530. }
  1531. });
  1532. }
  1533.  
  1534. /**
  1535. * Gets the token from the current URL
  1536. *
  1537. * @returns token
  1538. */
  1539. function getToken() {
  1540. const PATHNAME = window.location.pathname;
  1541. if (PATHNAME.startsWith("/game/")) {
  1542. return PATHNAME.replace("/game/", "");
  1543. }
  1544. else if (PATHNAME.startsWith("/challenge/")) {
  1545. return PATHNAME.replace("/challenge/", "");
  1546. }
  1547. else if (PATHNAME.startsWith("/battle-royale/")) {
  1548. return PATHNAME.replace("/battle-royale/", "");
  1549. }
  1550. else if (PATHNAME.startsWith("/duels/")) {
  1551. return PATHNAME.replace("/duels/", "");
  1552. }
  1553. else if (PATHNAME.startsWith("/team-duels/")) {
  1554. return PATHNAME.replace("/team-duels/", "");
  1555. }
  1556. }
  1557.  
  1558. /**
  1559. * Gets the round number from the ongoing game from the page itself
  1560. *
  1561. * @returns Round number
  1562. */
  1563. function getRoundFromPage() {
  1564. const roundData = document.querySelector("div[data-qa='round-number']");
  1565. if (roundData) {
  1566. let roundElement = roundData.querySelector("div:last-child");
  1567. if (roundElement) {
  1568. let round = parseInt(roundElement.innerText.charAt(0));
  1569. if (!isNaN(round) && round >= 1 && round <= 5) {
  1570. return round;
  1571. }
  1572. }
  1573. }
  1574. else {
  1575. return ROUND;
  1576. }
  1577. }
  1578.  
  1579.  
  1580. /**
  1581. * Injects Yandex Script
  1582. */
  1583. function injectYandexScript() {
  1584. return new Promise((resolve, reject) => {
  1585. if (!YANDEX_INJECTED) {
  1586. if (YANDEX_API_KEY === "") {
  1587. myLog("No Yandex Key")
  1588. reject();
  1589. }
  1590. else {
  1591. const SCRIPT = document.createElement("script");
  1592. SCRIPT.type = "text/javascript";
  1593. SCRIPT.async = true;
  1594. SCRIPT.onload = () => {
  1595. ymaps.ready(() => {
  1596. YANDEX_INJECTED = true;
  1597. myHighlight("Yandex API Loaded");
  1598. resolve();
  1599. });
  1600. }
  1601. SCRIPT.src = `https://api-maps.yandex.ru/2.1/?lang=en_US&apikey=${YANDEX_API_KEY}`;
  1602. document.body.appendChild(SCRIPT);
  1603. }
  1604. }
  1605. else {
  1606. resolve();
  1607. }
  1608. });
  1609. }
  1610.  
  1611. /**
  1612. * Injects Yandex Player and calls handleReturnToStart
  1613. */
  1614. function injectYandexPlayer() {
  1615. let lat = 41.321861;
  1616. let lng = 69.212920;
  1617.  
  1618. let options = {
  1619. "direction": [0, 16],
  1620. "span": [10, 67],
  1621. "controls": ["zoomControl"]
  1622. };
  1623. ymaps.panorama.createPlayer("player", [lat, lng], options)
  1624. .done((player) => {
  1625. YandexPlayer = player;
  1626. YandexPlayer.events.add("directionchange", (e) => {
  1627. updateCompass();
  1628. let pov = YandexPlayer.getDirection();
  1629. if (locHistory.length > 0 && nextPlayer == "Yandex") {
  1630. document.getElementById("switch").heading = pov[0];
  1631. locHistory[locHistory.length - 1][2] = pov[0];
  1632. locHistory[locHistory.length - 1][3] = pov[1];
  1633. }
  1634. });
  1635. YandexPlayer.events.add("panoramachange", (e) => {
  1636. if (defaultPanoIdChange) {
  1637. let num = YandexPlayer.getPanorama().getPosition();
  1638. let pov = YandexPlayer.getDirection();
  1639. // myLog(num);
  1640. // myLog(pov);
  1641. if (nextPlayer == "Yandex")
  1642. {
  1643. locHistory.push([num[0], num[1], pov[0], pov[1]]);
  1644. }
  1645. let btn = document.querySelector("button[data-qa='undo-move']");
  1646. if (locHistory.length > 1) {
  1647. btn.disabled = false;
  1648. btn.classList.remove('styles_disabled__W_k45');
  1649. }
  1650. // myLog(locHistory);
  1651. }
  1652. defaultPanoIdChange = true;
  1653.  
  1654. });
  1655. myHighlight("Yandex Player injected");
  1656. });
  1657.  
  1658. }
  1659.  
  1660.  
  1661. /**
  1662. * Injects Baidu script
  1663. */
  1664.  
  1665. function injectBaiduScript() {
  1666. return new Promise((resolve, reject) => {
  1667. if (!BAIDU_INJECTED) {
  1668. if (BAIDU_API_KEY === "") {
  1669. let canvas = document.getElementById("player");
  1670. myLog("No Baidu Key")
  1671. }
  1672. else {
  1673. const SCRIPT = document.createElement("script");
  1674. SCRIPT.type = "text/javascript";
  1675. SCRIPT.async = true;
  1676. SCRIPT.src = `https://api.map.baidu.com/api?v=3.0&ak=${BAIDU_API_KEY}&callback=init`;
  1677. document.body.appendChild(SCRIPT);
  1678.  
  1679. let canvas = document.createElement("bmap");
  1680. if (isBattleRoyale) {
  1681. if (isDuel)
  1682. {
  1683. canvas.innerHTML = `
  1684. <div id="PanoramaMap" class="inactive" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
  1685. `;
  1686. }
  1687. else
  1688. {
  1689. canvas.innerHTML = `
  1690. <div id="PanoramaMap" class="br-game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
  1691. `;
  1692. }
  1693. }
  1694. else {
  1695. canvas.innerHTML = `
  1696. <div id="PanoramaMap" class="game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
  1697. `;
  1698. }
  1699.  
  1700. var div = document.getElementById("player");
  1701. div.appendChild(canvas);
  1702.  
  1703. SCRIPT.addEventListener('load', () => {
  1704. myHighlight("Baidu API Loaded");
  1705. // resolve(BMap);
  1706. let timeout = 0;
  1707. let interval = setInterval(() => {
  1708. if (timeout >= 40) {
  1709. reject();
  1710. clearInterval(interval);
  1711. }
  1712. if (typeof BMap.Panorama !== undefined) {
  1713. BAIDU_INJECTED = true;
  1714. resolve(BMap);
  1715. clearInterval(interval);
  1716. }
  1717. timeout += 1;
  1718. }, 500);
  1719. })
  1720.  
  1721.  
  1722. }
  1723. }
  1724. else {
  1725. resolve();
  1726. }
  1727. });
  1728. }
  1729.  
  1730. /**
  1731. * Injects Baidu Player and calls handleReturnToStart
  1732. */
  1733. function injectBaiduPlayer() {
  1734. injectBaiduScript().then(BMap => {
  1735. BaiduPlayer = new BMap.Panorama('PanoramaMap');
  1736. BaiduPlayer.setPov({ heading: -40, pitch: 6 });
  1737. BaiduPlayer.setPosition(new BMap.Point(0, 0));
  1738. if (!eventListenerAttached && !povListenerAttached) {
  1739. myLog("position_listener attached");
  1740. BaiduPlayer.addEventListener('position_changed', function (e) {
  1741. eventListenerAttached = true;
  1742. myLog('position_changed')
  1743. let num = BaiduPlayer.getPosition();
  1744. let pov = BaiduPlayer.getPov();
  1745. if (nextPlayer == "Baidu" && num.lat != 0)
  1746. {
  1747. locHistory.push([num.lat, num.lng, pov.heading, pov.pitch]);
  1748. }
  1749. if (!isBattleRoyale || isDuel)
  1750. {
  1751. let btn = document.querySelector("button[data-qa='undo-move']");
  1752. if (locHistory.length > 1) {
  1753. btn.disabled = false;
  1754. btn.classList.remove('styles_disabled__W_k45');
  1755. }
  1756. }
  1757. // myLog(locHistory);
  1758. })
  1759.  
  1760. BaiduPlayer.addEventListener('pov_changed', function (e) {
  1761. // myLog("pov_listener attached");
  1762. povListenerAttached = true;
  1763. // myLog('pov_changed')
  1764. let pov = BaiduPlayer.getPov();
  1765. if (locHistory.length > 0 && nextPlayer == "Baidu") {
  1766. locHistory[locHistory.length - 1][2] = pov.heading;
  1767. locHistory[locHistory.length - 1][3] = pov.pitch;
  1768. }
  1769. // myLog(locHistory);
  1770. })
  1771. }
  1772. });
  1773. }
  1774.  
  1775. /**
  1776. * Injects Kakao script
  1777. */
  1778.  
  1779. function injectKakaoScript() {
  1780. return new Promise((resolve, reject) => {
  1781. if (!KAKAO_INJECTED) {
  1782. if (KAKAO_API_KEY === "") {
  1783. myLog("No Kakao Key")
  1784. }
  1785. else {
  1786.  
  1787. let canvas = document.createElement("kmap");
  1788. if (isBattleRoyale) {
  1789. if (isDuel)
  1790. {
  1791. canvas.innerHTML = `
  1792. <div id="roadview" class="inactive" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
  1793. `;
  1794. }
  1795. else
  1796. {
  1797. canvas.innerHTML = `
  1798. <div id="roadview" class="br-game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
  1799. `;
  1800. }
  1801. }
  1802. else {
  1803. canvas.innerHTML = `
  1804. <div id="roadview" class="game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
  1805. `;
  1806. }
  1807.  
  1808. var div = document.getElementById("player");
  1809. div.appendChild(canvas);
  1810.  
  1811. const SCRIPT = document.createElement("script");
  1812. SCRIPT.async = true;
  1813. // SCRIPT.type = "text/javascript";
  1814. SCRIPT.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${KAKAO_API_KEY}&autoload=false`;
  1815. document.body.appendChild(SCRIPT);
  1816. SCRIPT.onload = () => {
  1817. kakao.maps.load(function () {
  1818. var position = new kakao.maps.LatLng(33.450701, 126.560667);
  1819. let roadviewContainer = document.getElementById('roadview');
  1820. KakaoPlayer = new kakao.maps.Roadview(roadviewContainer);
  1821. var panoId = 1023434522;
  1822. KakaoPlayer.setPanoId(panoId, position);
  1823. KAKAO_INJECTED = true;
  1824. kakao.maps.event.addListener(KakaoPlayer, 'panoid_changed', function() {
  1825. if (defaultPanoIdChange) {
  1826. let latlng = KakaoPlayer.getPosition();
  1827. let lat = latlng.getLat();
  1828. let lng = latlng.getLng();
  1829. let pID = KakaoPlayer.getViewpointWithPanoId();
  1830. if (nextPlayer == "Kakao" && lat != 33.45047613915499)
  1831. {
  1832. // myLog("push");
  1833. locHistory.push([lat, lng, pID.panoId, pID.pan]);
  1834. document.getElementById("switch").heading = pID.pan;
  1835. }
  1836. let btn = document.querySelector("button[data-qa='undo-move']");
  1837. if (locHistory.length > 1 && (btn != null)) {
  1838. btn.disabled = false;
  1839. btn.classList.remove('styles_disabled__W_k45');
  1840. }
  1841. // myLog(locHistory);
  1842. }
  1843. defaultPanoIdChange = true;
  1844. });
  1845. kakao.maps.event.addListener(KakaoPlayer, 'viewpoint_changed', function() {
  1846. // myLog("pov_listener attached");
  1847. let pID = KakaoPlayer.getViewpointWithPanoId();
  1848. if (locHistory.length > 0 && nextPlayer == "Kakao") {
  1849. document.getElementById("switch").heading = pID.pan;
  1850. locHistory[locHistory.length - 1][3] = pID.pan;
  1851. }
  1852. // myLog(locHistory);
  1853. })
  1854. resolve();
  1855. });
  1856. };
  1857.  
  1858. }
  1859. }
  1860. else {
  1861. resolve();
  1862. }
  1863. });
  1864. }