GeoGuessr Custom Maps

using modified maps in geoguessr games

目前為 2024-09-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         GeoGuessr Custom Maps
// @namespace    https://greasyfork.org/users/1179204
// @description  using modified maps in geoguessr games
// @version      1.0.8
// @author       KaKa
// @license      BSD
// @match        *://www.geoguessr.com/*
// @require      https://update.greasyfork.org/scripts/502813/1423193/Geoguessr%20Tag.js
// @icon         https://www.svgrepo.com/show/392367/interaction-interface-layer-layers-location-map.svg
// ==/UserScript==

(function() {

    /*=========================================================================Modifiy your guess map here==================================================================================*/

    let customOptions={

        Language:'en',                                  //en,zh,ja,fr,de,es

        Google_StreetView_Layer_Lines_Style:'Default',   // More styles see below

        Google_StreetView_Layer_Shortcut:'V',

        Google_Labels_Layer_Shortcut:'G',

        Google_Terrain_Layer_Shortcut:'T',

        Google_Satellite_Layer_Shortcut:'B',

        Apple_StreetView_Layer_Shortcut:'P',

        Yandex_StreetView_Layer_Shortcut:'Y',

        OpenWeather_Shortcut:'Q',

        OpenWeather_Style:'radar',                      //'radar': Global Precipitation;  'CL':Cloud;  'APM':Pressure;  'TA2'Temperature;  'WS10':Wind Speed;

        OpenWeather_Date:'now',                        // foramt:yyyy-mm-dd, less than one week ago

        Bing_Maps_Style:'r',                           // 'a':satellite(without labels);  'h':hybrid;  'r':roadmap,'sre':terrain

        Map_Tiler_Style:'basic',                       //basic,satellite,bright,landscape,ocean,outdoor,topo,streets,dataviz

        Carto_Style:'light_all',                       //light_all,dark_all

        Thunderforest_Style:'spinal-map'}              //spinal-map,landscape,outdoors,atlas,transport,

    let tileServices=["Google_Maps","OpenStreetMap","Bing_Maps","Map_Tiler","Thunderforest","Carto","Yandex_Maps","Petal_Maps"]

    let colorOptions={

        Default:['1098ad','99e9f2'],

        Crimson:['f03e3e','ffc9c9'],

        Deep_Pink:['d6336c','fcc2d7'],

        Blue_Violet:['ae3ec9','eebefa'],

        Slate_Blue:['7048e8','d0bfff'],

        Royal_Blue:['4263eb','bac8ff'],

        Dodger_Blue: ['1c7ed6','a5d8ff'],

        Sea_Green:['0ca678','96f2d7'],

        Lime_Green:['37b24d','b2f2bb'],

        OliveDrab:['74b816','d8f5a2'],

        Orange:['f59f00','ffec99'],

        Dark_Orange:['f76707','ffd8a8'],

        Brown:['bd5f1b','f7ca9e'],
    }

    /*======================================================================================================================================================================================*/


    let currentMapType='roadmap',currentLayers=[],isGoogleDisplay=true,isSV,opacityControl

    const openWeatherBaseURL = "https://g.sat.owm.io/vane/2.0/weather";
    const radarURL = `https://b.sat.owm.io/maps/2.0/radar/{z}/{x}/{y}?appid=9de243494c0b295cca9337e1e96b00e2&day=${getNow(customOptions.OpenWeather_Date)}`;

    const openWeatherURL = (customOptions.OpenWeather_Style === 'radar')
    ? radarURL
    : `${openWeatherBaseURL}/${customOptions.OpenWeather_Style}/{z}/{x}/{y}?appid=9de243494c0b295cca9337e1e96b00e2&&date=${getTimestamp(customOptions.OpenWeather_Date)}&fill_bound=true`;

    let tileUrls = {
        Petal_Maps: `https://maprastertile-dra.dbankcdn.com/display-service/v1/online-render/getTile/24.07.06.10/{z}/{x}/{y}/?language=${customOptions.Language}&p=46&scale=1&mapType=ROADMAP&presetStyleId=standard&key=CgB6e3x91JxUZ4Ow3JZYVG6r9c9U7rH4ameNQdauHVaVBYGWwy8ueadAtqjs6Yl2z3OwymAEx3JR83vpgPzv4nuC`,
        OpenStreetMap: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
        Map_Tiler:`https://api.maptiler.com/maps/${customOptions.Map_Tiler_Style}-v2/256/{z}/{x}/{y}.png?key=0epLOAjD7fw17tghcyee`,
        Thunderforest:`https://b.tile.thunderforest.com/${customOptions.Thunderforest_Style}/{z}/{x}/{y}@2x.png?apikey=6a53e8b25d114a5e9216df5bf9b5e9c8`,
        Carto:`https://cartodb-basemaps-3.global.ssl.fastly.net/${customOptions.Carto_Style}/{z}/{x}/{y}.png`,
        Google_StreetView:`https://maps.googleapis.com/maps/vt?pb=%211m5%211m4%211i{z}%212i{x}%213i{y}%214i256%212m8%211e2%212ssvv%214m2%211scc%212s*211m3*211e2*212b1*213e2*212b1*214b1%214m2%211ssvl%212s*212b1%213m17%212sen%213sUS%215e18%2112m4%211e68%212m2%211sset%212sRoadmap%2112m3%211e37%212m1%211ssmartmaps%2112m4%211e26%212m2%211sstyles%212ss.e%3Ag.f%7Cp.c%3A%23${colorOptions[customOptions.Google_StreetView_Layer_Lines_Style][0]}%7Cp.w%3A1%2Cs.e%3Ag.s%7Cp.c%3A%23${colorOptions[customOptions.Google_StreetView_Layer_Lines_Style][1]}%7Cp.w%3A3%215m1%215f1.35`,
        Google_Labels:`https://maps.googleapis.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m1!2sm!3m17!2s${customOptions.Language}!3sUS!5e18!12m4!1e68!2m2!1sset!2sRoadmap!12m3!1e37!2m1!1ssmartmaps!12m4!1e26!2m2!1sstyles!2ss.e:g|p.v:off,s.t:1|s.e:g.s|p.v:off,s.e:l|p.v:on!5m1!5f2`,
        Apple_StreetView:`https://lookmap.eu.pythonanywhere.com/bluelines_raster_2x/{z}/{x}/{y}.png`,
        Yandex_StreetView:`https://core-stv-renderer.maps.yandex.net/2.x/tiles?l=stv&x={x}&y={y}&z={z}&scale=1&v=2024.09.06.19.22-1_24.09.08-0-21241`,
        Yandex_Maps:`https://core-renderer-tiles.maps.yandex.net/tiles?l=map&v=24.09.06-3-b240906182700&x={x}&y={y}&z={z}&scale=1`,
        OpenWeather: openWeatherURL,
    }

    let map,google,gsvLayer,initLayer=tag

    const intervalId = setInterval(() => {
        getMap();
        if (map) {
            clearInterval(intervalId)
            initCustomizer()}
    }, 500);


    function createOpacityControl(controlDiv, layer) {
        controlDiv.style.margin='20px'
        controlDiv.style.backgroundColor = '#fff';
        controlDiv.style.height = '30px';
        controlDiv.style.boxShadow = 'rgba(0, 0, 0, 0.3) 0px 1px 4px -1px';
        controlDiv.style.borderRadius = '5px';

        var opacitySlider = document.createElement('input');

        opacitySlider.setAttribute('type', 'range');
        opacitySlider.setAttribute('min', '0');
        opacitySlider.setAttribute('max', '100');
        opacitySlider.setAttribute('value', '100');
        opacitySlider.setAttribute('step', '1');
        opacitySlider.style.width = '90px';
        opacitySlider.style.height='20px'
        opacitySlider.style.marginTop='5px'
        opacitySlider.addEventListener('input', function() {
            var opacity = opacitySlider.value / 100
            layer.setOpacity(opacity);

        });

        controlDiv.appendChild(opacitySlider);
    }

    function addOpacityControl(m, layer) {
        var opacityControlDiv = document.createElement('div');
        new createOpacityControl(opacityControlDiv, layer);
        opacityControlDiv.id=layer.name
        opacityControlDiv.index = 1;
        m.controls[google.maps.ControlPosition.TOP_RIGHT].push(opacityControlDiv);
    }

    function removeOpacityControl(id) {
        var controls = map.controls[google.maps.ControlPosition.TOP_RIGHT];
        if(controls&&controls.getLength()>0){
            if(!id) controls.removeAt(0)
            else{
                for (var i = 0; i < controls.getLength(); i++) {
                    var control = controls.getAt(i);
                    if (control.id === id) {
                        controls.removeAt(i);
                        break;
                    }
                }
            }
        }
    }

    function getNow(date) {
        if(date!='now'){
            return date
        }
        const now = new Date();
        now.setHours(now.getHours() - 1);
        return now.toISOString().slice(0, 14)+'00';
    }

    function getTimestamp(date){
        var parsedDate
        if (date=== 'now') {
            parsedDate= new Date()
            return Math.floor(parsedDate.getTime() / 1000)
        }
        parsedDate = new Date(date);

        if (isNaN(parsedDate.getTime())) {
            throw new Error('Invalid date format');
        }
        return Math.floor(parsedDate.getTime() / 1000);

    }

    function extractTileCoordinates(url) {
        const regex = /!1i(\d+)!2i(\d+)!3i(\d+)!4i(\d+)/;
        const matches = url.match(regex);

        if (matches && matches.length === 5) {
            const z = matches[1];
            const x = matches[2];
            const y = matches[3];
            return { z, x, y };
        } else {
            return null;
        }
    }
    function getBingTiles(tileX, tileY, zoom,type) {
        var quadKey = tileXYToQuadKey(tileX, tileY, zoom);
        var baseUrl = 'https://ecn.t0.tiles.virtualearth.net/tiles/';

        return baseUrl + type + quadKey + '.jpeg?g=14519';
    }
    function tileXYToQuadKey(tileX, tileY, zoom) {
        var quadKey = '';
        for (var i = zoom; i > 0; i--) {
            var digit = 0;
            var mask = 1 << (i - 1);
            if ((tileX & mask) !== 0) {
                digit += 1;
            }
            if ((tileY & mask) !== 0) {
                digit += 2;
            }
            quadKey += digit.toString();
        }
        return quadKey;
    }


    function setMapLayer(layerName) {
        var tileLayerUrl = tileUrls[layerName];
        var tileLayer
        if (layerName==='Bing_Maps') {
            tileLayer = new google.maps.ImageMapType({
                getTileUrl: function(coord, zoom) {
                    return getBingTiles(coord.x,coord.y,zoom,customOptions.Bing_Maps_Style)
                        .replace('{z}', zoom)
                        .replace('{x}', coord.x)
                        .replace('{y}', coord.y);
                },
                tileSize: new google.maps.Size(256, 256),
                name: layerName,

            });
        }
        else if (tileServices.includes(layerName)){
            tileLayer = new google.maps.ImageMapType({
                getTileUrl: function(coord, zoom) {
                    return tileLayerUrl
                        .replace('{z}', zoom)
                        .replace('{x}', coord.x)
                        .replace('{y}', coord.y);
                },
                tileSize: new google.maps.Size(256, 256),
                name: layerName,
                maxZoom:20
            });
            map.mapTypes.set(layerName, tileLayer);
            map.setMapTypeId(layerName);
        }
        else{
            tileLayer = new google.maps.ImageMapType({
                getTileUrl: function(coord, zoom) {
                    return tileLayerUrl
                        .replace('{z}', zoom)
                        .replace('{x}', coord.x)
                        .replace('{y}', coord.y);
                },
                tileSize: new google.maps.Size(256, 256),
                name: layerName,

            });
        }

        if(!layerName.includes('Google')&&layerName!='Apple_StreetView'&&layerName!='Yandex_StreetView'){
            isGoogleDisplay=false
        }
        if(currentLayers.includes(layerName)){
            removeMapLayer(layerName)
            const index = currentLayers.indexOf(layerName);
            if (index !== -1) {
                currentLayers.splice(index, 1);
            }
            if(!layerName.includes('Google')&&!layerName.includes('Weather')&&!layerName.includes('StreetView')){
                setMapType('roadmap')
                map.overlayMapTypes.clear();
                currentLayers=[]
                isGoogleDisplay=true
            }
        }
        else {
            if (!tileServices.includes(layerName)||layerName==='Bing_Maps')map.overlayMapTypes.push(tileLayer)
            currentLayers.push(layerName)};

        if(layerName.includes('StreetView')){
            if(currentLayers.includes(layerName)){
                addOpacityControl(map,tileLayer)
            }
            else removeOpacityControl(layerName)
        }
    }


    function removeMapLayer(layerName) {
        for (let i = 0; i < map.overlayMapTypes.getLength(); i++) {
            const currentLayer = map.overlayMapTypes.getAt(i);
            if (currentLayer && currentLayer.name === layerName) {
                map.overlayMapTypes.removeAt(i);
                break;
            }
        }
    }

    function getMap(){
        let element = document.getElementsByClassName("guess-map_canvas__cvpqv")[0]
        //if (!element) element=document.getElementsByClassName("coordinate-result-map_map__Yh2Il")[0]
        const keys = Object.keys(element)
        const key = keys.find(key => key.startsWith("__reactFiber$"))
        const props = element[key]
        map=props.return.return.memoizedProps.map
        google=unsafeWindow.google
    }

    function setMapType(customType){
        if (currentMapType!=customType){
            currentMapType=customType
        }
        else{
            currentMapType='roadmap'
        }
        map.setMapTypeId(currentMapType);
    }


    function initCustomizer(){
        let onKeyDown = (e) => {
            if (e.key >= '1' && e.key <= '7') {
                initLayer(`layer:${tileServices[tileIndex]}`)
                if(!map) getMap()
                const tileIndex=parseInt(e.key)
                map.overlayMapTypes.clear();
                removeOpacityControl()
                setMapLayer(tileServices[tileIndex])
                const index = currentLayers.indexOf("Google_Labels");
                if (index !== -1) {
                    currentLayers.splice(index, 1);
                }
            }
            else if (e.key === '0') {
                e.stopImmediatePropagation();
                if(!map) getMap()
                initLayer('layer:Google_Labels')
                map.overlayMapTypes.clear();
                currentLayers=[]
                isGoogleDisplay=true
                removeOpacityControl()
                map.set('styles', [
                    {
                        featureType: 'all',
                        elementType: 'labels',
                        stylers: [{ visibility: 'on' }]
                    }
                ])
                isSV=false
            }
            else if (e.key === customOptions.Google_StreetView_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_StreetView_Layer_Shortcut) {
                e.stopImmediatePropagation();
                if(!map) getMap()
                initLayer('layer:Google_StreetView')
                if(!isSV){
                    map.set('styles', [
                        {
                            featureType: 'all',
                            elementType: 'labels',
                            stylers: [{ visibility: 'off' }]
                        }
                    ])
                    isSV=true}
                else{
                    map.set('styles', [
                        {
                            featureType: 'all',
                            elementType: 'labels',
                            stylers: [{ visibility: 'on' }]
                        }
                    ])
                    isSV=false
                }
                setMapLayer('Google_StreetView')
                if (isGoogleDisplay)setMapLayer('Google_Labels')
            }
            else if (e.key === customOptions.Apple_StreetView_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Apple_StreetView_Layer_Shortcut) {
                e.stopImmediatePropagation();
                initLayer('layer:Apple_StreetView')
                if(!map) getMap()
                if(!isSV){
                    map.set('styles', [
                        {
                            featureType: 'all',
                            elementType: 'labels',
                            stylers: [{ visibility: 'off' }]
                        }
                    ])
                    isSV=true}
                else{
                    map.set('styles', [
                        {
                            featureType: 'all',
                            elementType: 'labels',
                            stylers: [{ visibility: 'on' }]
                        }
                    ])
                    isSV=false
                }
                setMapLayer('Apple_StreetView')
                if (isGoogleDisplay)setMapLayer('Google_Labels')
            }

            else if (e.key === customOptions.Yandex_StreetView_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Yandex_StreetView_Layer_Shortcut) {
                e.stopImmediatePropagation();
                initLayer('layer:Yandex_StreetView')
                if(!map) getMap()
                if(!isSV){
                    map.set('styles', [
                        {
                            featureType: 'all',
                            elementType: 'labels',
                            stylers: [{ visibility: 'off' }]
                        }
                    ])
                    isSV=true}
                else{
                    map.set('styles', [
                        {
                            featureType: 'all',
                            elementType: 'labels',
                            stylers: [{ visibility: 'on' }]
                        }
                    ])
                    isSV=false
                }
                setMapLayer('Yandex_StreetView')
                if (isGoogleDisplay)setMapLayer('Google_Labels')
            }
            else if (e.key === customOptions.Google_Labels_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_Labels_Layer_Shortcut) {
                e.stopImmediatePropagation();
                if(!map) getMap()
                initLayer('layer:Google_Labels')
                setMapLayer('Google_Labels')
            }
            else if (e.key === customOptions.Google_Terrain_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_Terrain_Layer_Shortcut) {
                e.stopImmediatePropagation();
                if(!map) getMap()
                initLayer('layer:terrain')
                setMapType('terrain')
            }
            else if (e.key === customOptions.Google_Satellite_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_Satellite_Layer_Shortcut) {
                e.stopImmediatePropagation();
                if(!map) getMap()
                initLayer('layer:satellite')
                setMapType('satellite')
            }
            else if (e.key === customOptions.OpenWeather_Shortcut.toLowerCase()|| e.key === customOptions.OpenWeather_Shortcut) {
                e.stopImmediatePropagation();
                if(!map) getMap()
                initLayer('layer:weather')
                setMapLayer('OpenWeather')
            }
        }

        document.addEventListener("keydown", onKeyDown);
    }

})();