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 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

// ==UserScript==
// @name          Geoguessr Unity Script with Duels
// @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.
// @version       3.2.0b
// @include       https://www.geoguessr.com/*
// @run-at        document-start
// @license       MIT
// @namespace https://gf.zukizuki.org/users/838374
// ==/UserScript==

// API Keys

var YANDEX_API_KEY = "b704b5a9-3d67-4d19-b702-ec7807cecfc6";
var BAIDU_API_KEY = "8dQ9hZPGEQnqg9r0O1C8Ate2N6P8Zk92";
var KAKAO_API_KEY = "cbacbe41e3a223d794f321de4f3e247b";
const MAPS_API_URL = "https://maps.googleapis.com/maps/api/js"; // removed "?" from the link

myLog("Geoguessr Unity Script");

// Store each player instance

let YandexPlayer, BaiduPlayer, KakaoPlayer;
let YANDEX_INJECTED = false;
let BAIDU_INJECTED = false;
let KAKAO_INJECTED = false;

// Game mode detection

let isBattleRoyale = false;
let isDuel = false;

// Player detection and coordinate conversion

let nextPlayer = "Google";
let global_lat = 0;
let global_lng = 0;
let global_panoID = null;

let krCoordinates = [38.75292321084364, 124.2804539232574, 33.18509676203202, 129.597381999198]
let global_radi = 100

// Callback variables

let eventListenerAttached = false;
let povListenerAttached = false;
let playerLoaded = false;
let teleportLoaded = false;
let syncLoaded = false;

// Minimize Yandex API use

let yandex_map = false;

// Handle Yandex compass

let COMPASS = null;

// Handle undo

let locHistory = [];
let defaultPanoIdChange = true;

// Round check

let ROUND = 0;
let CURRENT_ROUND_DATA = null;


// let NEW_ROUND_LOADED = false;

/**
 * Helper Functions
 */

// Pretty print

function myLog(...args) {
    console.log(...args);
}
function myHighlight(...args) {
    console.log(`%c${[...args]}`, "color: dodgerblue; font-size: 24px;");
}

// Hex to number conversion for Baidu coordinate conversion

function hex2a(hexx) {
    var hex = hexx.toString();
    var str = '';
    for (var i = 0; i < hex.length; i += 2)
        str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
    return str;
}

// Coordinate computation given heading, distance and current coordinates for teleport

function FindPointAtDistanceFrom(lat, lng, initialBearingRadians, distanceKilometres) {
    const radiusEarthKilometres = 6371.01;
    var distRatio = distanceKilometres / radiusEarthKilometres;
    var distRatioSine = Math.sin(distRatio);
    var distRatioCosine = Math.cos(distRatio);

    var startLatRad = DegreesToRadians(lat);
    var startLonRad = DegreesToRadians(lng);

    var startLatCos = Math.cos(startLatRad);
    var startLatSin = Math.sin(startLatRad);

    var endLatRads = Math.asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.cos(initialBearingRadians)));

    var endLonRads = startLonRad
    + Math.atan2(
        Math.sin(initialBearingRadians) * distRatioSine * startLatCos,
        distRatioCosine - startLatSin * Math.sin(endLatRads));

    return { lat: RadiansToDegrees(endLatRads), lng: RadiansToDegrees(endLonRads) };
}

function DegreesToRadians(degrees) {
    const degToRadFactor = Math.PI / 180;
    return degrees * degToRadFactor;
}

function RadiansToDegrees(radians) {
    const radToDegFactor = 180 / Math.PI;
    return radians * radToDegFactor;
}

// Script injection

function runAsClient(f) {
    var s = document.createElement("script");
    s.type = "text/javascript";
    s.text = "(async () => { try { await (" + f.toString() + ")(); } catch (e) { console.error(e); }})();";
    document.body.appendChild(s);
}

window.runAsClient = runAsClient;

/**
 * Resolves succesfully after detecting that Google Maps API was loaded in a page
 *
 * @returns Promise
 */

function gmp() {
    return new Promise((resolve, reject) => {
        let scriptObserver = new MutationObserver((mutations, observer) => {
            for (let mutation of mutations) {
                for (let node of mutation.addedNodes) {
                    if (node.tagName === "SCRIPT" && node.src.startsWith(MAPS_API_URL)) {
                        scriptObserver.disconnect();
                        scriptObserver = undefined;
                        myLog("Detected Google Maps API");
                        node.onload = () => resolve();
                    }
                }
            }
        });

        let bodyDone = false;
        let headDone = false;

        let injectorObserver = new MutationObserver((mutations, observer) => {
            if (!bodyDone && document.body) {
                bodyDone = true;
                myLog("Body Observer Injected");
                scriptObserver && scriptObserver.observe(document.body, {
                    childList: true
                });
            }
            if (!headDone && document.head) {
                headDone = true;
                myLog("Head Observer Injected");
                scriptObserver && scriptObserver.observe(document.head, {
                    childList: true
                });
            }
            if (headDone && bodyDone) {
                myLog("Body and Head Observers Injected");
                observer.disconnect();
            }
        });

        injectorObserver.observe(document.documentElement, {
            childList: true,
            subtree: true
        });
    });
}

/**
 * Creates teleportation and Kakao switch button
 *
 * @returns Promise
 */

function ArisKakao() {
    runAsClient(() => {

        // let radi = 100;
        const google = window.google;
        // console.log(google);
        let curPosition, mapPlayer;
        let kakao_enabled = true;

        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/");

        const getPosition = sv => (
            {
                lat: sv.position.lat(),
                lng: sv.position.lng(),
                heading: sv.pov.heading,
            });

        // Handle the street view being navigated
        const onMove = (sv) => {
            try {
                if (!isGamePage()) return;
                const position = getPosition(sv);
                curPosition = position;
                if (googleKakaoButton.useGoogle)
                {
                    googleKakaoButton.lng = position.lng;
                    googleKakaoButton.lat = position.lat;
                    googleKakaoButton.heading = position.heading;
                }
                googleKakaoButton.useGoogle = true;
                teleportButton.google = true;
                // googleKakaoButton.heading = position.lat;
                // console.log(position.heading);
                // console.log(googleKakaoButton.lng);
            }
            catch (e) {
                console.error("GeoGuessr Path Logger Error:", e);
            }
        };

        // Helper Functions

        function FindPointAtDistanceFrom(startPoint, initialBearingRadians, distanceKilometres) {
            const radiusEarthKilometres = 6371.01;
            var distRatio = distanceKilometres / radiusEarthKilometres;
            var distRatioSine = Math.sin(distRatio);
            var distRatioCosine = Math.cos(distRatio);

            var startLatRad = DegreesToRadians(startPoint.lat);
            var startLonRad = DegreesToRadians(startPoint.lng);

            var startLatCos = Math.cos(startLatRad);
            var startLatSin = Math.sin(startLatRad);

            var endLatRads = Math.asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.cos(initialBearingRadians)));

            var endLonRads = startLonRad
            + Math.atan2(
                Math.sin(initialBearingRadians) * distRatioSine * startLatCos,
                distRatioCosine - startLatSin * Math.sin(endLatRads));

            return { lat: RadiansToDegrees(endLatRads), lng: RadiansToDegrees(endLonRads) };
        }

        function DegreesToRadians(degrees) {
            const degToRadFactor = Math.PI / 180;
            return degrees * degToRadFactor;
        }

        function RadiansToDegrees(radians) {
            const radToDegFactor = 180 / Math.PI;
            return radians * radToDegFactor;
        }

        function svCheck(data, status) {
            if (status === 'OK') {
                // console.log("OK for " + data.location.latLng + " at ID " + data.location.pano);
                let l = data.location.latLng.toString().split(',');
                let lat = l[0].replaceAll('(', '')
                let lng = l[1].replaceAll(')', '')
                if (lat == curPosition.lat && lng == curPosition.lng)
                {
                    console.log("Trying more distance");
                    teleportButton.distance += 100;
                    teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
                }
                else
                {
                    console.log("Teleport Success");
                    mapPlayer.setPosition(data.location.latLng);
                    mapPlayer.setPov({
                        heading: googleKakaoButton.heading,
                        pitch: 0,
                    })
                    // console.log(teleportButton.distance);
                    if (teleportButton.distance > 150)
                    {
                        teleportButton.distance = 100;
                        teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
                    }
                }
            }
            else {
                console.log("STATUS NOT OK");
                teleportButton.distance += 100;
                teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
            }
        }

        // When a StreetViewPanorama is constructed, add a listener for moving

        const oldSV = google.maps.StreetViewPanorama;
        const svService = new google.maps.StreetViewService();

        google.maps.StreetViewPanorama = Object.assign(function (...args) {
            const res = oldSV.apply(this, args);
            this.addListener('position_changed', () => onMove(this));
            mapPlayer = this;
            return res;
        }, {
            prototype: Object.create(oldSV.prototype)
        });

        var showButtons = document.createElement("Button");
        showButtons.id = "Show Buttons"
        showButtons.innerHTML = "Script Buttons";
        showButtons.style =
            "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;";
        document.body.appendChild(showButtons);
        showButtons.addEventListener("click", () => {
            if (hide) {
                teleportButton.style.visibility = "";
                plusButton.style.visibility = "";
                minusButton.style.visibility = "";
                resetButton.style.visibility = "";
                googleKakaoButton.style.visibility = "";
                hide = false;
            }
            else {
                teleportButton.style.visibility = "hidden";
                plusButton.style.visibility = "hidden";
                minusButton.style.visibility = "hidden";
                resetButton.style.visibility = "hidden"
                googleKakaoButton.style.visibility = "hidden";
                hide = true;
            }
        });

        var teleportButton = document.createElement("Button");
        teleportButton.id = "Main Button";
        teleportButton.distance = 100;
        teleportButton.google = true;
        teleportButton.innerHTML = "Teleport 100m";
        teleportButton.style =
            "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;";
        document.body.appendChild(teleportButton);
        teleportButton.addEventListener("click", () => {
            // console.log("Google Teleport");
            if (teleportButton.google && mapPlayer != null)
            {
                let heading = mapPlayer.getPov().heading;
                let place = FindPointAtDistanceFrom(curPosition, DegreesToRadians(heading), teleportButton.distance * 0.001)
                svService.getPanorama({ location: place, radius: 1000 }, svCheck);
            }
        });

        var plusButton = document.createElement("Button");
        plusButton.id = "plus"
        plusButton.innerHTML = "+";
        plusButton.style =
            "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;";
        document.body.appendChild(plusButton);
        plusButton.addEventListener("click", () => {
            if (teleportButton.distance > 21 && teleportButton.distance < 149) {
                teleportButton.distance = teleportButton.distance + 25;
            }
            teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
        });

        var minusButton = document.createElement("Button");
        minusButton.id = "minus"
        minusButton.innerHTML = "-";
        minusButton.style =
            "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;";
        document.body.appendChild(minusButton);
        minusButton.addEventListener("click", () => {
            if (teleportButton.distance > 26) {
                teleportButton.distance = teleportButton.distance - 25;
            }
            teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
        });

        var resetButton = document.createElement("Button");
        resetButton.id = "reset"
        resetButton.innerHTML = "Reset";
        resetButton.style =
            "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;";
        document.body.appendChild(resetButton);
        resetButton.addEventListener("click", () => {
            teleportButton.distance = 100;
            teleportButton.innerHTML = "Teleport " + teleportButton.distance + " m";
        });

        var googleKakaoButton = document.createElement("Button");
        googleKakaoButton.id = "switch";
        googleKakaoButton.init = true;
        googleKakaoButton.nextPlayer = "Google";
        googleKakaoButton.useGoogle = false;
        googleKakaoButton.lng = 0
        googleKakaoButton.lat = 0
        googleKakaoButton.heading = 0
        googleKakaoButton.innerHTML = "Switch coverage";
        googleKakaoButton.style =
            "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;";
        document.body.appendChild(googleKakaoButton);
        googleKakaoButton.addEventListener("click", () => {
            let GOOGLE_MAPS_CANVAS1 = document.querySelector(".game-layout__panorama-canvas");
            let GOOGLE_MAPS_CANVAS2 = document.querySelector(".br-game-layout__panorama-canvas");
            let GOOGLE_MAPS_CANVAS3 = document.querySelector(".inactive");
            let duel = false;

            let GOOGLE_MAPS_CANVAS = null;
            if (GOOGLE_MAPS_CANVAS1 !== null)
            {
                GOOGLE_MAPS_CANVAS = GOOGLE_MAPS_CANVAS1;
            }
            else if (GOOGLE_MAPS_CANVAS2 !== null)
            {
                GOOGLE_MAPS_CANVAS = GOOGLE_MAPS_CANVAS2;
            }


            if (GOOGLE_MAPS_CANVAS3 !== null)
            {
                duel = true;
            }

            let KAKAO_MAPS_CANVAS = document.getElementById("roadview");
            let YANDEX_MAPS_CANVAS = document.querySelector(".ymaps-2-1-79-panorama-screen");
            if (googleKakaoButton.useGoogle == false) {
                if (duel)
                {
                    document.getElementById("default_player").className = "game-panorama_panoramaCanvas__patp9";
                    if (googleKakaoButton.nextPlayer == "Kakao")
                    {
                        document.getElementById("roadview").className = "inactive";
                    }
                }
                else
                {
                    GOOGLE_MAPS_CANVAS.style.visibility = "";
                    if (googleKakaoButton.nextPlayer == "Kakao")
                    {
                        KAKAO_MAPS_CANVAS.style.visibility = "hidden";
                    }
                    else if (googleKakaoButton.nextPlayer == "Yandex")
                    {
                        YANDEX_MAPS_CANVAS.style.visibility = "hidden";
                    }
                }
                svService.getPanorama({ location: { lat: googleKakaoButton.lat, lng: googleKakaoButton.lng }, radius: 1000 }, svCheck);
                googleKakaoButton.useGoogle = true;
                teleportButton.google = true;
                console.log("use Google");
            }
            else {
                if (duel)
                {
                    document.getElementById("default_player").className = "inactive";
                    if (googleKakaoButton.nextPlayer == "Kakao")
                    {
                        document.getElementById("roadview").className = "game-panorama_panorama__3b2wI";
                    }
                }
                else
                {
                    GOOGLE_MAPS_CANVAS.style.visibility = "hidden";
                    if (googleKakaoButton.nextPlayer == "Kakao")
                    {
                        KAKAO_MAPS_CANVAS.style.visibility = "";
                    }
                    else if (googleKakaoButton.nextPlayer == "Yandex")
                    {
                        YANDEX_MAPS_CANVAS.style.visibility = "";
                    }
                }
                googleKakaoButton.useGoogle = false;
                teleportButton.google = false;
                console.log("use Others");
            }
        });

        // Battle Royale UI optimization

        let hide = true;

        console.log("Buttons Loaded");
    });
}

/**
 * Handle Keyboard inputs
 */

function kBoard()
{
    document.addEventListener('keydown', logKey);
}

function logKey(e) {
    // myLog(e.code);
    if (e.code == "Space")
    {
        setHidden(true);
    }
    if (e.code == "Digit1")
    {
        setHidden(false);
        document.getElementById("Show Buttons").click();
    }
    else if (e.code == "Digit3")
    {
        document.getElementById("Main Button").click();
    }
    else if (e.code == "Digit2")
    {
        document.getElementById("minus").click();
    }
    else if (e.code == "Digit4")
    {
        document.getElementById("plus").click();

    }
}


/**
 * Hide or reveal the buttons, and disable buttons if such feature is not available
 */

function setHidden(cond)
{
    if (cond)
    {
        if (document.getElementById("Show Buttons") != null)
        {
            document.getElementById("Show Buttons").style.visibility = "hidden";
            if (document.getElementById("Main Button") != null)
            {
                document.getElementById("plus").style.visibility = "hidden";
                document.getElementById("minus").style.visibility = "hidden";
                document.getElementById("reset").style.visibility = "hidden";
                document.getElementById("Main Button").style.visibility = "hidden";
                document.getElementById("switch").style.visibility = "hidden";
            }
        }
    }
    else
    {
        if (document.getElementById("Show Buttons") != null)
        {
            document.getElementById("Show Buttons").style.visibility = "";
        }
    }
}

function setDisable(cond)
{
    if (cond !== "Google")
    {
        if (document.getElementById("Main Button") != null)
        {
            if (cond === "Baidu")
            {
                document.getElementById("switch").disabled = true;
                document.getElementById("switch").style.backgroundColor = "red";
            }
            else
            {
                document.getElementById("switch").disabled = false;
                document.getElementById("switch").style.backgroundColor = "#4CAF50";
            }
        }
    }
    else
    {
        if (document.getElementById("Main Button") != null)
        {
            document.getElementById("switch").disabled = true;
            document.getElementById("switch").style.backgroundColor = "red";
        }
    }
}

/**
 * This observer stays alive while the script is running
 */

function launchObserver() {
    ArisKakao();
    BYKTeleport();
    SyncListener();
    kBoard();
    myHighlight("Main Observer");
    const OBSERVER = new MutationObserver((mutations, observer) => {
        detectGamePage();
    });
    OBSERVER.observe(document.head, { attributes: true, childList: true, subtree: true });
}

/**
 * Once the Google Maps API was loaded we can do more stuff
 */

gmp().then(() => {
    launchObserver();
});


/**
 * Check whether the current page is a game, if so which game mode
 */

function detectGamePage() {
    let toLoad = !playerLoaded && !YandexPlayer && !BaiduPlayer && !KakaoPlayer && !YANDEX_INJECTED && !BAIDU_INJECTED && !KAKAO_INJECTED
    const PATHNAME = window.location.pathname;
    //myLog(PATHNAME);
    if (PATHNAME.startsWith("/game/") || PATHNAME.startsWith("/challenge/")) {
        // myLog("Game page");
        isBattleRoyale = false;
        isDuel = false;
        if (toLoad) {
            loadPlayers();
        }
        waitLoad();
    }
    else if (PATHNAME.startsWith("/battle-royale/")) {
        if (document.querySelector(".br-game-layout") == null) {
            // myLog("Battle Royale Lobby");
            setHidden(true);
        }
        else {
            // myLog("Battle Royale");
            isBattleRoyale = true;
            isDuel = false;
            if (toLoad) {
                loadPlayers();
            }
            waitLoad();
        }
    }
    else if (PATHNAME.startsWith("/duels/") || PATHNAME.startsWith("/team-duels/")) {
        if (document.querySelector(".game_layout__1TqBM") == null) {
            // myLog("Battle Royale Lobby");
            setHidden(true);
        }
        else {
            // myLog("Duels");
            isBattleRoyale = true;
            isDuel = true;
            if (toLoad) {
                loadPlayers();
            }
            waitLoad();
        }
    }
    else {
        //myLog("Not a Game page");

        ROUND = 0;
        YandexPlayer = null;
        BaiduPlayer = null;
        KakaoPlayer = null;

        BAIDU_INJECTED = false;
        YANDEX_INJECTED = false;
        KAKAO_INJECTED = false;

        nextPlayer = "Google"
        global_lat = 0;
        global_lng = 0;
        global_panoID = null;

        COMPASS = null;
        eventListenerAttached = false;
        povListenerAttached = false;
        playerLoaded = false;
        locHistory = [];
        setHidden(true);
        yandex_map = false;
        CURRENT_ROUND_DATA = null;
    }
}

/**
 * Wait for various players to load
 */

function waitLoad() {
    if (!YandexPlayer || !BaiduPlayer || !KakaoPlayer || !YANDEX_INJECTED || !BAIDU_INJECTED || !KAKAO_INJECTED) {
        let teleportButton = document.getElementById("Main Button");
        let plusButton = document.getElementById("plus");
        let minusButton = document.getElementById("minus");
        let resetButton = document.getElementById("reset");
        let googleKakaoButton = document.getElementById("switch");
        let showButtons = document.getElementById("Show Buttons");
        if (document.querySelector(".br-game-layout__panorama-canvas") != null)
        {
            teleportButton.style.top = "2px";
            plusButton.style.top = "2px";
            minusButton.style.top = "2px";
            resetButton.style.top = "calc(2.5em + 2px)";
            googleKakaoButton.style.top = "calc(2.5em + 2px)";
            showButtons.style.top = "2px";

            teleportButton.style.right = "calc(9.5em + 300px)";
            plusButton.style.right = "calc(7em + 300px)";
            minusButton.style.right = "calc(20em + 300px)";
            resetButton.style.right = "calc(17.5em + 300px)";
            googleKakaoButton.style.right = "calc(7em + 300px)";
            showButtons.style.right = "300px";
        }


        if (document.querySelector(".game-panorama_panorama__3b2wI") != null)
        {
            teleportButton.style.top = "8em";
            plusButton.style.top = "8em";
            minusButton.style.top = "8em";
            resetButton.style.top = "10.5em";
            googleKakaoButton.style.top = "10.5em";
            showButtons.style.top = "8em";

        }

        setTimeout(waitLoad, 250);
    } else {
        checkRound();
    }
}

/**
 * Checks for round changes
 */

function checkRound() {
    //   myLog("Check Round");
    if (!isBattleRoyale) {
        let currentRound = getRoundFromPage();
        if (ROUND != currentRound) {
            myHighlight("New round");
            ROUND = currentRound;
            // NEW_ROUND_LOADED = true;
            COMPASS = null;
            locHistory = [];
            getMapData();
            nextButtonCallback();
        }
    }
    else {
        getMapData();
    }
}

/**
 * Add listeners if buttons have been created
 */

function nextButtonCallback()
{
    let nextButton = document.querySelector("button[data-qa='close-round-result']");
    if (nextButton != null)
    {
        nextButton.addEventListener("click", (e) => {
            if (document.getElementById("Show Buttons") != null)
            {
                myLog("try to hide show buttons")
                document.getElementById("Show Buttons").style.visibility = "";
            }
        })
    }
    else
    {
        setTimeout(nextButtonCallback, 500);
    }
}

function guessButtonCallback()
{
    let guessButton = document.querySelector("button[data-qa='perform-guess']");
    if (guessButton != null)
    {

        guessButton.addEventListener("click", (e) => {
            if (document.getElementById("Show Buttons") != null)
            {
                myLog("try to hide show buttons")
                document.getElementById("Show Buttons").style.visibility = "hidden";
                setHidden(true);
            }
        })
    }
    else
    {
        setTimeout(guessButtonCallback, 500);
    }
}

/**
 * Load different streetview players
 */

function injectYandex()
{
    injectYandexScript().then(() => {
        myLog("Ready to inject Yandex player");
        injectYandexPlayer();
    }).catch((error) => {
        myLog(error);
    });
}

function loadPlayers() {
    playerLoaded = true;
    if (!isBattleRoyale)
    {
        getSeed().then((data) => {
            // myLog(data);
            if (data.mapName.includes("A United World") || data.mapName.includes("byk"))
            {
                myLog("A United World");
                injectYandex();
            }
            else if (data.mapName.includes("Yandex"))
            {
                yandex_map = true;
                myLog("Is Yandex Map");
                injectYandex();
            }
            else{
                // YANDEX_API_KEY = "";
                YANDEX_INJECTED = true;
                YandexPlayer = "YD";
                myLog("Not a Yandex map");
            }
            setHidden(false);

        }).catch((error) => {
            myLog(error);
        });
    }
    else
    {
        injectYandex();
    }

    initializeCanvas();




}

/**
 * Handles Return to start and undo
 */

function handleReturnToStart() {
    let rtsButton = document.querySelector("button[data-qa='return-to-start']");
    if (rtsButton != null) {
        myLog("handleReturnToStart listener attached");
        rtsButton.addEventListener("click", (e) => {
            goToLocation();
            const elementClicked = e.target;
            elementClicked.setAttribute('listener', 'true');
            myLog("Return to start");
        });
        guessButtonCallback();
        setTimeout(function () {goToLocation();}, 1000);
    }
    else
    {
        setTimeout(handleReturnToStart, 500);
    }
}

function handleUndo() {
    let undoButton = document.querySelector("button[data-qa='undo-move']");
    if (undoButton != null)
    {
        myLog("Attach undo");
        undoButton.addEventListener("click", (e) => {
            if (locHistory.length > 0) {
                goToUndoMove();
                myLog("Undo Move");
            }
        })
    }
    else
    {
        setTimeout(handleUndo, 500);
    }

}

/**
 * Load game information
 */

function getMapData() {
    getSeed().then((data) => {
        // myHighlight("Seed data");
        // myLog(data);
        if (isBattleRoyale) {
            if (document.querySelector(".br-game-layout") == null && document.querySelector(".version3-in-game_layout__13T8U") == null) {
                // myLog("Battle Royale Lobby");
            }
            else
            {
                let origin = false;
                if (!CURRENT_ROUND_DATA) {
                    CURRENT_ROUND_DATA = data
                    origin = true;
                }

                if (origin || !(data.currentRoundNumber === CURRENT_ROUND_DATA.currentRoundNumber)) {
                    myHighlight("Battle Royale New round");
                    // NEW_ROUND_LOADED = true;
                    COMPASS = null;
                    locHistory = [];
                    setHidden(false);
                    if (!origin) {
                        CURRENT_ROUND_DATA = data;
                    }
                    locationCheck(data);
                    // myLog(data);
                    //setTimeout(function () {goToLocation();}, 1000);
                    handleReturnToStart();
                    if (isDuel)
                    {
                        handleUndo();
                        hideButtons();
                    }

                }
            }
        }
        else {
            locationCheck(data);
            //setTimeout(function () { goToLocation();}, 1000);
            handleReturnToStart();
            handleUndo();
            hideButtons();
        }
    }).catch((error) => {
        myLog(error);
    });
}

/**
 * Hide unnecessary buttons for non-Google coverages
 */

function hideButtons() {
    let CHECKPOINT = document.querySelector("button[data-qa='set-checkpoint']");
    let ZOOM_IN = document.querySelector("button[data-qa='pano-zoom-in']");
    let ZOOM_OUT = document.querySelector("button[data-qa='pano-zoom-out']");

    if (CHECKPOINT != null)
    {
        if (nextPlayer === "Google") {

            CHECKPOINT.style.visibility = "";
            ZOOM_IN.style.visibility = "";
            ZOOM_OUT.style.visibility = "";
            myLog("Buttons Unhidden");

        }
        else {

            CHECKPOINT.style.visibility = "hidden";
            ZOOM_IN.style.visibility = "hidden";
            ZOOM_OUT.style.visibility = "hidden";
            myLog("Buttons Hidden");

        }
    }
    else
    {
        setTimeout(hideButtons, 250);
    }
}

/**
 * Check which player to use for the next location
 */

function locationCheck(data) {
    // console.log(data);
    if (isBattleRoyale) {
        if (isDuel)
        {
            global_lat = data.rounds[data.currentRoundNumber - 1].panorama.lat;
            global_lng = data.rounds[data.currentRoundNumber - 1].panorama.lng;
            global_panoID = data.rounds[data.currentRoundNumber - 1].panorama.panoId;
        }
        else
        {
            global_lat = data.rounds[data.currentRoundNumber - 1].lat;
            global_lng = data.rounds[data.currentRoundNumber - 1].lng;
            global_panoID = data.rounds[data.currentRoundNumber - 1].panoId;
        }
    }
    else {
        global_lat = data.rounds[data.round - 1].lat;
        global_lng = data.rounds[data.round - 1].lng;
        global_panoID = data.rounds[data.round - 1].panoId;
    }
    // myLog(global_lat);
    // myLog(global_lng);
    // myLog(krCoordinates);

    nextPlayer = "Google";

    if ( krCoordinates[0] > global_lat && krCoordinates[2] < global_lat && krCoordinates[1] < global_lng && krCoordinates[3] > global_lng)
    {
        nextPlayer = "Kakao";
    }
    else if (yandex_map)
    {
        nextPlayer = "Yandex";
    }
    else
    {
        if (global_panoID) {
            let locInfo = hex2a(global_panoID);
            let mapType = locInfo.substring(0, 5);
            if (mapType === "BDMAP") {
                nextPlayer = "Baidu";
                let coord = locInfo.substring(5);
                global_lat = coord.split(",")[0];
                global_lng = coord.split(",")[1];
                // myLog(global_lat);
            }
            else if (mapType === "YDMAP" ) {
                nextPlayer = "Yandex";
            }
        }
    }

    // Disable buttons if NM, NMPZ

    if(!isBattleRoyale)
    {
        if (data.forbidMoving || data.forbidRotating || data.forbidZooming)
        {
            setDisable("NMPZ");
        }
        else
        {
            setDisable(nextPlayer);
        }
    }
    else
    {
        if (data.movementOptions.forbidMoving || data.movementOptions.forbidRotating || data.movementOptions.forbidZooming)
        {
            setDisable("NMPZ");
        }
        else
        {
            setDisable(nextPlayer);
        }
    }

    myLog(nextPlayer);
    injectCanvas();
}


/**
 * setID for canvas
 */

function initializeCanvas() {
    let GAME_CANVAS = "";
    let DUEL_CANVAS = "";
    //myLog("Is duels");
    //myLog(duels);

    if (isBattleRoyale) {
        if (isDuel) {
            GAME_CANVAS = document.querySelector(".game-panorama_panorama__3b2wI");
            DUEL_CANVAS = document.querySelector(".game-panorama_panoramaCanvas__patp9");
        }
        else
        {
            GAME_CANVAS = document.querySelector(".br-game-layout__canvas");
            DUEL_CANVAS = "dummy";
        }
    }
    else {
        GAME_CANVAS = document.querySelector(".game-layout__canvas");
        DUEL_CANVAS = "dummy";
    }
    if (GAME_CANVAS && DUEL_CANVAS)
    {
        myLog("Canvas injected");
        GAME_CANVAS.id = "player";
        if (isDuel) {
            DUEL_CANVAS.id = "default_player";
        }
        injectBaiduPlayer();
        injectKakaoScript().then(() => {
            myLog("Ready to inject Kakao player");
        }).catch((error) => {
            myLog(error);
        });
    }
    else
    {
        setTimeout(initializeCanvas, 250);
    }

}

/**
 * Hide or show players based on where the next location is
 */

function injectCanvas() {
    if (isDuel)
    {
        canvasSwitch();
    }
    else
    {
        Google();
        Baidu();
        Kakao();
        Yandex();
    }
    ZoomControls();
}

// for duels (class ID change)

function canvasSwitch()
{
    let GOOGLE_MAPS_CANVAS = document.querySelector(".game-panorama_panoramaCanvas__patp9");
    if (nextPlayer === "Google") {
        document.getElementById("default_player").className = "game-panorama_panoramaCanvas__patp9";
        document.getElementById("PanoramaMap").className = "inactive";
        document.getElementById("roadview").className = "inactive";
        document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "hidden";
        document.getElementById("Main Button").google = true;
        document.getElementById("switch").nextPlayer = "Google";
        document.getElementById("switch").useGoogle = true;
        myLog("Google Duel Canvas loaded");
    }
    else if (nextPlayer === "Baidu")
    {
        document.getElementById("default_player").className = "inactive";
        document.getElementById("PanoramaMap").className = "game-panorama_panorama__3b2wI";
        document.getElementById("roadview").className = "inactive";
        document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "hidden";
        document.getElementById("Main Button").google = false;
        document.getElementById("switch").nextPlayer = "Baidu";
        document.getElementById("switch").useGoogle = false;
        myLog("Baidu Duel Canvas loaded");
    }
    else if (nextPlayer === "Kakao")
    {
        document.getElementById("default_player").className = "inactive";
        document.getElementById("PanoramaMap").className = "inactive";
        document.getElementById("roadview").className = "game-panorama_panorama__3b2wI";
        document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "hidden";
        document.getElementById("Main Button").google = false;
        document.getElementById("switch").nextPlayer = "Kakao";
        document.getElementById("switch").useGoogle = false;
        myLog("Kakao Duel Canvas loaded");
    }
    else if (nextPlayer === "Yandex")
    {
        document.getElementById("default_player").className = "inactive";
        document.getElementById("PanoramaMap").className = "inactive";
        document.getElementById("roadview").className = "inactive";
        document.querySelector(".ymaps-2-1-79-panorama-screen").style.visibility = "";
        document.getElementById("Main Button").google = false;
        document.getElementById("switch").nextPlayer = "Yandex";
        document.getElementById("switch").useGoogle = false;
        myLog("Yandex Duel Canvas loaded");
    }
}

// for Battle Royale and classic (change visibility)

function Google() {
    let GOOGLE_MAPS_CANVAS = ""
    if (isBattleRoyale) {
        GOOGLE_MAPS_CANVAS = document.querySelector(".br-game-layout__panorama-canvas");
    }
    else {
        GOOGLE_MAPS_CANVAS = document.querySelector(".game-layout__panorama-canvas");
    }
    if (nextPlayer === "Google") {
        GOOGLE_MAPS_CANVAS.style.visibility = "";
        document.getElementById("Main Button").google = true;
        document.getElementById("switch").nextPlayer = "Google";
        document.getElementById("switch").useGoogle = true;
        myLog("Google Canvas loaded");
    }
    else {
        GOOGLE_MAPS_CANVAS.style.visibility = "hidden";
        document.getElementById("Main Button").google = false;
        myLog("Google Canvas hidden");
    }

}

function Baidu() {
    let BAIDU_MAPS_CANVAS = document.getElementById("PanoramaMap");
    myLog("Baidu canvas");
    if (nextPlayer === "Baidu") {
        BAIDU_MAPS_CANVAS.style.visibility = "";
        document.getElementById("switch").nextPlayer = "Baidu";
        document.getElementById("switch").useGoogle = false;
        myLog("Baidu Canvas loaded");
    }
    else {
        BAIDU_MAPS_CANVAS.style.visibility = "hidden";
        myLog("Baidu Canvas hidden");
    }

}

function Kakao() {
    let KAKAO_MAPS_CANVAS = document.getElementById("roadview");
    myLog("Kakao canvas");
    if (nextPlayer === "Kakao") {
        KAKAO_MAPS_CANVAS.style.visibility = "";
        document.getElementById("switch").nextPlayer = "Kakao";
        document.getElementById("switch").useGoogle = false;
        myLog("Kakao Canvas loaded");
    }
    else {
        KAKAO_MAPS_CANVAS.style.visibility = "hidden";
        myLog("Kakao Canvas hidden");
    }

}

function Yandex() {
    let YANDEX_MAPS_CANVAS = document.querySelector(".ymaps-2-1-79-panorama-screen");
    if (YANDEX_MAPS_CANVAS != null)
    {
        // myLog("Yandex canvas");
        /*   myLog(YANDEX_MAPS_CANVAS); */
        if (nextPlayer === "Yandex") {
            YANDEX_MAPS_CANVAS.style.visibility = "";
            document.getElementById("switch").nextPlayer = "Yandex";
            document.getElementById("switch").useGoogle = false;
            myLog("Yandex Canvas loaded");
        }
        else {
            YANDEX_MAPS_CANVAS.style.visibility = "hidden";
            myLog("Yandex Canvas hidden");
        }
    }

}

/**
 * Adjust button placement
 */

function ZoomControls() {
    let style = `
	.ymaps-2-1-79-panorama-gotoymaps {display: none !important;}
	.game-layout__controls {bottom: 8rem !important; left: 1rem !important;}
	`;

    let style_element = document.createElement("style");
    style_element.innerHTML = style;
    document.body.appendChild(style_element);
}

/**
 * Updates the compass to match Yandex Panorama facing
 */
function updateCompass() {
    if (!COMPASS) {
        let compass = document.querySelector("img.compass__indicator");
        if (compass != null) {
            COMPASS = compass;
            let direction = YandexPlayer.getDirection()[0] * -1;
            COMPASS.setAttribute("style", `transform: rotate(${direction}deg);`);
        }
    }
    else {
        let direction = YandexPlayer.getDirection()[0] * -1;
        COMPASS.setAttribute("style", `transform: rotate(${direction}deg);`);
    }
}

/**
 * Open next location in streetview player given next player and next coordinate
 */

function goToLocation() {
    myLog("Going to location");
    if (nextPlayer === "Yandex") {
        let options = {};
        YandexPlayer.moveTo([global_lat, global_lng], options);
        YandexPlayer.setDirection([0, 16]);
        YandexPlayer.setSpan([10, 67]);
    }
    else if (nextPlayer === "Baidu") {
        let a = new BMap.Point(global_lng, global_lat);
        BaiduPlayer.setPov({ heading: -40, pitch: 6 });
        BaiduPlayer.setPosition(a);
    }
    else if (nextPlayer === "Kakao") {
        var roadviewClient = new kakao.maps.RoadviewClient();
        var position = new kakao.maps.LatLng(global_lat, global_lng);
        roadviewClient.getNearestPanoId(position, 500, function (panoId) {
            KakaoPlayer.setPanoId(panoId, position);
        });
    }
    document.getElementById("switch").lat = global_lat;
    document.getElementById("switch").lng = global_lng;
}

/**
 * Handle undo using the location history of the current round
 */

function goToUndoMove(data) {
    /*   myLog(global_lat);
      myLog(global_lng); */
    let options = {};
    let prevStep = null;
    if (locHistory.length === 1) {
        prevStep = locHistory[0];
    }
    else {
        prevStep = locHistory.pop();
    }
    // myLog(prevStep);
    // myLog(locHistory)
    if (nextPlayer === "Yandex") {
        defaultPanoIdChange = false;
        YandexPlayer.moveTo([prevStep[0], prevStep[1]], options);
        YandexPlayer.setDirection([prevStep[2], prevStep[3]]);
        YandexPlayer.setSpan([10, 67]);
        document.getElementById("switch").lat = prevStep[0];
        document.getElementById("switch").lng = prevStep[1];
    }
    else if (nextPlayer === "Kakao") {
        let btn = document.querySelector("button[data-qa='undo-move']");
        btn.disabled = false;
        btn.classList.remove('styles_disabled__W_k45');
        defaultPanoIdChange = false;
        let position = new kakao.maps.LatLng(prevStep[0], prevStep[1]);
        KakaoPlayer.setPanoId(prevStep[2], position);
        document.getElementById("switch").lat = prevStep[0];
        document.getElementById("switch").lng = prevStep[1];
        document.getElementById("switch").useGoogle = false;
        document.getElementById("Main Button").google = false;
        // myLog("Undo 1 step");
        // myLog(locHistory);
    }
    else if (nextPlayer === "Baidu") {
        // myLog(prevStep[1]);
        let position = new BMap.Point(prevStep[1], prevStep[0]);
        let pov = { heading: prevStep[2], pitch: prevStep[3] };
        BaiduPlayer.setPosition(position);
        BaiduPlayer.setPov(pov);
        document.getElementById("switch").lat = prevStep[1];
        document.getElementById("switch").lng = prevStep[0];
    }

}

function BYKTeleport()
{
    let teleportButtonBYK = document.getElementById("Main Button");
    if (teleportButtonBYK)
    {
        teleportButtonBYK.addEventListener("click", () => {
            if (!teleportButtonBYK.google)
            {
                // myLog("non-Google Teleport");
                let prevStep = null;
                if (locHistory.length === 1) {
                    prevStep = locHistory[0];
                }
                else {
                    prevStep = locHistory[locHistory.length - 1];
                }
                // myLog(prevStep);
                let options = {};
                let place, position, pID;
                if (nextPlayer === "Yandex") {
                    place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[2]), teleportButtonBYK.distance * 0.001);
                    YandexPlayer.setDirection([prevStep[2], prevStep[3]]);
                    YandexPlayer.moveTo([place.lat, place.lng], options);
                    YandexPlayer.setSpan([10, 67]);
                    //                     locHistory.push([place.lat, place.lng, prevStep[2], prevStep[3]]);
                }
                else if (nextPlayer === "Kakao") {
                    //                     place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[3]), teleportButtonBYK.distance * 0.001);
                    //                     position = new kakao.maps.LatLng(place.lat, place.lng);
                    //                     pID = KakaoPlayer.getViewpointWithPanoId();
                    //                     KakaoPlayer.setPanoId(pID.panoId, position);
                    //                     locHistory.push([place.lat, place.lng, pID.panoId, prevStep[3]]);
                    var roadviewClient = new kakao.maps.RoadviewClient();
                    place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[3]), teleportButtonBYK.distance * 0.001);
                    position = new kakao.maps.LatLng(place.lat, place.lng);
                    roadviewClient.getNearestPanoId(position, 500, function (panoId) {
                        KakaoPlayer.setPanoId(panoId, position);
                        // myLog("Teleport 1 step");
                        // myLog(locHistory);
                        //                         locHistory.push([place.lat, place.lng, panoId, prevStep[3]]);
                    });
                }
                else if (nextPlayer === "Baidu") {
                    place = FindPointAtDistanceFrom(prevStep[0], prevStep[1], DegreesToRadians(prevStep[2]), teleportButtonBYK.distance * 0.001);
                    position = new BMap.Point(place.lng, place.lat);
                    let pov = { heading: prevStep[2], pitch: prevStep[3] };
                    BaiduPlayer.setPosition(position);
                    BaiduPlayer.setPov(pov);
                    // locHistory.push([place.lat, place.lng, prevStep[2], prevStep[3]]);
                }
                document.getElementById("switch").lat = place.lat;
                document.getElementById("switch").lng = place.lng;
                if (teleportButtonBYK.distance > 150)
                {
                    teleportButtonBYK.distance = 100;
                    teleportButtonBYK.innerHTML = "Teleport " + teleportButtonBYK.distance + " m";
                }
            }
        });
    }
    else
    {
    }
}

function SyncListener()
{
    let googleKakaoButton = document.getElementById("switch");
    googleKakaoButton.addEventListener("click", () => {
        if (googleKakaoButton.useGoogle == false) {
            // googleKakaoButton.useGoogle = true;
            if (googleKakaoButton.nextPlayer === "Yandex") {
                let options = {};
                YandexPlayer.moveTo([googleKakaoButton.lat, googleKakaoButton.lng], options);
                YandexPlayer.setDirection([document.getElementById("switch").heading, 0]);

                // document.getElementById("switch").nextPlayer = "Yandex";
            }
            else if (googleKakaoButton.nextPlayer === "Kakao") {
                let roadviewClient = new kakao.maps.RoadviewClient();
                // myLog(googleKakaoButton.lat);
                let position = new kakao.maps.LatLng(googleKakaoButton.lat, googleKakaoButton.lng);
                roadviewClient.getNearestPanoId(position, 500, function (panoId) {
                    KakaoPlayer.setPanoId(panoId, position);
                });
                KakaoPlayer.setViewpoint({
                    pan: document.getElementById("switch").heading,
                    tilt: 0,
                    zoom: 0
                });
                // document.getElementById("switch").nextPlayer = "Kakao";
            }
        }
    });

}




/**
 * Gets the seed data for the current game
 *
 * @returns Promise with seed data as object
 */
function getSeed() {
    // myLog("getSeed called");
    return new Promise((resolve, reject) => {
        let token = getToken();
        let URL;
        let cred = ""

        const PATHNAME = window.location.pathname;

        if (PATHNAME.startsWith("/game/")) {
            URL = `https://www.geoguessr.com/api/v3/games/${token}`;
        }
        else if (PATHNAME.startsWith("/challenge/")) {
            URL = `https://www.geoguessr.com/api/v3/challenges/${token}/game`;
        }
        else if (PATHNAME.startsWith("/battle-royale/")) {
            URL = `https://game-server.geoguessr.com/api/battle-royale/${token}`;
        }
        else if (PATHNAME.startsWith("/duels/") || PATHNAME.startsWith("/team-duels/")) {
            URL = `https://game-server.geoguessr.com/api/duels/${token}`;
        }
        if (isBattleRoyale) {
            fetch(URL, {
                // Include credentials to GET from the endpoint
                credentials: 'include'
            })
                .then((response) => response.json())
                .then((data) => {
                resolve(data);
            })
                .catch((error) => {
                reject(error);
            });
        }
        else {
            fetch(URL)
                .then((response) => response.json())
                .then((data) => {
                resolve(data);
            })
                .catch((error) => {
                reject(error);
            });
        }
    });
}

/**
 * Gets the token from the current URL
 *
 * @returns token
 */
function getToken() {
    const PATHNAME = window.location.pathname;
    if (PATHNAME.startsWith("/game/")) {
        return PATHNAME.replace("/game/", "");
    }
    else if (PATHNAME.startsWith("/challenge/")) {
        return PATHNAME.replace("/challenge/", "");
    }
    else if (PATHNAME.startsWith("/battle-royale/")) {
        return PATHNAME.replace("/battle-royale/", "");
    }
    else if (PATHNAME.startsWith("/duels/")) {
        return PATHNAME.replace("/duels/", "");
    }
    else if (PATHNAME.startsWith("/team-duels/")) {
        return PATHNAME.replace("/team-duels/", "");
    }
}

/**
 * Gets the round number from the ongoing game from the page itself
 *
 * @returns Round number
 */
function getRoundFromPage() {
    const roundData = document.querySelector("div[data-qa='round-number']");
    if (roundData) {
        let roundElement = roundData.querySelector("div:last-child");
        if (roundElement) {
            let round = parseInt(roundElement.innerText.charAt(0));
            if (!isNaN(round) && round >= 1 && round <= 5) {
                return round;
            }
        }
    }
    else {
        return ROUND;
    }
}


/**
 * Injects Yandex Script
 */
function injectYandexScript() {
    return new Promise((resolve, reject) => {
        if (!YANDEX_INJECTED) {
            if (YANDEX_API_KEY === "") {
                myLog("No Yandex Key")
                reject();
            }
            else {
                const SCRIPT = document.createElement("script");
                SCRIPT.type = "text/javascript";
                SCRIPT.async = true;
                SCRIPT.onload = () => {
                    ymaps.ready(() => {
                        YANDEX_INJECTED = true;
                        myHighlight("Yandex API Loaded");
                        resolve();
                    });
                }
                SCRIPT.src = `https://api-maps.yandex.ru/2.1/?lang=en_US&apikey=${YANDEX_API_KEY}`;
                document.body.appendChild(SCRIPT);
            }
        }
        else {
            resolve();
        }
    });
}

/**
 * Injects Yandex Player and calls handleReturnToStart
 */
function injectYandexPlayer() {
    let lat = 41.321861;
    let lng = 69.212920;

    let options = {
        "direction": [0, 16],
        "span": [10, 67],
        "controls": ["zoomControl"]
    };
    ymaps.panorama.createPlayer("player", [lat, lng], options)
        .done((player) => {
        YandexPlayer = player;
        YandexPlayer.events.add("directionchange", (e) => {
            updateCompass();
            let pov = YandexPlayer.getDirection();
            if (locHistory.length > 0 && nextPlayer == "Yandex") {
                document.getElementById("switch").heading = pov[0];
                locHistory[locHistory.length - 1][2] = pov[0];
                locHistory[locHistory.length - 1][3] = pov[1];
            }
        });
        YandexPlayer.events.add("panoramachange", (e) => {
            if (defaultPanoIdChange) {
                let num = YandexPlayer.getPanorama().getPosition();
                let pov = YandexPlayer.getDirection();
                // myLog(num);
                // myLog(pov);
                if (nextPlayer == "Yandex")
                {
                    locHistory.push([num[0], num[1], pov[0], pov[1]]);
                }
                let btn = document.querySelector("button[data-qa='undo-move']");
                if (locHistory.length > 1) {
                    btn.disabled = false;
                    btn.classList.remove('styles_disabled__W_k45');
                }
                // myLog(locHistory);
            }
            defaultPanoIdChange = true;

        });
        myHighlight("Yandex Player injected");
    });

}


/**
 * Injects Baidu script
 */

function injectBaiduScript() {
    return new Promise((resolve, reject) => {
        if (!BAIDU_INJECTED) {
            if (BAIDU_API_KEY === "") {
                let canvas = document.getElementById("player");
                myLog("No Baidu Key")
            }
            else {
                const SCRIPT = document.createElement("script");
                SCRIPT.type = "text/javascript";
                SCRIPT.async = true;
                SCRIPT.src = `https://api.map.baidu.com/api?v=3.0&ak=${BAIDU_API_KEY}&callback=init`;
                document.body.appendChild(SCRIPT);

                let canvas = document.createElement("bmap");
                if (isBattleRoyale) {
                    if (isDuel)
                    {
                        canvas.innerHTML = `
                 <div id="PanoramaMap" class="inactive" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
            `;
                    }
                    else
                    {
                        canvas.innerHTML = `
                 <div id="PanoramaMap" class="br-game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
            `;
                    }
                }
                else {
                    canvas.innerHTML = `
                 <div id="PanoramaMap" class="game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
            `;
                }

                var div = document.getElementById("player");
                div.appendChild(canvas);

                SCRIPT.addEventListener('load', () => {
                    myHighlight("Baidu API Loaded");
                    // resolve(BMap);
                    let timeout = 0;
                    let interval = setInterval(() => {
                        if (timeout >= 40) {
                            reject();
                            clearInterval(interval);
                        }
                        if (typeof BMap.Panorama !== undefined) {
                            BAIDU_INJECTED = true;
                            resolve(BMap);
                            clearInterval(interval);
                        }
                        timeout += 1;
                    }, 500);
                })


            }
        }
        else {
            resolve();
        }
    });
}

/**
 * Injects Baidu Player and calls handleReturnToStart
 */
function injectBaiduPlayer() {
    injectBaiduScript().then(BMap => {
        BaiduPlayer = new BMap.Panorama('PanoramaMap');
        BaiduPlayer.setPov({ heading: -40, pitch: 6 });
        BaiduPlayer.setPosition(new BMap.Point(0, 0));
        if (!eventListenerAttached && !povListenerAttached) {
            myLog("position_listener attached");
            BaiduPlayer.addEventListener('position_changed', function (e) {
                eventListenerAttached = true;
                myLog('position_changed')
                let num = BaiduPlayer.getPosition();
                let pov = BaiduPlayer.getPov();
                if (nextPlayer == "Baidu" && num.lat != 0)
                {
                    locHistory.push([num.lat, num.lng, pov.heading, pov.pitch]);
                }
                if (!isBattleRoyale || isDuel)
                {
                    let btn = document.querySelector("button[data-qa='undo-move']");
                    if (locHistory.length > 1) {
                        btn.disabled = false;
                        btn.classList.remove('styles_disabled__W_k45');
                    }
                }
                // myLog(locHistory);
            })

            BaiduPlayer.addEventListener('pov_changed', function (e) {
                // myLog("pov_listener attached");
                povListenerAttached = true;
                // myLog('pov_changed')
                let pov = BaiduPlayer.getPov();
                if (locHistory.length > 0 && nextPlayer == "Baidu") {
                    locHistory[locHistory.length - 1][2] = pov.heading;
                    locHistory[locHistory.length - 1][3] = pov.pitch;
                }
                // myLog(locHistory);
            })
        }
    });
}

/**
 * Injects Kakao script
 */

function injectKakaoScript() {
    return new Promise((resolve, reject) => {
        if (!KAKAO_INJECTED) {
            if (KAKAO_API_KEY === "") {
                myLog("No Kakao Key")
            }
            else {

                let canvas = document.createElement("kmap");
                if (isBattleRoyale) {
                    if (isDuel)
                    {
                        canvas.innerHTML = `
                 <div id="roadview" class="inactive" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
            `;
                    }
                    else
                    {
                        canvas.innerHTML = `
                 <div id="roadview" class="br-game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
            `;
                    }
                }
                else {
                    canvas.innerHTML = `
                 <div id="roadview" class="game-layout__panorama" style="zIndex: 99999,position: "absolute", top: 0, left: 0, width: '100%', height: '100%',"> </div>
            `;
                }

                var div = document.getElementById("player");
                div.appendChild(canvas);

                const SCRIPT = document.createElement("script");
                SCRIPT.async = true;
                // SCRIPT.type = "text/javascript";
                SCRIPT.src = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${KAKAO_API_KEY}&autoload=false`;
                document.body.appendChild(SCRIPT);
                SCRIPT.onload = () => {
                    kakao.maps.load(function () {
                        var position = new kakao.maps.LatLng(33.450701, 126.560667);
                        let roadviewContainer = document.getElementById('roadview');
                        KakaoPlayer = new kakao.maps.Roadview(roadviewContainer);
                        var panoId = 1023434522;
                        KakaoPlayer.setPanoId(panoId, position);
                        KAKAO_INJECTED = true;
                        kakao.maps.event.addListener(KakaoPlayer, 'panoid_changed', function() {
                            if (defaultPanoIdChange) {
                                let latlng = KakaoPlayer.getPosition();
                                let lat = latlng.getLat();
                                let lng = latlng.getLng();
                                let pID = KakaoPlayer.getViewpointWithPanoId();
                                if (nextPlayer == "Kakao" && lat != 33.45047613915499)
                                {
                                    // myLog("push");
                                    locHistory.push([lat, lng, pID.panoId, pID.pan]);
                                    document.getElementById("switch").heading = pID.pan;
                                }
                                let btn = document.querySelector("button[data-qa='undo-move']");
                                if (locHistory.length > 1 && (btn != null)) {
                                    btn.disabled = false;
                                    btn.classList.remove('styles_disabled__W_k45');
                                }
                                // myLog(locHistory);
                            }
                            defaultPanoIdChange = true;
                        });
                        kakao.maps.event.addListener(KakaoPlayer, 'viewpoint_changed', function() {
                            // myLog("pov_listener attached");
                            let pID = KakaoPlayer.getViewpointWithPanoId();
                            if (locHistory.length > 0 && nextPlayer == "Kakao") {
                                document.getElementById("switch").heading = pID.pan;
                                locHistory[locHistory.length - 1][3] = pID.pan;
                            }
                            // myLog(locHistory);
                        })
                        resolve();
                    });
                };

            }
        }
        else {
            resolve();
        }
    });
}