Greasy Fork

Greasy Fork is available in English.

RoLocate

Adds filter options to roblox server page. Alternative to paid extensions like RoPro, RoGold (Ultimate), RoQol, and RoKit.

当前为 2025-02-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         RoLocate
// @namespace    https://oqarshi.github.io/
// @version      27.2
// @description  Adds filter options to roblox server page. Alternative to paid extensions like RoPro, RoGold (Ultimate), RoQol, and RoKit.
// @author       Oqarshi
// @match        https://www.roblox.com/games/*
// @license      CC-BY-4.0; https://creativecommons.org/licenses/by/4.0/
// @icon         data:image/jpeg;base64,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
// @grant        GM_xmlhttpRequest
// ==/UserScript==



(function() {
    'use strict';

    /*********************************************************************************************************************************************************************************************************************************************
                                                             This is all of the functions for the filter button and the popup for the 8 buttons does not include the functions for the 8 buttons

    *********************************************************************************************************************************************************************************************************************************************/

    function createPopup() {
        const popup = document.createElement('div');
        popup.className = 'server-filters-dropdown-box'; // Unique class name
        popup.style.cssText = `
        position: absolute;
        width: 210px;
        height: 420px;
        right: 0px;
        top: 30px;
        z-index: 1000;
        border-radius: 5px;
        background-color: rgb(30, 32, 34);
        display: flex;
        flex-direction: column;
        padding: 5px;
    `;

        // Create the header section
        const header = document.createElement('div');
        header.style.cssText = `
        display: flex;
        align-items: center;
        padding: 10px;
        border-bottom: 1px solid #444;
        margin-bottom: 5px;
    `;

        // Add the logo (base64 image)
        const logo = document.createElement('img');
        logo.src = 'data:image/jpeg;base64,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'; // Replace with your base64 logo
        logo.style.cssText = `
        width: 24px;
        height: 24px;
        margin-right: 10px;
    `;

        // Add the title
        const title = document.createElement('span');
        title.textContent = 'RoLocate';
        title.style.cssText = `
        color: white;
        font-size: 18px;
        font-weight: bold;
    `;

        // Append logo and title to the header
        header.appendChild(logo);
        header.appendChild(title);

        // Append the header to the popup
        popup.appendChild(header);

        // Define unique names, tooltips, experimental status, and explanations for each button
        const buttonData = [{
                name: "Smallest Servers",
                tooltip: "**Reverses the order of the server list.** The emptiest servers will be displayed first.",
                experimental: false
            },
            {
                name: "Available Space",
                tooltip: "**Filters out servers which are full.** Servers with space will only be shown.",
                experimental: false
            },
            {
                name: "Player Count",
                tooltip: "**Roblox Locator finds servers with your specified player count or fewer.** Searching for up to 3 minutes. If no exact match is found, it shows servers closest to the target.",
                experimental: false
            },
            {
                name: "Random Shuffle",
                tooltip: "**Display servers in a completely random order.** Shows servers with space and servers with low player counts in a randomized order.",
                experimental: false
            },
            {
                name: "Server Region",
                tooltip: "**Filters servers by region.** Offering more accuracy than 'Best Connection' in areas with fewer Roblox servers, like India, or in games with high player counts.",
                experimental: true,
                experimentalExplanation: "**Experimental**: Still in development and testing. Ping may be inaccurate sometimes because of the Roblox API."
            },
            {
                name: "Best Connection",
                tooltip: "**Automatically joins the fastest servers for you.** However, it may be less accurate in regions with fewer Roblox servers, like India, or in games with large player counts.",
                experimental: true,
                experimentalExplanation: "**Experimental**: Still in development and testing.  it may be less accurate in regions with fewer Roblox servers"
            },
            {
                name: "Join Small Server",
                tooltip: "**Automatically tries to join a server with a very low population.** On popular games servers may fill up very fast so you might not always get in alone.",
                experimental: false
            },
            {
                name: "Locate Player",
                tooltip: "**Finds and joins the server a user is playing on if they are playing this particular game.** Note: May take a while for very popular games.",
                experimental: true,
                experimentalExplanation: "**Experimental**: Still in development and testing. It may not be accurate with popular avatars, such as the default Roblox avatars."
            },
            {
                name: "About",
                tooltip: "**The Credits.** Rolocate was created by Oqarshi. Special thanks to BTRoblox ❤️. Enjoy using Rolocate!",
                experimental: false
            }
        ];

        // Create buttons with unique names, tooltips, experimental status, and explanations
        buttonData.forEach((data, index) => {
            const buttonContainer = document.createElement('div');
            buttonContainer.className = 'server-filter-option';
            buttonContainer.style.cssText = `
            width: 190px;
            height: 30px;
            background-color: #393B3D;
            margin: 5px;
            border-radius: 5px;
            padding: 3.5px;
            position: relative;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.3s ease;
        `;

            const tooltip = document.createElement('div');
            tooltip.className = 'filter-tooltip';
            tooltip.style.cssText = `
            display: none;
            position: absolute;
            top: -10px;
            left: 200px;
            width: auto;
            inline-size: 200px;
            height: auto;
            background-color: #191B1D;
            color: white;
            padding: 5px;
            border-radius: 5px;
            white-space: pre-wrap;
            font-size: 14px;
        `;

            // Parse tooltip text and replace **...** with bold HTML tags
            tooltip.innerHTML = data.tooltip.replace(/\*\*(.*?)\*\*/g, "<b style='color: #068f00;'>$1</b>");

            const buttonText = document.createElement('p');
            buttonText.style.cssText = `
            margin: 0;
            color: white;
            font-size: 16px;
        `;
            buttonText.textContent = data.name;

            // Add "EXP" label if the button is experimental
            if (data.experimental) {
                const expLabel = document.createElement('span');
                expLabel.textContent = 'EXP';
                expLabel.style.cssText = `
                margin-left: 8px;
                color: gold;
                font-size: 12px;
                font-weight: bold;
                background-color: rgba(255, 215, 0, 0.1);
                padding: 2px 6px;
                border-radius: 3px;
            `;
                buttonText.appendChild(expLabel);
            }

            // Add experimental explanation tooltip (left side)
            let experimentalTooltip = null;
            if (data.experimental) {
                experimentalTooltip = document.createElement('div');
                experimentalTooltip.className = 'experimental-tooltip';
                experimentalTooltip.style.cssText = `
        display: none;
        position: absolute;
        top: 0;
        right: 200px;
        width: 200px;
        background-color: #191B1D;
        color: white;
        padding: 5px;
        border-radius: 5px;
        font-size: 14px;
        white-space: pre-wrap;
        z-index: 1001;
    `;

                // Function to replace **text** with bold and gold styled text
                const formatText = (text) => {
                    return text.replace(/\*\*(.*?)\*\*/g, '<span style="font-weight: bold; color: gold;">$1</span>');
                };

                // Apply the formatting to the experimental explanation
                experimentalTooltip.innerHTML = formatText(data.experimentalExplanation);

                buttonContainer.appendChild(experimentalTooltip);
            }
            buttonContainer.appendChild(tooltip);
            buttonContainer.appendChild(buttonText);

            buttonContainer.addEventListener('mouseover', () => {
                tooltip.style.display = 'block';
                if (data.experimental) {
                    experimentalTooltip.style.display = 'block';
                }
                buttonContainer.style.backgroundColor = '#4A4C4E'; // Hover effect
            });
            buttonContainer.addEventListener('mouseout', () => {
                tooltip.style.display = 'none';
                if (data.experimental) {
                    experimentalTooltip.style.display = 'none';
                }
                buttonContainer.style.backgroundColor = '#393B3D'; // Revert to original color
            });

            buttonContainer.addEventListener('click', () => {
                switch (index) {
                    case 0:
                        smallest_servers();
                        break;
                    case 1:
                        available_space_servers();
                        break;
                    case 2:
                        player_count_tab();
                        break;
                    case 3:
                        random_servers();
                        break;
                    case 4:
                        createServerCountPopup((totalLimit) => {
                            rebuildServerList(gameId, totalLimit);
                        });
                        break;
                    case 5:
                        rebuildServerList(gameId, 50, true);
                        break;
                    case 6:
                        auto_join_small_server();
                        break;
                    case 7:
                        find_user_server_tab();
                        break;
                    case 8:
                        credits();
                        break;
                }
            });

            popup.appendChild(buttonContainer);
        });

        return popup;
    }


// Main function to handle the server hopping
function ServerHop() {
    console.log("Starting server hop...");
    showLoadingOverlay();

    // Extract the game ID from the URL
    const url = window.location.href;
    const gameId = url.split("/")[4]; // Extracts the game ID, assuming URL is in the format: /games/{gameId}/Title

    console.log(`Game ID: ${gameId}`);

    // Array to store server IDs
    let serverIds = [];
    let nextPageCursor = null;
    let pagesRequested = 0;

    // Get the list of all recently joined servers in localStorage
    const allStoredServers = Object.keys(localStorage)
        .filter(key => key.startsWith("recentServers_"))
        .map(key => JSON.parse(localStorage.getItem(key)));

    // Remove any expired servers for all games (older than 15 minutes)
    const currentTime = new Date().getTime();
    allStoredServers.forEach(storedServers => {
        const validServers = storedServers.filter(server => {
            const lastJoinedTime = new Date(server.timestamp).getTime();
            return (currentTime - lastJoinedTime) <= 15 * 60 * 1000; // 15 minutes
        });

        // Update localStorage with the valid (non-expired) servers
        localStorage.setItem(`recentServers_${gameId}`, JSON.stringify(validServers));
    });

    // Get the list of recently joined servers for the current game
    const storedServers = JSON.parse(localStorage.getItem(`recentServers_${gameId}`)) || [];

    // Check if there are any recently joined servers and exclude them from selection
    const validServers = storedServers.filter(server => {
        const lastJoinedTime = new Date(server.timestamp).getTime();
        return (currentTime - lastJoinedTime) <= 15 * 60 * 1000; // 15 minutes
    });

    if (validServers.length > 0) {
        console.log(`Excluding servers joined in the last 15 minutes: ${validServers.map(s => s.serverId).join(', ')}`);
    } else {
        console.log("No recently joined servers within the last 15 minutes. Proceeding to pick a new server.");
    }

    // Function to fetch servers
    function fetchServers(cursor) {
        const url = `https://games.roblox.com/v1/games/${gameId}/servers/0?sortOrder=2&excludeFullGames=true&limit=100${cursor ? `&cursor=${cursor}` : ""}`;

        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(response) {
                console.log("API Response:", response.responseText);

                try {
                    const data = JSON.parse(response.responseText);

                    // If there's an error, log it and return without processing
                    if (data.errors) {
                        console.warn("Skipping unreadable response:", data.errors[0].message);
                        return;
                    }

                    // After a successful request, wait 0.15 seconds before proceeding
                    setTimeout(() => {
                        if (!data || !data.data) {
                            console.error("Invalid response structure: 'data' is missing or undefined", data);
                            return;
                        }

                        data.data.forEach(server => {
                            if (validServers.some(vs => vs.serverId === server.id)) {
                                console.log(`Skipping previously joined server ${server.id}.`);
                            } else {
                                serverIds.push(server.id);
                            }
                        });

                        // Fetch next page if available and within limit
                        if (data.nextPageCursor && pagesRequested < 4) {
                            pagesRequested++;
                            console.log(`Fetching page ${pagesRequested}...`);
                            fetchServers(data.nextPageCursor);
                        } else {
                            pickRandomServer();
                        }
                    }, 150);

                } catch (error) {
                    console.error("Error parsing response:", error);
                }
            },
            onerror: function(error) {
                console.error("Error fetching server data:", error);
            }
        });
    }

    // Function to pick a random server and join it
    function pickRandomServer() {
        if (serverIds.length > 0) {
            const randomServerId = serverIds[Math.floor(Math.random() * serverIds.length)];
            console.log(`Joining server: ${randomServerId}`);

            // Join the game instance with the selected server ID
            Roblox.GameLauncher.joinGameInstance(gameId, randomServerId);

            // Store the selected server ID with the time and date in localStorage
            const timestamp = new Date().toISOString();
            const newServer = {
                serverId: randomServerId,
                timestamp
            };
            validServers.push(newServer);

            // Save the updated list of recently joined servers to localStorage
            localStorage.setItem(`recentServers_${gameId}`, JSON.stringify(validServers));

            console.log(`Server ${randomServerId} stored with timestamp ${timestamp}`);
        } else {
            console.log("No servers found to join.");
            notifications("You have joined all the servers recently. No servers found to join.", "error", "⚠️");
        }
    }

    // Start the fetching process
    fetchServers();
}


    /*******************************************************
    name of function: An Observer for the filter button
    description: to put the filter button on the page
    *******************************************************/

// Wait for the server list options container or the play button to load
const observer = new MutationObserver((mutations, obs) => {
    const serverListOptions = document.querySelector('.server-list-options');
    const playButton = document.querySelector('.btn-common-play-game-lg.btn-primary-md');

    if (serverListOptions && !document.querySelector('.RL-filter-button')) {
        // Create the filter button
        const filterButton = document.createElement('a');
        filterButton.className = 'RL-filter-button'; // Unique class name
        filterButton.style.cssText = `
            color: white;
            font-weight: bold;
            text-decoration: none;
            cursor: pointer;
            margin-left: 10px;
            padding: 5px 10px;
            display: flex;
            align-items: center;
            gap: 5px;
            position: relative;
            margin-top: 4px;
        `;
        filterButton.addEventListener('mouseover', () => {
            filterButton.style.textDecoration = 'underline';
        });
        filterButton.addEventListener('mouseout', () => {
            filterButton.style.textDecoration = 'none';
        });

        // Add the "Filter" text
        const buttonText = document.createElement('span');
        buttonText.className = 'RL-filter-text';
        buttonText.textContent = 'Filters';
        filterButton.appendChild(buttonText);

        // Add the icon (three horizontal dashes)
        const icon = document.createElement('span');
        icon.className = 'RL-filter-icon';
        icon.textContent = '≡';
        icon.style.cssText = `font-size: 18px;`;
        filterButton.appendChild(icon);

        // Append the button to the server list options container
        serverListOptions.appendChild(filterButton);

        // Handle click event to show/hide the popup
        let popup = null;
        filterButton.addEventListener('click', (event) => {
            event.stopPropagation();
            if (popup) {
                popup.remove();
                popup = null;
            } else {
                popup = createPopup();
                popup.style.top = `${filterButton.offsetHeight}px`;
                popup.style.left = '0';
                filterButton.appendChild(popup);
            }
        });

        // Close the popup when clicking outside
        document.addEventListener('click', (event) => {
            if (popup && !filterButton.contains(event.target)) {
                popup.remove();
                popup = null;
            }
        });
    }

    if (playButton && !document.querySelector('.custom-play-button')) {
        // Create a container to hold both buttons
        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = `
            display: flex;
            gap: 10px;
            align-items: center;
            width: 100%;
        `;

        // Adjust the Play button to occupy 75% of the space
        playButton.style.cssText += `
            flex: 3;
            padding: 10px 12px;
            text-align: center;
        `;

        // Create the ServerHop Button with 25% width
        const serverHopButton = document.createElement('button');
        serverHopButton.className = 'custom-play-button';
        serverHopButton.style.cssText = `
            background-color: #335fff;
            color: white;
            border: none;
            padding: 7.5px 12px;
            cursor: pointer;
            font-weight: bold;
            border-radius: 8px;
            flex: 1;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
        `;

        // Custom tooltip
        const tooltip = document.createElement('div');
        tooltip.textContent = 'Join Random Server / Server Hop';
        tooltip.style.cssText = `
            position: absolute;
            background-color: rgba(51, 95, 255, 0.8);
            color: white;
            padding: 5px 10px;
            border-radius: 5px;
            font-size: 12px;
            visibility: hidden;
            opacity: 0;
            transition: opacity 0.2s ease-in-out;
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%);
            white-space: nowrap;
        `;
        serverHopButton.appendChild(tooltip);

        // Show tooltip on hover
        serverHopButton.addEventListener('mouseover', () => {
            tooltip.style.visibility = 'visible';
            tooltip.style.opacity = '1';
        });

        serverHopButton.addEventListener('mouseout', () => {
            tooltip.style.visibility = 'hidden';
            tooltip.style.opacity = '0';
        });

        // Add the logo (placeholder, you can replace this with your own base64)
        const logo = document.createElement('img');
        logo.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAEC0lEQVR4Xu2byWsUQRTG03pxAz2q0ZsHl7iByzigBxGMEhdEj3pRENGT/h16EslBxHh0ISoSl4MI7noQTEAlN3dviiZ60fH7hleh0k4yPfVqprraGSjS3VPV732/er28Sb2kI/WpVCoJDvWg7UPbgNaJNj3dL5L9n/DzA9ojtMtoN5Ikqdi+U+zYB+JXYucs2ppIBDbq5nMMOAQIL83AMQAQvx0HL6LNbPSskfX/wegGhFv0uwpAZv5hSvxv7D9GG0L7FplI4+5sbHSh8VKeamkghDIgDCZyzT9LhT1hHESHN5EKH+c2NC7GgXMCwnxHzSUC2IGN69YIit8C8b+KIN5ogM5p2L6bgtBDABdwcL90ZNgvK8rMpycQWpfIJT1FvusjgGHsLJID9yF+U5FmvgYERnhZjg8TwAh2ZsiBXgA4UnAAvdB3WDSOEID9YnAKAE4UHMBJ6DtuNDoDALd5OMlqNAJ8AXCfWwnO1T7G6QDgBHw1PoPGp4d5kfqDbT5JjgLEx2aC0NpXARDjfDlaOIHIdzheahYEH/a1AK5B4M46M9wPAHuaEQVwXm3fGQAGzoeo91bYT6SRl0On73uCL/saANsgbCDjzHYDwO2MfTN1g+Ne7GsAdMPTm5m87ejYCgB3MvbN1A2Oe7GvAcDHHi8B8xrZ6kvAi31nAFSLwf34s7vOlF3B7O/NNK0NdvJhXwuAN8InkzwG38pj8FOD2jJ1lxuhyr4KgEQBIZxG22VdDrzzX0U7htlvinhDSCA421cDsByZi+1Vss9X4S+ZptFTJwhxsu8NgCcdLT9NG4A2GWr5lHk22I6AvESAaz6vDYjgEaDN56MG4COfjx2AOp+PFoCvfD5mAF7y+ZgBeMnnYwbgJZ+PFoBkkkF/TxAfdP8X0MyAj3xeYz84gJz8nhAuAuzZc83no48ArQDt+OC5gFaAdnwbQF7SYe1Muo73FgGh8nnrR1mn9QlqADnI51XrE1QAQufzPuxrAQTN5+G82r4zgND5vC/7GgBB83k47sW+BkDQfB6Oe7GvARA0n5fHrnp9gjOAPOTzcF79e4IWQHt9gNyNnf8/7/oKa70BqtYnqCIgD/m8BaK9PsAlmmpFwP+8XH40XTDxAEtdNrqQjWUMIuCfgok+OH9ABLBkpgsQXsciqBE/IX4p+g+imbWO52sVTXE1+OaCFk3dg7b1FrRq0RTX/D9FW2t9QQgsm3vVCOG89pWZZ9mcLZ7rDcumcHIFdnhtzLJE8HIgGIbM17yKq+PXHHy/HK1khT2HfK+KT5Ihu3SWycalFIRIdU/qNsWzdLa6mj1dPE1aLJ5eV0TlEtEsnmY5cPUzDgAPyD2BhdSmfH4Btk1ZXWxcRuEwM0hTPj+QLp//C/HknAythT+iAAAAAElFTkSuQmCC';
        logo.style.cssText = `
            width: 45px;
            height: 45px;
        `;
        serverHopButton.appendChild(logo);

        // Insert both buttons into the container
        playButton.parentNode.insertBefore(buttonContainer, playButton);
        buttonContainer.appendChild(playButton);
        buttonContainer.appendChild(serverHopButton);

        // Handle click event
        serverHopButton.addEventListener('click', () => {
            ServerHop();
        });
    }

    // Stop observing if both elements are found
    if (document.querySelector('.RL-filter-button') && document.querySelector('.custom-play-button')) {
        obs.disconnect();
    }
});




    /*********************************************************************************************************************************************************************************************************************************************
                                                             The End of: This is all of the functions for the filter button and the popup for the 8 buttons does not include the functions for the 8 buttons

    *********************************************************************************************************************************************************************************************************************************************/


    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 1st button

    *********************************************************************************************************************************************************************************************************************************************/


    /*******************************************************
    name of function: smallest_servers FIRST FUNCTION
    description: Fetches the smallest servers, disables the "Load More" button, shows a loading bar, and recreates the server cards.
    *******************************************************/
    async function smallest_servers() {
        // Disable the "Load More" button and show the loading bar
        Loadingbar(true);
        disableFilterButton(true);
        disableLoadMoreButton();
        notifications("Finding small servers...","success","🧐")

        // Get the game ID from the URL
        const gameId = window.location.pathname.split('/')[2];

        // Retry mechanism
        let retries = 3;
        let success = false;

        while (retries > 0 && !success) {
            try {
                // Fetch server data from the Roblox API
                const response = await fetch(`https://games.roblox.com/v1/games/${gameId}/servers/0?sortOrder=1&excludeFullGames=true&limit=100`);

                // Check if the response status is 429 (Too Many Requests)
                if (response.status === 429) {
                    throw new Error('429: Too Many Requests');
                }

                const data = await response.json();

                // Process each server
                for (const server of data.data) {
                    const {
                        id: serverId,
                        playerTokens,
                        maxPlayers,
                        playing
                    } = server;

                    // Pass the server data to the card creation function
                    await rbx_card(serverId, playerTokens, maxPlayers, playing, gameId);
                }

                success = true; // Mark as successful if no errors occurred
            } catch (error) {
                retries--; // Decrement the retry count

                if (error.message === '429: Too Many Requests' && retries > 0) {
                    console.log('Encountered a 429 error. Retrying in 10 seconds...');
                    await new Promise(resolve => setTimeout(resolve, 10000)); // Wait for 10 seconds
                } else {
                    console.error('Error fetching server data:', error);
                    break; // Exit the loop if it's not a 429 error or no retries left
                }
            } finally {
                if (success || retries === 0) {
                    // Hide the loading bar and enable the filter button
                    Loadingbar(false);
                    disableFilterButton(false);
                }
            }
        }
    }



    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 2nd button

    *********************************************************************************************************************************************************************************************************************************************/


    /*******************************************************
    name of function: available_space_servers
    description: Fetches servers with available space, disables the "Load More" button, shows a loading bar, and recreates the server cards.
    *******************************************************/
    async function available_space_servers() {
        // Disable the "Load More" button and show the loading bar
        Loadingbar(true);
        disableLoadMoreButton();
        disableFilterButton(true);
        notifications("Finding servers with space...","success","🧐")

        // Get the game ID from the URL
        const gameId = window.location.pathname.split('/')[2];

        // Retry mechanism
        let retries = 3;
        let success = false;

        while (retries > 0 && !success) {
            try {
                // Fetch server data from the Roblox API
                const response = await fetch(`https://games.roblox.com/v1/games/${gameId}/servers/0?sortOrder=2&excludeFullGames=true&limit=100`);

                // Check if the response status is 429 (Too Many Requests)
                if (response.status === 429) {
                    throw new Error('429: Too Many Requests');
                }

                const data = await response.json();

                // Process each server
                for (const server of data.data) {
                    const {
                        id: serverId,
                        playerTokens,
                        maxPlayers,
                        playing
                    } = server;

                    // Pass the server data to the card creation function
                    await rbx_card(serverId, playerTokens, maxPlayers, playing, gameId);
                }

                success = true; // Mark as successful if no errors occurred
            } catch (error) {
                retries--; // Decrement the retry count

                if (error.message === '429: Too Many Requests' && retries > 0) {
                    console.log('Encountered a 429 error. Retrying in 10 seconds...');
                    await new Promise(resolve => setTimeout(resolve, 10000)); // Wait for 10 seconds
                } else {
                    console.error('Error fetching server data:', error);
                    break; // Exit the loop if it's not a 429 error or no retries left
                }
            } finally {
                if (success || retries === 0) {
                    // Hide the loading bar and enable the filter button
                    Loadingbar(false);
                    disableFilterButton(false);
                }
            }
        }
    }

    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 3rd button

    *********************************************************************************************************************************************************************************************************************************************/


    /*******************************************************
    	name of function: player_count_tab
    	description: Opens a popup for the user to select the max player count using a slider and filters servers accordingly.
    *******************************************************/
    function player_count_tab() {
        // Create the overlay (backdrop)
        const overlay = document.createElement('div');
        overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 9999;
        opacity: 0;
        transition: opacity 0.3s ease;
    `;
        document.body.appendChild(overlay);

        // Create the popup container
        const popup = document.createElement('div');
        popup.className = 'player-count-popup';
        popup.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: rgb(30, 32, 34);
        padding: 20px;
        border-radius: 10px;
        z-index: 10000;
        box-shadow: 0 0 15px rgba(0, 0, 0, 0.7);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 15px;
        width: 300px;
        opacity: 0;
        transition: opacity 0.3s ease, transform 0.3s ease;
    `;

        // Add a close button in the top-right corner (bigger size)
        const closeButton = document.createElement('button');
        closeButton.innerHTML = '&times;'; // Using '×' for the close icon
        closeButton.style.cssText = `
        position: absolute;
        top: 10px;
        right: 10px;
        background: transparent;
        border: none;
        color: #ffffff;
        font-size: 24px; /* Increased font size */
        cursor: pointer;
        width: 36px; /* Increased size */
        height: 36px; /* Increased size */
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: background-color 0.3s ease, color 0.3s ease;
    `;
        closeButton.addEventListener('mouseenter', () => {
            closeButton.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
            closeButton.style.color = '#ff4444';
        });
        closeButton.addEventListener('mouseleave', () => {
            closeButton.style.backgroundColor = 'transparent';
            closeButton.style.color = '#ffffff';
        });

        // Add a title
        const title = document.createElement('h3');
        title.textContent = 'Select Max Player Count';
        title.style.cssText = `
        color: white;
        margin: 0;
        font-size: 18px;
        font-weight: 500;
    `;
        popup.appendChild(title);

        // Add a slider with improved functionality and styling
        const slider = document.createElement('input');
        slider.type = 'range';
        slider.min = '1';
        slider.max = '100';
        slider.value = '1'; // Default value
        slider.step = '1'; // Step for better accuracy
        slider.style.cssText = `
        width: 80%;
        cursor: pointer;
        margin: 10px 0;
        -webkit-appearance: none; /* Remove default styling */
        background: transparent;
    `;
        // Custom slider track
        slider.style.background = `
        linear-gradient(
            to right,
            #00A2FF 0%,
            #00A2FF ${slider.value}%,
            #444 ${slider.value}%,
            #444 100%
        );
        border-radius: 5px;
        height: 6px;
    `;
        // Custom slider thumb
        slider.style.setProperty('--thumb-size', '20px'); /* Larger thumb */
        slider.style.setProperty('--thumb-color', '#00A2FF');
        slider.style.setProperty('--thumb-hover-color', '#0088cc');
        slider.style.setProperty('--thumb-border', '2px solid #fff');
        slider.style.setProperty('--thumb-shadow', '0 0 5px rgba(0, 0, 0, 0.5)');
        slider.addEventListener('input', () => {
            slider.style.background = `
            linear-gradient(
                to right,
                #00A2FF 0%,
                #00A2FF ${slider.value}%,
                #444 ${slider.value}%,
                #444 100%
            );
        `;
            sliderValue.textContent = slider.value; // Update the displayed value
        });
        // Keyboard support for better accuracy (fixed to increment/decrement by 1)
        slider.addEventListener('keydown', (e) => {
            e.preventDefault(); // Prevent default behavior (which might cause jumps)
            let newValue = parseInt(slider.value, 10);
            if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
                newValue = Math.max(1, newValue - 1); // Decrease by 1
            } else if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
                newValue = Math.min(100, newValue + 1); // Increase by 1
            }
            slider.value = newValue;
            slider.dispatchEvent(new Event('input')); // Trigger input event to update UI
        });
        popup.appendChild(slider);

        // Add a display for the slider value
        const sliderValue = document.createElement('span');
        sliderValue.textContent = slider.value;
        sliderValue.style.cssText = `
        color: white;
        font-size: 16px;
        font-weight: bold;
    `;
        popup.appendChild(sliderValue);

        // Add a submit button with dark, blackish style
        const submitButton = document.createElement('button');
        submitButton.textContent = 'Search';
        submitButton.style.cssText = `
        padding: 8px 20px;
        font-size: 16px;
        background-color: #1a1a1a; /* Dark blackish color */
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        transition: background-color 0.3s ease, transform 0.2s ease;
    `;
        submitButton.addEventListener('mouseenter', () => {
            submitButton.style.backgroundColor = '#333'; /* Slightly lighter on hover */
            submitButton.style.transform = 'scale(1.05)';
        });
        submitButton.addEventListener('mouseleave', () => {
            submitButton.style.backgroundColor = '#1a1a1a';
            submitButton.style.transform = 'scale(1)';
        });

        // Add a yellow box with a tip under the submit button
        const tipBox = document.createElement('div');
        tipBox.style.cssText = `
        width: 100%;
        padding: 10px;
        background-color: rgba(255, 204, 0, 0.15);
        border-radius: 5px;
        text-align: center;
        font-size: 14px;
        color: #ffcc00;
        transition: background-color 0.3s ease;
    `;
        tipBox.textContent = 'Tip: Using arrow keys would be more accurate.';
        tipBox.addEventListener('mouseenter', () => {
            tipBox.style.backgroundColor = 'rgba(255, 204, 0, 0.25)';
        });
        tipBox.addEventListener('mouseleave', () => {
            tipBox.style.backgroundColor = 'rgba(255, 204, 0, 0.15)';
        });
        popup.appendChild(tipBox);

        // Append the popup to the body
        document.body.appendChild(popup);

        // Fade in the overlay and popup
        setTimeout(() => {
            overlay.style.opacity = '1';
            popup.style.opacity = '1';
            popup.style.transform = 'translate(-50%, -50%) scale(1)';
        }, 10);

        /*******************************************************
            name of function: fadeOutAndRemove
            description: Fades out and removes the popup and overlay.
        *******************************************************/
        function fadeOutAndRemove(popup, overlay) {
            popup.style.opacity = '0';
            popup.style.transform = 'translate(-50%, -50%) scale(0.9)';
            overlay.style.opacity = '0';
            setTimeout(() => {
                popup.remove();
                overlay.remove();
            }, 300); // Match the duration of the transition
        }

        // Close the popup when clicking outside
        overlay.addEventListener('click', () => {
            fadeOutAndRemove(popup, overlay);
        });

        // Close the popup when the close button is clicked
        closeButton.addEventListener('click', () => {
            fadeOutAndRemove(popup, overlay);
        });

        // Handle submit button click
        submitButton.addEventListener('click', () => {
            const maxPlayers = parseInt(slider.value, 10);
            if (!isNaN(maxPlayers) && maxPlayers > 0) {
                filterServersByPlayerCount(maxPlayers);
                fadeOutAndRemove(popup, overlay);
            } else {
                notifications('Error: Please enter a number greater than 0', 'error', '⚠️');
            }
        });

        popup.appendChild(submitButton);
        popup.appendChild(closeButton);
    }
    /*******************************************************
    name of function: fetchServersWithRetry
    description: Fetches server data with retry logic and a delay between requests to avoid rate-limiting.
    Uses GM_xmlhttpRequest instead of fetch.
    *******************************************************/
    async function fetchServersWithRetry(url, retries = 15, currentDelay = 750) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function(response) {
                    // Check for 429 Rate Limit error
                    if (response.status === 429) {
                        if (retries > 0) {
                            const newDelay = currentDelay * 1; // Exponential backoff
                            console.log(`[DEBUG] Rate limited. Waiting ${newDelay / 1000} seconds before retrying...`);
                            setTimeout(() => {
                                resolve(fetchServersWithRetry(url, retries - 1, newDelay)); // Retry with increased delay
                            }, newDelay);
                        } else {
                            console.error('[DEBUG] Rate limit retries exhausted.');
                            notifications('Error: Rate limited please try again later.', 'error', '⚠️')
                            reject(new Error('RateLimit'));
                        }
                        return;
                    }

                    // Handle other HTTP errors
                    if (response.status < 200 || response.status >= 300) {
                        console.error('[DEBUG] HTTP error:', response.status, response.statusText);
                        reject(new Error(`HTTP error: ${response.status}`));
                        return;
                    }

                    // Parse and return the JSON data
                    try {
                        const data = JSON.parse(response.responseText);
                        console.log('[DEBUG] Fetched data successfully:', data);
                        resolve(data);
                    } catch (error) {
                        console.error('[DEBUG] Error parsing JSON:', error);
                        reject(error);
                    }
                },
                onerror: function(error) {
                    console.error('[DEBUG] Error in GM_xmlhttpRequest:', error);
                    reject(error);
                }
            });
        });
    }

    /*******************************************************
    name of function: filterServersByPlayerCount
    description: Filters servers to show only those with a player count equal to or below the specified max.
    If no exact matches are found, prioritizes servers with player counts lower than the input.
    Keeps fetching until at least 8 servers are found, with a dynamic delay between requests.
    *******************************************************/
    async function filterServersByPlayerCount(maxPlayers) {
        // Validate maxPlayers before proceeding
        if (isNaN(maxPlayers) || maxPlayers < 1 || !Number.isInteger(maxPlayers)) {
            console.error('[DEBUG] Invalid input for maxPlayers.');
            notifications('Error: Please input a valid whole number greater than or equal to 1.', 'error', '⚠️');
            return;
        }

        // Disable UI elements and clear the server list
        Loadingbar(true);
        disableLoadMoreButton();
        disableFilterButton(true);
        const serverList = document.querySelector('#rbx-game-server-item-container');
        serverList.innerHTML = '';

        const gameId = window.location.pathname.split('/')[2];
        let cursor = null;
        let serversFound = 0;
        let serverMaxPlayers = null;
        let isCloserToOne = null;
        let topDownServers = []; // Servers collected during top-down search
        let bottomUpServers = []; // Servers collected during bottom-up search
        let currentDelay = 500; // Initial delay of 0.5 seconds
        const timeLimit = 3 * 60 * 1000; // 3 minutes in milliseconds
        const startTime = Date.now(); // Record the start time
        notifications('Will search for a maximum of 3 minutes to find a server.', 'success', '🔎');


        try {
            while (serversFound < 16) {
                // Check if the time limit has been exceeded
                if (Date.now() - startTime > timeLimit) {
                    console.log('[DEBUG] Time limit reached. Proceeding to fallback servers.');
                    notifications('Warning: Time limit reached. Proceeding to fallback servers.', 'warning', '❗');
                    break;
                }

                // Fetch initial data to determine serverMaxPlayers and isCloserToOne
                if (!serverMaxPlayers) {
                    const initialUrl = cursor ?
                        `https://games.roblox.com/v1/games/${gameId}/servers/public?excludeFullGames=true&limit=100&cursor=${cursor}` :
                        `https://games.roblox.com/v1/games/${gameId}/servers/public?excludeFullGames=true&limit=100`;

                    const initialData = await fetchServersWithRetry(initialUrl);
                    if (initialData.data.length > 0) {
                        serverMaxPlayers = initialData.data[0].maxPlayers;
                        isCloserToOne = maxPlayers <= (serverMaxPlayers / 2);
                    } else {
                        console.error('[DEBUG] No servers found in initial fetch.');
                        break;
                    }
                }

                // Validate maxPlayers against serverMaxPlayers
                if (maxPlayers >= serverMaxPlayers) {
                    console.error('[DEBUG] Invalid input: maxPlayers is greater than or equal to serverMaxPlayers.');
                    notifications(`Error: Please input a number between 1 through ${serverMaxPlayers - 1}`, 'error', '⚠️');
                    return;
                }

                // Adjust the URL based on isCloserToOne
                const baseUrl = isCloserToOne ?
                    `https://games.roblox.com/v1/games/${gameId}/servers/public?sortOrder=1&excludeFullGames=true&limit=100` :
                    `https://games.roblox.com/v1/games/${gameId}/servers/public?excludeFullGames=true&limit=100`; // why does this work lmao

                const url = cursor ? `${baseUrl}&cursor=${cursor}` : baseUrl;
                const data = await fetchServersWithRetry(url);

                // Safety check: Ensure the server list is valid and iterable
                if (!Array.isArray(data.data)) {
                    console.error('[DEBUG] Invalid server list received. Waiting 1 second before retrying...');
                    await delay(1000); // Wait 1 second before retrying
                    continue; // Skip the rest of the loop and retry
                }

                // Filter and process servers
                for (const server of data.data) {
                    if (server.playing === maxPlayers) {
                        await rbx_card(server.id, server.playerTokens, server.maxPlayers, server.playing, gameId);
                        serversFound++;

                        if (serversFound >= 16) {
                            break;
                        }
                    } else if (!isCloserToOne && server.playing > maxPlayers) {
                        topDownServers.push(server); // Add to top-down fallback list
                    } else if (isCloserToOne && server.playing < maxPlayers) {
                        bottomUpServers.push(server); // Add to bottom-up fallback list
                    }
                }

                // Exit if no more servers are available
                if (!data.nextPageCursor) {
                    break;
                }

                cursor = data.nextPageCursor;

                // Adjust delay dynamically
                if (currentDelay > 150) {
                    currentDelay = Math.max(150, currentDelay / 2); // Gradually reduce delay
                }
                console.log(`[DEBUG] Waiting ${currentDelay / 1000} seconds before next request...`);
                await delay(currentDelay);
            }

            // If no exact matches were found or time limit reached, use fallback servers
            if (serversFound === 0 && (topDownServers.length > 0 || bottomUpServers.length > 0)) {
                // Sort top-down servers by player count (ascending)
                topDownServers.sort((a, b) => a.playing - b.playing);

                // Sort bottom-up servers by player count (descending)
                bottomUpServers.sort((a, b) => b.playing - a.playing);

                // Combine both fallback lists (prioritize top-down servers first)
                const combinedFallback = [...topDownServers, ...bottomUpServers];

                for (const server of combinedFallback) {
                    await rbx_card(server.id, server.playerTokens, server.maxPlayers, server.playing, gameId);
                    serversFound++;

                    if (serversFound >= 16) {
                        break;
                    }
                }
            }

            if (serversFound <= 0) {
                notifications('No Servers Found Within The Provided Criteria', 'info', '🔎');
            }
        } catch (error) {
            console.error('[DEBUG] Error in filterServersByPlayerCount:', error);
        } finally {
            Loadingbar(false);
            disableFilterButton(false);
        }
    }

    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 4th button

    *********************************************************************************************************************************************************************************************************************************************/

    /*******************************************************
    name of function: random_servers
    description: Fetches servers from two different URLs, combines the results, ensures no duplicates, shuffles the list, and passes the server information to the rbx_card function in a random order. Handles 429 errors with retries.
    *******************************************************/
    async function random_servers() {
        notifications('Finding Random Server. Please wait 5-10 seconds', 'success', '🔎');
        // Disable the "Load More" button and show the loading bar
        Loadingbar(true);
        disableFilterButton(true);
        disableLoadMoreButton();

        // Get the game ID from the URL
        const gameId = window.location.pathname.split('/')[2];

        try {
            // Fetch servers from the first URL with retry logic
            const firstUrl = `https://games.roblox.com/v1/games/${gameId}/servers/public?excludeFullGames=true&limit=10`;
            const firstData = await fetchWithRetry(firstUrl, 3); // Retry up to 3 times

            // Wait for 5 seconds
            await delay(5000);

            // Fetch servers from the second URL with retry logic
            const secondUrl = `https://games.roblox.com/v1/games/${gameId}/servers/public?sortOrder=1&excludeFullGames=true&limit=10`;
            const secondData = await fetchWithRetry(secondUrl, 3); // Retry up to 3 times

            // Combine the servers from both URLs
            const combinedServers = [...firstData.data, ...secondData.data];

            // Remove duplicates by server ID
            const uniqueServers = [];
            const seenServerIds = new Set();

            for (const server of combinedServers) {
                if (!seenServerIds.has(server.id)) {
                    seenServerIds.add(server.id);
                    uniqueServers.push(server);
                }
            }

            // Shuffle the unique servers array
            const shuffledServers = shuffleArray(uniqueServers);

            // Get the first 16 shuffled servers
            const selectedServers = shuffledServers.slice(0, 16);

            // Process each server in random order
            for (const server of selectedServers) {
                const {
                    id: serverId,
                    playerTokens,
                    maxPlayers,
                    playing
                } = server;

                // Pass the server data to the card creation function
                await rbx_card(serverId, playerTokens, maxPlayers, playing, gameId);
            }
        } catch (error) {
            console.error('Error fetching server data:', error);
            notifications('Error: Failed to fetch server data. Please try again later.', 'error', '⚠️');
        } finally {
            // Hide the loading bar and enable the filter button
            Loadingbar(false);
            disableFilterButton(false);
        }
    }

    /*******************************************************
    name of function: fetchWithRetry
    description: Fetches data from a URL with retry logic for 429 errors. this is for this unique function
    *******************************************************/
    async function fetchWithRetry(url, retries) {
        for (let i = 0; i < retries; i++) {
            try {
                const response = await fetch(url);
                if (response.status === 429) {
                    // If 429 error, wait 10 seconds and retry
                    console.log(`Rate limited. Retrying in 10 seconds... (Attempt ${i + 1}/${retries})`);
                    await delay(10000); // Wait 10 seconds
                    continue;
                }
                if (!response.ok) {
                    throw new Error(`HTTP error: ${response.status}`);
                }
                return await response.json();
            } catch (error) {
                if (i === retries - 1) {
                    // If no retries left, throw the error
                    throw error;
                }
            }
        }
    }

    /*******************************************************
    name of function: shuffleArray
    description: Shuffles an array using the Fisher-Yates algorithm.
    *******************************************************/
    function shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1)); // Random index from 0 to i
            [array[i], array[j]] = [array[j], array[i]]; // Swap elements
        }
        return array;
    }


    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 5th button. taken from my other project

    *********************************************************************************************************************************************************************************************************************************************/

    // so we inject css into the page. if ur on light mode some stuff may look weird so not my fault
    const style = document.createElement('style');
    style.textContent = `
/* Overlay for the modal background */
.overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.85); /* Solid black overlay */
    z-index: 1000; /* Ensure overlay is below the popup */
    opacity: 0; /* Start invisible */
    animation: fadeIn 0.3s ease forwards; /* Fade-in animation */
}

@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

/* Popup Container for the server region */
.filter-popup {
    background-color: #1e1e1e; /* Darker background */
    color: #ffffff; /* White text */
    padding: 25px;
    border-radius: 12px;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5);
    width: 320px;
    max-width: 90%;
    position: fixed; /* Fixed positioning */
    top: 50%; /* Center vertically */
    left: 50%; /* Center horizontally */
    transform: translate(-50%, -50%); /* Offset to truly center */
    text-align: center;
    z-index: 1001; /* Ensure popup is above the overlay */
    border: 1px solid #444; /* Subtle border */
    opacity: 0; /* Start invisible */
    animation: fadeInPopup 0.3s ease 0.1s forwards; /* Fade-in animation with delay */
}

@keyframes fadeInPopup {
    from {
        opacity: 0;
        transform: translate(-50%, -55%); /* Slight upward offset */
    }
    to {
        opacity: 1;
        transform: translate(-50%, -50%); /* Center position */
    }
}

/* Fade-out animation for overlay and popup */
.overlay.fade-out {
    animation: fadeOut 0.3s ease forwards;
}

.filter-popup.fade-out {
    animation: fadeOutPopup 0.3s ease forwards;
}

@keyframes fadeOut {
    from {
        opacity: 1;
    }
    to {
        opacity: 0;
    }
}

@keyframes fadeOutPopup {
    from {
        opacity: 1;
        transform: translate(-50%, -50%); /* Center position */
    }
    to {
        opacity: 0;
        transform: translate(-50%, -55%); /* Slight upward offset */
    }
}

/* Close Button for the server selector */
#closePopup {
    position: absolute;
    top: 5px; /* Reduced from 12px to 5px */
    right: 1px; /* Reduced from 12px to 5px */
    background: transparent; /* Transparent background */
    border: none;
    color: #ffffff; /* White color */
    font-size: 20px;
    cursor: pointer;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.3s ease, color 0.3s ease;
}

#closePopup:hover {
    background-color: rgba(255, 255, 255, 0.1); /* Light hover effect */
    color: #ff4444; /* Red color on hover */
}

/* Label */
.filter-popup label {
    display: block;
    margin-bottom: 12px;
    font-size: 16px;
    color: #ffffff;
    font-weight: 500; /* Slightly bolder text */
}

/* Dropdown */
.filter-popup select {
    background-color: #333; /* Darker gray background */
    color: #ffffff; /* White text */
    padding: 10px;
    border-radius: 6px;
    border: 1px solid #555; /* Darker border */
    width: 100%;
    margin-bottom: 12px;
    font-size: 14px;
    transition: border-color 0.3s ease;
}

.filter-popup select:focus {
    border-color: #888; /* Lighter border on focus */
    outline: none;
}

/* Custom Input */
.filter-popup input[type="number"] {
    background-color: #333; /* Darker gray background */
    color: #ffffff; /* White text */
    padding: 10px;
    border-radius: 6px;
    border: 1px solid #555; /* Darker border */
    width: 100%;
    margin-bottom: 12px;
    font-size: 14px;
    transition: border-color 0.3s ease;
}

.filter-popup input[type="number"]:focus {
    border-color: #888; /* Lighter border on focus */
    outline: none;
}

/* Confirm Button */
#confirmServerCount {
    background-color: #444; /* Dark gray background */
    color: #ffffff; /* White text */
    padding: 10px 20px;
    border: 1px solid #666; /* Gray border */
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    width: 100%;
    transition: background-color 0.3s ease, transform 0.2s ease;
}

#confirmServerCount:hover {
    background-color: #555; /* Lighter gray on hover */
    transform: translateY(-1px); /* Slight lift effect */
}

#confirmServerCount:active {
    transform: translateY(0); /* Reset lift effect on click */
}

/* Highlighted server item */
.rbx-game-server-item.highlighted {
    border: 2px solid #4caf50; /* Green border */
    border-radius: 8px;
    background-color: rgba(76, 175, 80, 0.1); /* Subtle green background */
}

/* Disabled fetch button */
.fetch-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Popup Header */
.popup-header {
    margin-bottom: 24px;
    text-align: left;
    padding: 16px;
    background-color: rgba(255, 255, 255, 0.05); /* Subtle background for contrast */
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1); /* Subtle border */
    transition: background-color 0.3s ease, border-color 0.3s ease;
}

.popup-header:hover {
    background-color: rgba(255, 255, 255, 0.08); /* Slightly brighter on hover */
    border-color: rgba(255, 255, 255, 0.2);
}

.popup-header h3 {
    margin: 0 0 12px 0;
    font-size: 22px;
    color: #ffffff;
    font-weight: 700; /* Bolder for emphasis */
    letter-spacing: -0.5px; /* Tighter letter spacing for modern look */
}

.popup-header p {
    margin: 0;
    font-size: 14px;
    color: #cccccc;
    line-height: 1.6; /* Improved line height for readability */
    opacity: 0.9; /* Slightly transparent for a softer look */
}

/* Popup Footer */
.popup-footer {
    margin-top: 20px;
    text-align: left;
    font-size: 14px;
    color: #ffcc00; /* Yellow color for warnings */
    background-color: rgba(255, 204, 0, 0.15); /* Lighter yellow background */
    padding: 12px;
    border-radius: 8px;
    border: 1px solid rgba(255, 204, 0, 0.15); /* Subtle border */
    transition: background-color 0.3s ease, border-color 0.3s ease;
}

.popup-footer:hover {
    background-color: rgba(255, 204, 0, 0.25); /* Slightly brighter on hover */
    border-color: rgba(255, 204, 0, 0.25);
}

.popup-footer p {
    margin: 0;
    line-height: 1.5;
    font-weight: 500; /* Slightly bolder for emphasis */
}

/* Label */
.filter-popup label {
    display: block;
    margin-bottom: 12px;
    font-size: 15px;
    color: #ffffff;
    font-weight: 500;
    text-align: left;
    opacity: 0.9; /* Slightly transparent for a softer look */
    transition: opacity 0.3s ease;
}

.filter-popup label:hover {
    opacity: 1; /* Fully opaque on hover */
}
    `;
    document.head.appendChild(style);


    // Function to show the message under the "Load More" button
    function showMessage(message) {
        const loadMoreButtonContainer = document.querySelector('.rbx-running-games-footer');

        if (!loadMoreButtonContainer) {
            console.error("Load More button container not found!");
            return;
        }

        // Create the message element
        const messageElement = document.createElement('div');
        messageElement.className = 'filter-message';
        messageElement.textContent = message;

        // Clear any existing message and append the new one
        const existingMessage = loadMoreButtonContainer.querySelector('.filter-message');
        if (existingMessage) {
            existingMessage.remove(); // Remove the existing message if it exists
        }

        loadMoreButtonContainer.appendChild(messageElement);

        return messageElement;
    }

    // Function to hide the message of the showmessage functioon
    function hideMessage() {
        const messageElement = document.querySelector('.filter-message');
        if (messageElement) messageElement.remove();
    }

    // Function to show the popup for random stuff
    function showPopup() {
        const overlay = document.createElement('div');
        overlay.className = 'overlay';

        const popup = document.createElement('div');
        popup.className = 'filter-popup';
        popup.textContent = 'Filtering servers, please wait...';

        document.body.appendChild(overlay);
        document.body.appendChild(popup);

        return popup;
    }

    // Function to hide the popup for the stuff
    function hidePopup() {
        const popup = document.querySelector('.filter-popup');
        const overlay = document.querySelector('.overlay');

        if (popup) popup.remove();
        if (overlay) overlay.remove();
    }

    // Function to fetch server details so game id and job id. yea!
    async function fetchServerDetails(gameId, jobId) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: "https://gamejoin.roblox.com/v1/join-game-instance", // url for game id
                headers: { // doesent need cookie cuase of magic
                    "Content-Type": "application/json",
                    "User-Agent": "Roblox/WinInet",
                },
                data: JSON.stringify({
                    placeId: gameId,
                    gameId: jobId
                }),
                onload: function(response) {
                    const json = JSON.parse(response.responseText);

                    console.log("API Response:", json); // This prints the full response

                    // Check if the response indicates that the user needs to purchase the game
                    if (json.status === 12 && json.message === 'You need to purchase access to this game before you can play.') { // yea error message!
                        reject('purchase_required'); // Special error code for this case yea!
                        return;
                    }

                    const address = json?.joinScript?.UdmuxEndpoints?.[0]?.Address ?? json?.joinScript?.MachineAddress;

                    if (!address) {
                        console.error("API Response (Unknown Location) Which means Full Server!:", json); // Log the API response for debug
                        reject(`Unable to fetch server location: Status ${json.status}`); // debug
                        return;
                    }

                    const location = serverRegionsByIp[address.replace(/^(128\.116\.\d+)\.\d+$/, "$1.0")]; // lmao all servers atart with this so yea dont argue with me

                    if (!location) {
                        console.error("API Response (Unknown Location):", json); // Log the API response into the chat. might remove it from production but idc rn
                        reject(`Unknown server address ${address}`);
                        return;
                    }

                    resolve(location);
                },
                onerror: function(error) {
                    console.error("API Request Failed:", error); // damn if this happpens idk what to tell u
                    reject(`Failed to fetch server details: ${error}`);
                },
            });
        });
    }

    // cusomt delay also known as sleep fucntion in js cause this language sucks and doesent have a default function
    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // Function to create a popup for selecting the number of servers
    // basically yea thats what it doesent
    function createServerCountPopup(callback) {
        const overlay = document.createElement('div');
        overlay.className = 'overlay';

        const popup = document.createElement('div');
        popup.className = 'filter-popup'; // reason 100 is selected because thjats how many the api will show per request
        popup.innerHTML = `
<button id="closePopup">X</button>
<div class="popup-header">
    <h3>Select Number of Servers</h3>
    <p>Choose how many servers you want to search. Higher values will provide more location variety but may take longer to process.</p>
<div class="popup-footer">
    <p><strong>Note:</strong> Searching over 100 servers may take longer and could result in rate limiting.</p>
</div>
</div>
<label for="serverCount">Number of Servers:</label>
<select id="serverCount">
    <option value="10">10 Servers</option>
    <option value="25">25 Servers</option>
    <option value="50">50 Servers</option>
    <option value="100" selected>100 Servers</option>
    <option value="200">200 Servers</option>
    <option value="500">500 Servers</option>
    <option value="1000">1000 Servers</option>
    <option value="custom">Custom</option>
</select>
<input id="customServerCount" type="number" min="1" max="1000" placeholder="Enter a number (1-1000)" style="display: none;">
<button id="confirmServerCount">Confirm</button>
    `;

        document.body.appendChild(overlay);
        document.body.appendChild(popup);

        const serverCountDropdown = popup.querySelector('#serverCount');
        const customServerCountInput = popup.querySelector('#customServerCount');
        const confirmButton = popup.querySelector('#confirmServerCount');
        const closeButton = popup.querySelector('#closePopup');

        // Show/hide custom input based on dropdown selection
        serverCountDropdown.addEventListener('change', () => {
            if (serverCountDropdown.value === 'custom') {
                customServerCountInput.style.display = 'block';
            } else {
                customServerCountInput.style.display = 'none';
            }
        });

        // button click on start or what ever
        confirmButton.addEventListener('click', () => {
            let serverCount;

            if (serverCountDropdown.value === 'custom') {
                serverCount = parseInt(customServerCountInput.value);

                // Validate custom input
                if (isNaN(serverCount) || serverCount < 1 || serverCount > 1000) {
                    notifications('Error: Please enter a valid number between 1 and 1000.', 'error', '⚠️')
                    return;
                }
            } else {
                serverCount = parseInt(serverCountDropdown.value);
            }

            // Show an alert if the user selects a number above 100
            if (serverCount > 100) { // error cause people dont know about this maybe. idk yea so here. also if u think this is a stupid way i should have done it before the button press idc so yea
                notifications('Warning: Searching over 100 servers may take some time and you might get rate limited!', 'warning', '❗');
            }

            // Pass the selected server count to the callback
            callback(serverCount);
            disableFilterButton(true); // disbale filter button
            disableLoadMoreButton(true); // disable load more button
            notifications('Note: Filter Button is disabled as this function is resource intensive. \nRefresh the page to call other functions/press other buttons.', 'info', '⚠️')
            hidePopup();
            Loadingbar(true); // enable loading bar
        });

        // Close button logic :))
        closeButton.addEventListener('click', () => {
            hidePopup();
        });

        // Function to hide the popup
        // yea im dumb and used the same function name but it works and im too lazy to change it
        function hidePopup() {
            const overlay = document.querySelector('.overlay');
            const popup = document.querySelector('.filter-popup');

            // Add fade-out classes
            overlay.classList.add('fade-out');
            popup.classList.add('fade-out');

            // Remove elements after animation completes
            setTimeout(() => {
                overlay.remove();
                popup.remove();
            }, 300); // Match the duration of the fade-out animation
        }
    }

    // Function to fetch public servers
    // totallimit is amount of sevrers to fetch
    async function fetchPublicServers(gameId, totalLimit) {
        let servers = [];
        let cursor = null;

        while (servers.length < totalLimit) { // too lazy to comment any of this. hopefully i remember what this does in the future
            const url = `https://games.roblox.com/v1/games/${gameId}/servers/public?excludeFullGames=true&limit=100${cursor ? `&cursor=${cursor}` : ''}`;

            const response = await new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    onload: function(response) {
                        resolve(JSON.parse(response.responseText));
                    },
                    onerror: function(error) {
                        reject(`Failed to fetch public servers: ${error}`);
                    },
                });
            });

            servers = servers.concat(response.data);

            if (!response.nextPageCursor || servers.length >= totalLimit) {
                break;
            }

            cursor = response.nextPageCursor;
            await delay(3000); // wait 3 seconds before each page request. if u think this is slow i tried 1 second i got rate limited :|
        }

        return servers.slice(0, totalLimit);
    }

    // Function to create dropdown menus for filtering
    function createFilterDropdowns(servers) {
        const filterContainer = document.createElement('div');
        filterContainer.className = 'filter-container';
        filterContainer.style.display = 'flex';
        filterContainer.style.gap = '15px';
        filterContainer.style.alignItems = 'center';
        filterContainer.style.justifyContent = 'center';
        filterContainer.style.padding = '20px';
        filterContainer.style.backgroundColor = '#1e1e1e';
        filterContainer.style.borderRadius = '12px';
        filterContainer.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
        filterContainer.style.opacity = '0'; // Start invisible for fade-in animation
        filterContainer.style.transform = 'translateY(-20px)'; // Start slightly above for animation
        filterContainer.style.transition = 'opacity 0.5s ease, transform 0.5s ease';

        // Fade-in animation for the container
        setTimeout(() => {
            filterContainer.style.opacity = '1';
            filterContainer.style.transform = 'translateY(0)';
        }, 100);

        // Add a logo placeholder (you can replace this with your own image)
        const logo = document.createElement('img');
        logo.src = 'data:image/jpeg;base64,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';
        logo.style.width = '40px';
        logo.style.height = '40px';
        logo.style.borderRadius = '8px';
        logo.style.marginRight = '10px';
        logo.style.transition = 'transform 0.3s ease';

        // Add hover effect to the logo
        logo.addEventListener('mouseover', () => {
            logo.style.transform = 'scale(1.1)';
        });

        logo.addEventListener('mouseout', () => {
            logo.style.transform = 'scale(1)';
        });

        filterContainer.appendChild(logo);

        const createDropdown = (id, placeholder) => {
            const dropdown = document.createElement('select');
            dropdown.id = id;
            dropdown.innerHTML = `<option value="">${placeholder}</option>`;
            dropdown.style.backgroundColor = '#333';
            dropdown.style.color = '#fff';
            dropdown.style.borderRadius = '8px';
            dropdown.style.padding = '10px 15px';
            dropdown.style.fontSize = '14px';
            dropdown.style.border = 'none';
            dropdown.style.outline = 'none';
            dropdown.style.cursor = 'pointer';
            dropdown.style.transition = 'all 0.3s ease';
            dropdown.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
            dropdown.style.opacity = '0'; // Start invisible for fade-in animation
            dropdown.style.transform = 'translateY(-10px)'; // Start slightly above for animation

            // Fade-in animation for the dropdown
            setTimeout(() => {
                dropdown.style.opacity = '1';
                dropdown.style.transform = 'translateY(0)';
            }, 300);

            dropdown.addEventListener('mouseover', () => {
                dropdown.style.backgroundColor = '#444';
                dropdown.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.3)';
                dropdown.style.transform = 'scale(1.02)';
            });

            dropdown.addEventListener('mouseout', () => {
                dropdown.style.backgroundColor = '#333';
                dropdown.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
                dropdown.style.transform = 'scale(1)';
            });

            dropdown.addEventListener('focus', () => {
                dropdown.style.backgroundColor = '#444';
                dropdown.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.3)';
            });

            dropdown.addEventListener('blur', () => {
                dropdown.style.backgroundColor = '#333';
                dropdown.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
            });

            // Add transition when an option is selected
            dropdown.addEventListener('change', () => {
                dropdown.style.transform = 'scale(1.05)';
                setTimeout(() => {
                    dropdown.style.transform = 'scale(1)';
                }, 200); // Reset after 200ms
            });

            return dropdown;
        };

        const countryDropdown = createDropdown('countryFilter', 'All Countries');
        const cityDropdown = createDropdown('cityFilter', 'All Cities');

        // Count the number of servers per country and add them to the dropdown
        const countryCounts = {};
        servers.forEach(server => {
            const country = server.location.country.name;
            countryCounts[country] = (countryCounts[country] || 0) + 1;
        });

        // Populate country dropdown with server counts
        Object.keys(countryCounts).forEach(country => {
            const option = document.createElement('option');
            option.value = country;
            option.textContent = `${country} (${countryCounts[country]})`;
            countryDropdown.appendChild(option);
        });

        // Add the city dropdown based on selected country
        countryDropdown.addEventListener('change', () => {
            const selectedCountry = countryDropdown.value;
            cityDropdown.innerHTML = '<option value="">All Cities</option>';

            if (selectedCountry) {
                // Count the number of servers per city in the selected country
                const cityCounts = {};
                servers
                    .filter(server => server.location.country.name === selectedCountry)
                    .forEach(server => {
                        const city = server.location.city;
                        const region = server.location.region?.name;
                        const cityKey = region ? `${city}, ${region}` : city;
                        cityCounts[cityKey] = (cityCounts[cityKey] || 0) + 1;
                    });

                // Populate city dropdown with server counts
                Object.keys(cityCounts).forEach(city => {
                    const option = document.createElement('option');
                    option.value = city;
                    option.textContent = `${city} (${cityCounts[city]})`;
                    cityDropdown.appendChild(option);
                });

                // Auto-select the city if there's only one
                const cities = Object.keys(cityCounts);
                if (cities.length === 1) {
                    cityDropdown.value = cities[0];
                }

                // Add a transition effect when the city dropdown updates
                cityDropdown.style.opacity = '0';
                cityDropdown.style.transform = 'translateY(-10px)';
                setTimeout(() => {
                    cityDropdown.style.opacity = '1';
                    cityDropdown.style.transform = 'translateY(0)';
                }, 100);
            }
        });

        filterContainer.appendChild(countryDropdown);
        filterContainer.appendChild(cityDropdown);

        return filterContainer;
    }

    // Function to filter servers based on selected country and city cause im lazy
    function filterServers(servers, country, city) {
        return servers.filter(server => {
            const matchesCountry = !country || server.location.country.name === country;
            const matchesCity = !city || `${server.location.city}${server.location.region?.name ? `, ${server.location.region.name}` : ''}` === city;
            return matchesCountry && matchesCity;
        });
    }

    // Function to sort servers by ping. maybe inaccurate but thats roblox's problem not mine
    function sortServersByPing(servers) {
        return servers.sort((a, b) => a.server.ping - b.server.ping);
    }

    async function fetchPlayerThumbnails_servers(playerTokens) {
        const body = playerTokens.map(token => ({
            requestId: `0:${token}:AvatarHeadshot:150x150:png:regular`,
            type: "AvatarHeadShot",
            targetId: 0,
            token,
            format: "png",
            size: "150x150",
        }));

        const response = await fetch("https://thumbnails.roblox.com/v1/batch", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                Accept: "application/json",
            },
            body: JSON.stringify(body),
        });

        const data = await response.json();
        return data.data || [];
    }

    async function rebuildServerList(gameId, totalLimit, best_connection) {
        const serverListContainer = document.getElementById("rbx-game-server-item-container");


        // If "Best Connection" is enabled
        // FUNCTION FOR THE 6TH BUTTON!
        if (best_connection === true) {
            disableLoadMoreButton(true);
            disableFilterButton(true);
            notifications("Retrieving Location...", "success", "🌎")
            // Ask for the user's location
            const userLocation = await getUserLocation();
            if (!userLocation) {
                notifications('Error: Unable to fetch your location. Please enable location access.', 'error', '⚠️');
                disableFilterButton(false);
                return;
            }

            // Fetch 50 servers
            const servers = await fetchPublicServers(gameId, 50);
            if (servers.length === 0) {
                notifications('Error: No servers found. Please try again later.', 'error', '⚠️');
                disableFilterButton(false);
                return;
            }

            // Calculate distances and find the closest server
            let closestServer = null;
            let minDistance = Infinity;
            let closestServerLocation = null;

            for (const server of servers) {
                const {
                    id: serverId,
                    maxPlayers,
                    playing
                } = server;

                // Skip full servers
                if (playing >= maxPlayers) {
                    continue;
                }

                try {
                    // Fetch server location
                    const location = await fetchServerDetails(gameId, serverId);

                    // Calculate distance
                    const distance = calculateDistance(
                        userLocation.latitude,
                        userLocation.longitude,
                        location.latitude,
                        location.longitude
                    );

                    // Update closest server
                    if (distance < minDistance) {
                        minDistance = distance;
                        closestServer = server;
                        closestServerLocation = location;
                    }
                } catch (error) {
                    console.error(`Error fetching details for server ${serverId}:`, error);
                    // Skip this server and continue with the next one
                    continue;
                }
            }

            if (closestServer) {
                // Automatically join the closest server
                showLoadingOverlay();
                Roblox.GameLauncher.joinGameInstance(gameId, closestServer.id);
                notifications(`Joining nearest server!
            Server ID: ${closestServer.id}
            Distance: ${(minDistance / 1.609).toFixed(2)} miles | ${minDistance.toFixed(2)} km
            Location (Country): ${closestServerLocation.country.name}.`, 'success', '🚀');

                disableFilterButton(false);
                Loadingbar(false);
            } else {
                notifications('No valid servers found. Please try again later after refreshing the webpage. Filter button disabled.', 'error', '⚠️');
                Loadingbar(false);
            }

            return; // Exit the function after joining the best server
        }

        // Rest of the original function (for non-"Best Connection" mode)
        if (!serverListContainer) {
            console.error("Server list container not found!");
            const popup = showPopup();
            notifications('Error: No Servers found. There is nobody playing this game. :(', 'warning', '❗');
            return;
        }

        const messageElement = showMessage("Filtering servers, please wait...");

        try {
            const servers = await fetchPublicServers(gameId, totalLimit);
            const totalServers = servers.length;
            let skippedServers = 0;

            messageElement.textContent = `Filtering servers, please do not leave this page as it slows down the search...\n${totalServers} servers found, 0 servers loaded.`;
            notifications(`Please do not leave this page as it slows down the search. \nFound a total of ${totalServers} servers found.`, 'success', '👍');

            const serverDetails = [];
            for (let i = 0; i < servers.length; i++) {
                const server = servers[i];
                const {
                    id: serverId,
                    maxPlayers,
                    playing,
                    ping,
                    fps,
                    playerTokens
                } = server;

                let location;
                try {
                    location = await fetchServerDetails(gameId, serverId);
                } catch (error) {
                    if (error === 'purchase_required') {
                        messageElement.textContent = "Cannot access server data because you haven't purchased the game.";
                        notifications('Error: Cannot access server data because you haven\'t purchased the game.', 'error', '⚠️');
                        Loadingbar(false); // disable loading bar
                        return;
                    } else {
                        console.error(error);
                        location = {
                            city: "Unknown",
                            country: {
                                name: "Unknown",
                                code: "??"
                            }
                        };
                    }
                }

                if (location.city === "Unknown" || playing >= maxPlayers) {
                    console.log(`Skipping server ${serverId} because it is full or location is unknown.`);
                    skippedServers++;
                    continue;
                }

                // Fetch player thumbnails
                const playerThumbnails = playerTokens && playerTokens.length > 0 ? await fetchPlayerThumbnails_servers(playerTokens) : [];

                serverDetails.push({
                    server,
                    location,
                    playerThumbnails
                });

                messageElement.textContent = `Filtering servers, please do not leave this page...\n${totalServers} servers found, ${i + 1} server locations found`;
            }

            if (serverDetails.length === 0) {
                messageElement.textContent = "No servers found. Please try again with an increase in the number of servers to search for.";
                notifications('Error: No servers found. Please try again with an increase in the number of servers to search for.', 'error', '⚠️');
                Loadingbar(false); // disable loading bar
                return;
            }

            const loadedServers = totalServers - skippedServers;
            notifications(`Filtering complete!\n${totalServers} servers found, ${loadedServers} servers loaded, ${skippedServers} servers skipped (full).`, 'success', '👍');
            messageElement.textContent = `Filtering complete!\n${totalServers} servers found, ${loadedServers} servers loaded, ${skippedServers} servers skipped (full).`;
            Loadingbar(false); // disable loading bar

            // Add filter dropdowns
            const filterContainer = createFilterDropdowns(serverDetails);
            serverListContainer.parentNode.insertBefore(filterContainer, serverListContainer);

            // Style the server list container to use a grid layout
            serverListContainer.style.display = "grid";
            serverListContainer.style.gridTemplateColumns = "repeat(4, 1fr)"; // 4 columns
            serverListContainer.style.gap = "16px"; // Gap between cards

            const displayFilteredServers = (country, city) => {
                serverListContainer.innerHTML = "";

                const filteredServers = filterServers(serverDetails, country, city);
                const sortedServers = sortServersByPing(filteredServers);

                sortedServers.forEach(({
                    server,
                    location,
                    playerThumbnails
                }) => {
                    const serverCard = document.createElement("li");
                    serverCard.className = "rbx-game-server-item col-md-3 col-sm-4 col-xs-6";

                    // Set consistent width and height for the server card
                    serverCard.style.width = "100%"; // Take up full width of the grid cell
                    serverCard.style.minHeight = "400px"; // Set a minimum height
                    serverCard.style.display = "flex";
                    serverCard.style.flexDirection = "column";
                    serverCard.style.justifyContent = "space-between";
                    serverCard.style.boxSizing = "border-box"; // Include padding and border in dimensions

                    // Remove any conflicting outline (e.g., from .highlighted class)
                    serverCard.style.outline = 'none';

                    // Determine the group and set the outline color
                    let outlineColor;
                    if (server.ping < 100) {
                        outlineColor = 'green'; // Best ping
                    } else if (server.ping < 200) {
                        outlineColor = 'orange'; // Medium ping
                    } else {
                        outlineColor = 'red'; // Bad ping
                    }

                    // Apply the new outline and outlineOffset
                    serverCard.style.outline = `3px solid ${outlineColor}`;
                    serverCard.style.outlineOffset = '-6px';
                    serverCard.style.padding = '6px';
                    serverCard.style.borderRadius = '8px';

                    // Create a container for player thumbnails
                    const thumbnailsContainer = document.createElement("div");
                    thumbnailsContainer.className = "player-thumbnails-container";
                    thumbnailsContainer.style.display = "grid";
                    thumbnailsContainer.style.gridTemplateColumns = "repeat(3, 60px)"; // 3 columns
                    thumbnailsContainer.style.gridTemplateRows = "repeat(2, 60px)"; // 2 rows
                    thumbnailsContainer.style.gap = "5px";
                    thumbnailsContainer.style.marginBottom = "10px";

                    // Add player thumbnails to the container (max 5)
                    const maxThumbnails = 5;
                    const displayedThumbnails = playerThumbnails.slice(0, maxThumbnails);
                    displayedThumbnails.forEach(thumb => {
                        if (thumb && thumb.imageUrl) {
                            const img = document.createElement("img");
                            img.src = thumb.imageUrl;
                            img.className = "avatar-card-image";
                            img.style.width = "60px";
                            img.style.height = "60px";
                            img.style.borderRadius = "50%";
                            thumbnailsContainer.appendChild(img);
                        }
                    });

                    // Add a placeholder for hidden players
                    const hiddenPlayers = server.playing - displayedThumbnails.length;
                    if (hiddenPlayers > 0) {
                        const placeholder = document.createElement("div");
                        placeholder.className = "avatar-card-image";
                        placeholder.style.width = "60px";
                        placeholder.style.height = "60px";
                        placeholder.style.borderRadius = "50%";
                        placeholder.style.backgroundColor = "#BDBEBE80"; // Dark gray background
                        placeholder.style.display = "flex";
                        placeholder.style.alignItems = "center";
                        placeholder.style.justifyContent = "center";
                        placeholder.style.color = "#fff"; // White text
                        placeholder.style.fontSize = "14px";
                        placeholder.textContent = `+${hiddenPlayers}`;
                        thumbnailsContainer.appendChild(placeholder);
                    }

                    // Server card content
                    const cardItem = document.createElement("div");
                    cardItem.className = "card-item";
                    cardItem.style.display = "flex";
                    cardItem.style.flexDirection = "column";
                    cardItem.style.justifyContent = "space-between";
                    cardItem.style.height = "100%"; // Ensure the card content takes up the full height

                    cardItem.innerHTML = `
                <!-- Player thumbnails at the top -->
                ${thumbnailsContainer.outerHTML}
                <div class="rbx-game-server-details game-server-details">
                    <div class="text-info rbx-game-status rbx-game-server-status text-overflow">
                        ${server.playing} of ${server.maxPlayers} people max
                    </div>
                    <div class="server-player-count-gauge border">
                        <div class="gauge-inner-bar border" style="width: ${(server.playing / server.maxPlayers) * 100}%;"></div>
                    </div>
                    <span data-placeid="${gameId}">
                        <button type="button" class="btn-full-width btn-control-xs rbx-game-server-join game-server-join-btn btn-primary-md btn-min-width">Join</button>
                    </span>
                </div>
                <!-- Generated info (ping, location, FPS) at the bottom -->
                <div style="margin-top: 10px; text-align: center;">
                    <div class="ping-info">Ping: ${server.ping}ms</div>
                    <div class="location-info">${location.city}, ${location.country.name}</div>
                    <div class="fps-info">FPS: ${Math.round(server.fps)}</div>
                </div>
            `;

                    const joinButton = cardItem.querySelector(".rbx-game-server-join");
                    joinButton.addEventListener("click", () => {
                        console.log(`Roblox.GameLauncher.joinGameInstance(${gameId}, "${server.id}")`);
                        showLoadingOverlay();
                        Roblox.GameLauncher.joinGameInstance(gameId, server.id); // join server
                    });

                    const container = adjustJoinButtonContainer(joinButton);
                    const inviteButton = createInviteButton(gameId, server.id);
                    container.appendChild(inviteButton);

                    serverCard.appendChild(cardItem);
                    serverListContainer.appendChild(serverCard);
                });
            };

            // Add event listeners to dropdowns
            const countryFilter = document.getElementById('countryFilter');
            const cityFilter = document.getElementById('cityFilter');

            countryFilter.addEventListener('change', () => {
                displayFilteredServers(countryFilter.value, cityFilter.value);
            });

            cityFilter.addEventListener('change', () => {
                displayFilteredServers(countryFilter.value, cityFilter.value);
            });

            // Display all servers initially
            displayFilteredServers("", "");

            setTimeout(() => {
                hideMessage();
            }, 3000);
        } catch (error) {
            console.error("Error rebuilding server list:", error);
            notifications('An error occurred while filtering servers. Please try again.', 'error', '😔');
            messageElement.textContent = "An error occurred while filtering servers. Please try again.";
            Loadingbar(false); // enable loading bar
        } finally {
            Loadingbar(false); // omg bruh i just realzed i could put this here but now im too lazy to thorugh the code to remove all of the loading bar disabl functions
        }
    }

    // Function to extract the game ID from the URL
    function extractGameId() {
        const url = window.location.href;
        const match = url.match(/roblox\.com\/games\/(\d+)/);

        if (match && match[1]) {
            return match[1]; // Return the game ID
        }
        return null; // Return null if no game ID is found
    }

    // Log the game ID to the console
    const gameId = extractGameId();

    // Function to create and append the Invite button
    function createInviteButton(placeId, serverId) { // too lazy to comment this function tbh just ready the name
        const inviteButton = document.createElement('button');
        inviteButton.textContent = 'Invite';
        inviteButton.className = 'btn-control-xs btn-primary-md btn-min-width btn-full-width';
        inviteButton.style.width = '25%';
        inviteButton.style.marginLeft = '5px';

        inviteButton.style.padding = '4px 8px';
        inviteButton.style.fontSize = '12px';
        inviteButton.style.borderRadius = '8px';
        inviteButton.style.backgroundColor = '#393b3d';
        inviteButton.style.borderColor = '#bdbebe';
        inviteButton.style.color = '#bdbebe';
        inviteButton.style.cursor = 'pointer';
        inviteButton.style.fontWeight = '500';
        inviteButton.style.textAlign = 'center';
        inviteButton.style.whiteSpace = 'nowrap';
        inviteButton.style.verticalAlign = 'middle';
        inviteButton.style.lineHeight = '100%';
        inviteButton.style.fontFamily = 'Builder Sans, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif';
        inviteButton.style.textRendering = 'auto';
        inviteButton.style.webkitFontSmoothing = 'antialiased';
        inviteButton.style.mozOsxFontSmoothing = 'grayscale';

        inviteButton.addEventListener('mouseenter', () => {
            inviteButton.style.color = '#ffffff';
            inviteButton.style.borderColor = '#ffffff';
        });
        inviteButton.addEventListener('mouseleave', () => {
            inviteButton.style.color = '#bdbebe';
            inviteButton.style.borderColor = '#bdbebe';
        });

        inviteButton.addEventListener('click', () => {
            const inviteLink = `https://oqarshi.github.io/Invite/?placeid=${placeId}&serverid=${serverId}`;
            navigator.clipboard.writeText(inviteLink).then(() => {
                console.log(`Invite link copied to clipboard: ${inviteLink}`);
                notifications('Success! Invite link copied to clipboard!', 'success', '🎉');
            }).catch(() => {
                console.error('Failed to copy invite link.');
                notifications('Error: Failed to copy invite link', 'error', '😔');
            });
        });

        return inviteButton;
    }

    // Function to adjust the Join button and its container
    function adjustJoinButtonContainer(joinButton) {
        const container = document.createElement('div');
        container.style.display = 'flex';
        container.style.width = '100%';

        joinButton.style.width = '75%';

        joinButton.parentNode.insertBefore(container, joinButton);
        container.appendChild(joinButton);

        return container;
    }




    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 6th button.

    *********************************************************************************************************************************************************************************************************************************************/




    function calculateDistance(lat1, lon1, lat2, lon2) {
        const R = 6371; // Radius of the Earth in kilometers
        const dLat = (lat2 - lat1) * (Math.PI / 180);
        const dLon = (lon2 - lon1) * (Math.PI / 180);
        const a =
            Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) *
            Math.sin(dLon / 2) * Math.sin(dLon / 2);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c; // Distance in kilometers
    }


    function getUserLocation() {
        return new Promise((resolve, reject) => {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(
                    (position) => {
                        notifications('We successfully detected your location.\nConnecting you to a nearby server in about 15-20 seconds. 😊', 'success', '🌎');
                        disableLoadMoreButton(true);
                        disableFilterButton(true);
                        Loadingbar(true);
                        resolve({
                            latitude: position.coords.latitude,
                            longitude: position.coords.longitude,
                        });
                    },
                    (error) => {
                        console.error('Error getting user location:', error);
                        disableLoadMoreButton(true);
                        disableFilterButton(true);
                        Loadingbar(true);
                        notifications('Error getting user location.\nPlease enable location permissions for this website.\nAssuming your location is New York in the United States.', 'error', '⚠️');
                        // Fallback to a default location (e.g., New York City)
                        resolve({
                            latitude: 40.7128, // Default latitude (New York City)
                            longitude: -74.0060, // Default longitude (New York City)
                        });
                    }
                );
            } else {
                console.error('Geolocation is not supported by this browser.');
                disableLoadMoreButton(true);
                disableFilterButton(true);
                Loadingbar(true);
                notifications('Error getting user location.\nThis browser doesent support location.\nAssuming your location is New York in the United States.', 'error', '⚠️');
                // Fallback to a default location (e.g., New York City)
                resolve({
                    latitude: 40.7128, // Default latitude (New York City)
                    longitude: -74.0060, // Default longitude (New York City)
                });
            }
        });
    }



    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 7th button.

    *********************************************************************************************************************************************************************************************************************************************/
    async function auto_join_small_server() {
        // Disable the "Load More" button and show the loading bar
        Loadingbar(true);
        disableFilterButton(true);
        disableLoadMoreButton();

        // Get the game ID from the URL
        const gameId = window.location.pathname.split('/')[2];

        // Retry mechanism for 429 errors
        let retries = 3; // Number of retries
        let success = false;

        while (retries > 0 && !success) {
            try {
                // Fetch server data using GM_xmlhttpRequest
                const data = await new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `https://games.roblox.com/v1/games/${gameId}/servers/public?sortOrder=1&excludeFullGames=true&limit=100`,
                        onload: function(response) {
                            if (response.status === 429) {
                                reject('429: Too Many Requests');
                            } else if (response.status >= 200 && response.status < 300) {
                                resolve(JSON.parse(response.responseText));
                            } else {
                                reject(`HTTP error: ${response.status}`);
                            }
                        },
                        onerror: function(error) {
                            reject(error);
                        },
                    });
                });

                // Find the server with the lowest player count
                let minPlayers = Infinity;
                let targetServer = null;

                for (const server of data.data) {
                    if (server.playing < minPlayers) {
                        minPlayers = server.playing;
                        targetServer = server;
                    }
                }

                if (targetServer) {
                    // Join the server with the lowest player count
                    showLoadingOverlay();
                    Roblox.GameLauncher.joinGameInstance(gameId, targetServer.id);
                    notifications(`Joining a server with ${targetServer.playing} player(s).`, 'success', '🚀');
                    success = true; // Mark as successful
                } else {
                    notifications('No available servers found.', 'error', '⚠️');
                    break; // Exit the loop if no servers are found
                }
            } catch (error) {
                if (error === '429: Too Many Requests' && retries > 0) {
                    console.log('Rate limited. Retrying in 10 seconds...');
                    notifications('Rate limited. Retrying in 10 seconds...', 'warning', '⏳');
                    await delay(10000); // Wait 10 seconds before retrying
                    retries--;
                } else {
                    console.error('Error fetching server data:', error);
                    notifications('Error: Failed to fetch server data. Please try again later.', 'error', '⚠️');
                    break; // Exit the loop if it's not a 429 error or no retries left
                }
            }
        }

        // Hide the loading bar and enable the filter button
        Loadingbar(false);
        disableFilterButton(false);
    }
    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 8th button.

    *********************************************************************************************************************************************************************************************************************************************/

    function find_user_server_tab() {
        // Create the overlay (backdrop)
        const overlay = document.createElement('div');
        overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 9999;
        opacity: 0;
        transition: opacity 0.3s ease;
    `;
        document.body.appendChild(overlay);

        // Create the popup container
        const popup = document.createElement('div');
        popup.className = 'player-count-popup';
        popup.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: rgb(30, 32, 34);
        padding: 20px;
        border-radius: 10px;
        z-index: 10000;
        box-shadow: 0 0 15px rgba(0, 0, 0, 0.7);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 15px;
        width: 300px;
        opacity: 0;
        transition: opacity 0.3s ease, transform 0.3s ease;
    `;

        // Add a close button in the top-right corner (bigger size)
        const closeButton = document.createElement('button');
        closeButton.innerHTML = '&times;'; // Using '×' for the close icon
        closeButton.style.cssText = `
        position: absolute;
        top: 10px;
        right: 10px;
        background: transparent;
        border: none;
        color: #ffffff;
        font-size: 24px; /* Increased font size */
        cursor: pointer;
        width: 36px; /* Increased size */
        height: 36px; /* Increased size */
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: background-color 0.3s ease, color 0.3s ease;
    `;
        closeButton.addEventListener('mouseenter', () => {
            closeButton.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
            closeButton.style.color = '#ff4444';
        });
        closeButton.addEventListener('mouseleave', () => {
            closeButton.style.backgroundColor = 'transparent';
            closeButton.style.color = '#ffffff';
        });

        // Add a title
        const title = document.createElement('h3');
        title.textContent = 'Enter Username';
        title.style.cssText = `
        color: white;
        margin: 0;
        font-size: 18px;
        font-weight: 500;
    `;
        popup.appendChild(title);

        // Add an input box for the username
        const usernameInput = document.createElement('input');
        usernameInput.type = 'text';
        usernameInput.placeholder = 'Username';
        usernameInput.style.cssText = `
        width: 80%;
        padding: 8px;
        font-size: 16px;
        border: 1px solid #444;
        border-radius: 5px;
        background-color: #1a1a1a;
        color: white;
        outline: none;
    `;
        popup.appendChild(usernameInput);

        // Add a confirm button with dark, blackish style
        const confirmButton = document.createElement('button');
        confirmButton.textContent = 'Confirm';
        confirmButton.style.cssText = `
        padding: 8px 20px;
        font-size: 16px;
        background-color: #1a1a1a; /* Dark blackish color */
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        transition: background-color 0.3s ease, transform 0.2s ease;
    `;
        confirmButton.addEventListener('mouseenter', () => {
            confirmButton.style.backgroundColor = '#333'; /* Slightly lighter on hover */
            confirmButton.style.transform = 'scale(1.05)';
        });
        confirmButton.addEventListener('mouseleave', () => {
            confirmButton.style.backgroundColor = '#1a1a1a';
            confirmButton.style.transform = 'scale(1)';
        });

        // Handle confirm button click
        confirmButton.addEventListener('click', () => {
            const username = usernameInput.value.trim();
            if (username) {
                // Check if the username is between 3 and 20 characters
                if (username.length >= 3 && username.length <= 20) {
                    // Call the function with the username
                    FindPlayerGameServer(username);
                    notifications("Searching for the user's server...", "info", "");
                    fadeOutAndRemove_7th(popup, overlay);
                } else {
                    // Show an error notification if the username is not within the required length
                    notifications('Error: Username must be between 3 and 20 characters', 'error', '⚠️');
                }
            } else {
                notifications('Error: Please enter a username', 'error', '⚠️');
            }
        });

        // Append the popup to the body
        document.body.appendChild(popup);

        // Fade in the overlay and popup
        setTimeout(() => {
            overlay.style.opacity = '1';
            popup.style.opacity = '1';
            popup.style.transform = 'translate(-50%, -50%) scale(1)';
        }, 10);

        /*******************************************************
            name of function: fadeOutAndRemove_7th
            description: Fades out and removes the popup and overlay.
        *******************************************************/
        function fadeOutAndRemove_7th(popup, overlay) {
            popup.style.opacity = '0';
            popup.style.transform = 'translate(-50%, -50%) scale(0.9)';
            overlay.style.opacity = '0';
            setTimeout(() => {
                popup.remove();
                overlay.remove();
            }, 300); // Match the duration of the transition
        }

        // Close the popup when clicking outside
        overlay.addEventListener('click', () => {
            fadeOutAndRemove_7th(popup, overlay);
        });

        // Close the popup when the close button is clicked
        closeButton.addEventListener('click', () => {
            fadeOutAndRemove_7th(popup, overlay);
        });

        popup.appendChild(confirmButton);
        popup.appendChild(closeButton);
    }


    async function FindPlayerGameServer(playerName) {
        disableLoadMoreButton();
        Loadingbar(true);
        disableFilterButton(true);
        const wait = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));

        const fetchData = async (url, options = {}) => {
            if (!options.headers) options.headers = {};
            return fetch(url, options)
                .then(response => response.json())
                .catch(error => console.error("Fetch error:", error));
        };

        const fetchDataGM = (url, options = {}) => {
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: options.method || 'GET',
                    url: url,
                    headers: options.headers || {},
                    anonymous: true, // Prevents sending cookies
                    nocache: true, // Prevents caching
                    onload: function(response) {
                        try {
                            const parsedData = JSON.parse(response.responseText);
                            resolve(parsedData);
                        } catch (error) {
                            console.error("JSON parsing error:", error);
                            reject(error);
                        }
                    },
                    onerror: function(error) {
                        console.error("Request error:", error);
                        reject(error);
                    }
                });
            });
        };

        console.log(`Initiating search for player: ${playerName}`);

        const gameId = window.location.href.split("/")[4];
        console.log(`Game ID identified: ${gameId}`);

        let userId;

        try {
            console.log(`Retrieving user ID for player: ${playerName}`);
            const userProfile = await fetch(`https://www.roblox.com/users/profile?username=${playerName}`);
            if (!userProfile.ok) {
                notifications("Error: User does not exist on Roblox!", "error", "⚠️");
                Loadingbar(false);
                disableFilterButton(false);
                throw `Player "${playerName}" not found`;
            }
            userId = userProfile.url.match(/\d+/)[0];
            console.log(`User ID retrieved: ${userId}`);
        } catch (error) {
            console.error("Error:", error);
            return `Error: ${error}`;
        }

        console.log(`Fetching avatar thumbnail for user ID: ${userId}`);
        const avatarThumbnail = (await fetchData(`https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds=${userId}&format=Png&size=150x150`)).data[0].imageUrl;
        console.log(`Avatar thumbnail URL: ${avatarThumbnail}`);

        let pageCursor = null;
        let playerFound = false;
        let totalServersChecked = 0;
        let startTime = Date.now();

        // Show the search progress popup with the player's thumbnail
        const progressPopup = showSearchProgressPopup(avatarThumbnail);

        while (true) {
            let apiUrl = `https://games.roblox.com/v1/games/${gameId}/servers/0?limit=100`;
            if (pageCursor) apiUrl += "&cursor=" + pageCursor;

            console.log(`Accessing servers with URL: ${apiUrl}`);
            const serverList = await fetchDataGM(apiUrl, {
                credentials: "omit"
            }).catch(() => null);

            if (serverList && serverList.data) {
                console.log(`Discovered ${serverList.data.length} servers in this set.`);
                for (let index = 0; index < serverList.data.length; index++) {
                    const server = serverList.data[index];
                    if (!playerFound) {
                        totalServersChecked++;

                        // Calculate time elapsed
                        const timeElapsed = Math.floor((Date.now() - startTime) / 1000);

                        // Update the progress popup
                        updateSearchProgressPopup(
                            progressPopup,
                            totalServersChecked,
                            timeElapsed
                        );

                        if (server.playerTokens.length === 0) {
                            console.log(`Server ${index + 1} is empty. Proceeding to next server.`);
                            continue;
                        }

                        console.log(`Inspecting server ${index + 1} hosting ${server.playing} players...`);

                        let thumbnailData;
                        while (true) {
                            let requestBody = [];

                            const generateRequestEntry = (playerToken) => ({
                                requestId: `0:${playerToken}:AvatarHeadshot:150x150:png:regular`,
                                type: "AvatarHeadShot",
                                targetId: 0,
                                token: playerToken,
                                format: "png",
                                size: "150x150"
                            });

                            server.playerTokens.forEach(token => {
                                requestBody.push(generateRequestEntry(token));
                            });

                            try {
                                console.log(`Fetching thumbnails for ${server.playerTokens.length} player(s)...`);
                                thumbnailData = await fetchData("https://thumbnails.roblox.com/v1/batch", {
                                    method: "POST",
                                    headers: {
                                        "Content-Type": "application/json",
                                        Accept: "application/json"
                                    },
                                    body: JSON.stringify(requestBody)
                                });
                                console.log("Thumbnail Data Response:", thumbnailData);
                                break;
                            } catch (error) {
                                console.error("Thumbnail retrieval error:", error);
                                await wait(1000);
                            }
                        }

                        if (!thumbnailData.data) {
                            console.log("No thumbnail data available. Moving to next server.");
                            continue;
                        }

                        for (let thumbIndex = 0; thumbIndex < thumbnailData.data.length; thumbIndex++) {
                            const thumbnail = thumbnailData.data[thumbIndex];
                            if (thumbnail && thumbnail.imageUrl === avatarThumbnail) {
                                playerFound = true;
                                console.log(`Player located in server ${index + 1}!`);
                                notifications("Found User's Server! Joining Server...", "success", "🚀");
                                showLoadingOverlay();
                                Roblox.GameLauncher.joinGameInstance(gameId, server.id);
                                fadeOutAndRemove_7th_progress(progressPopup.popup, progressPopup.overlay);
                                Loadingbar(false);
                                disableFilterButton(false);
                                return {
                                    gameId,
                                    serverId: server.id,
                                    currentPlayers: server.playing,
                                    maximumPlayers: server.maxPlayers,
                                };
                            }
                        }
                    } else {
                        break;
                    }
                }

                pageCursor = serverList.nextPageCursor;
                if (!pageCursor || playerFound) break;
                else {
                    console.log("Pausing for 1 seconds before next server batch...");
                    await wait(1);
                }
            } else {
                console.log("Server fetch failed. Retrying in 10 seconds...");
                notifications("Got rate limited. Waiting 10 seconds...", "info", "❗")
                await wait(10000);
            }
        }

        if (!playerFound) {
            // Wait for 2 seconds before calling another function
            setTimeout(() => {
                fadeOutAndRemove_7th_progress(progressPopup.popup, progressPopup.overlay);
                notifications("User not found playing this game!", "error", "⚠️");
            }, 2000); // 2000 milliseconds = 2 seconds

            // Existing logic (unchanged)
            Loadingbar(false);
            disableFilterButton(false);
            console.log(`Player not found in the searched servers (${totalServersChecked} servers checked)`);
            // Update the progress popup with the final count
            updateSearchProgressPopup(
                progressPopup,
                totalServersChecked,
                Math.floor((Date.now() - startTime) / 1000),
                true
            );
            return `Player not found in the searched servers (${totalServersChecked} servers checked)`;
        }
    }

    /*******************************************************
        name of function: showSearchProgressPopup
        description: Creates and displays a popup showing the search progress.
    *******************************************************/
    function showSearchProgressPopup(avatarThumbnail) {
        // Create the overlay (backdrop)
        const overlay = document.createElement('div');
        overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 9999;
        opacity: 0;
        transition: opacity 0.3s ease;
    `;
        document.body.appendChild(overlay);

        // Create the popup container
        const popup = document.createElement('div');
        popup.className = 'search-progress-popup';
        popup.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: rgb(30, 32, 34);
        padding: 20px;
        border-radius: 10px;
        z-index: 10000; /* Higher than overlay */
        box-shadow: 0 0 15px rgba(0, 0, 0, 0.7);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 15px;
        width: 300px;
        opacity: 0; /* Start invisible */
        transition: opacity 0.3s ease, transform 0.3s ease;
    `;

        // Add a title
        const title = document.createElement('h3');
        title.textContent = 'Searching for Player...';
        title.style.cssText = `
        color: white;
        margin: 0;
        font-size: 18px;
        font-weight: 500;
    `;
        popup.appendChild(title);

        // Add the player's thumbnail
        const thumbnail = document.createElement('img');
        thumbnail.src = avatarThumbnail;
        thumbnail.style.cssText = `
        width: 100px;
        height: 100px;
        border-radius: 50%;
        object-fit: cover;
    `;
        popup.appendChild(thumbnail);

        // Add a progress text for servers searched
        const serversSearchedText = document.createElement('p');
        serversSearchedText.textContent = 'Servers searched: 0';
        serversSearchedText.style.cssText = `
        color: white;
        margin: 0;
        font-size: 16px;
    `;
        popup.appendChild(serversSearchedText);

        // Add a text for time elapsed
        const timeElapsedText = document.createElement('p');
        timeElapsedText.textContent = 'Time elapsed: 0s';
        timeElapsedText.style.cssText = `
        color: white;
        margin: 0;
        font-size: 16px;
    `;
        popup.appendChild(timeElapsedText);

        // Append the popup to the body
        document.body.appendChild(popup);

        // Fade in the overlay and popup
        setTimeout(() => {
            overlay.style.opacity = '1';
            popup.style.opacity = '1';
            popup.style.transform = 'translate(-50%, -50%) scale(1)';
        }, 10);

        return {
            popup,
            overlay,
            serversSearchedText,
            timeElapsedText,
        };
    }

    /*******************************************************
        name of function: updateSearchProgressPopup
        description: Updates the search progress popup with the current count.
    *******************************************************/
    function updateSearchProgressPopup(
        progressPopup,
        totalServersChecked,
        timeElapsed,
        isFinal = false
    ) {
        progressPopup.serversSearchedText.textContent = `Servers searched: ${totalServersChecked}`;
        progressPopup.timeElapsedText.textContent = `Time elapsed: ${timeElapsed}s`;

        if (isFinal) {
            progressPopup.serversSearchedText.textContent += ' (Search completed)';
        }
    }

    /*******************************************************
        name of function: fadeOutAndRemove
        description: Fades out and removes the popup and overlay.
    *******************************************************/
    function fadeOutAndRemove_7th_progress(popup, overlay) {
        popup.style.opacity = '0';
        popup.style.transform = 'translate(-50%, -50%) scale(0.9)';
        overlay.style.opacity = '0';
        setTimeout(() => {
            popup.remove();
            overlay.remove();
        }, 300); // Match the duration of the transition
    }

    /*********************************************************************************************************************************************************************************************************************************************
                                                             Functions for the 9th button.

    *********************************************************************************************************************************************************************************************************************************************/

    function credits() {
        // Inject CSS for the popup
        const css = `
        .credits-popup {
            display: flex;
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            justify-content: center;
            align-items: center;
            z-index: 1000;
            opacity: 0;
            animation: fadeIn 0.5s ease-in-out forwards;
        }
        .credits-popup-content {
            background-color: #1e1e1e;
            padding: 30px;
            border-radius: 15px;
            width: 350px;
            max-width: 90%;
            box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5);
            text-align: center;
            position: relative;
            color: #fff;
            font-family: 'Arial', sans-serif;
        }
        .credits-popup-content h2 {
            margin-top: 0;
            color: #fff;
            font-size: 24px;
            font-weight: bold;
        }
        .credits-popup-content .version {
            font-size: 14px;
            color: #aaa;
            margin-bottom: 20px;
        }
        .credits-popup-content ul {
            list-style-type: none;
            padding: 0;
        }
        .credits-popup-content ul li {
            margin: 15px 0;
            color: #bbb;
            font-size: 16px;
        }
        .credits-popup-content a {
            color: #4da6ff;
            text-decoration: none;
            transition: color 0.3s ease;
        }
        .credits-popup-content a:hover {
            color: #6bb7ff;
            text-decoration: underline;
        }
        .credits-popup-close {
            position: absolute;
            top: 15px;
            right: 15px;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            color: #fff;
            transition: color 0.3s ease;
        }
        .credits-popup-close:hover {
            color: #ccc;
        }
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }
        @keyframes fadeOut {
            from { opacity: 1; }
            to { opacity: 0; }
        }
    `;

        // Add CSS to the document
        const style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        document.head.appendChild(style);

        // Create the popup HTML
        const popupHTML = `
        <div class="credits-popup">
            <div class="credits-popup-content">
                <span class="credits-popup-close">&times;</span>
                <div class="version">Rolocate: Version 27.2</div>
                <h2>Credits</h2>
                <p>This project was created by:</p>
                <ul>
                  <li>Developer: <a href="https://www.roblox.com/users/545334824/profile" target="_blank">Oqarshi</a></li>
                  <li>Special Thanks: <a href="https://chromewebstore.google.com/detail/btroblox-making-roblox-be/hbkpclpemjeibhioopcebchdmohaieln" target="_blank">Btroblox Team</a></li>
                  <li>Roblox Locate: <a href="http://greasyfork.icu/en/scripts/523727-rolocate" target="_blank">GreasyFork</a></li>
                  <li>Invite & FAQ Source Code: <a href="https://github.com/Oqarshi/Invite" target="_blank">GitHub</a></li>
                  <li>FAQ Website: <a href="https://oqarshi.github.io/Invite/rolocate/index.html" target="_blank">RoLocate FAQ</a></li>
                </ul>
            </div>
        </div>
    `;

        // Add the popup to the document
        const popupContainer = document.createElement('div');
        popupContainer.innerHTML = popupHTML;
        document.body.appendChild(popupContainer);

        // Add event listener to close the popup with animation
        const closeButton = document.querySelector('.credits-popup-close');
        const popup = document.querySelector('.credits-popup');
        closeButton.addEventListener('click', () => {
            popup.style.animation = 'fadeOut 0.5s ease-in-out forwards';
            setTimeout(() => {
                popup.remove(); // Remove the popup from the DOM after animation
            }, 500); // Match the duration of the fadeOut animation
        });
    }

    /*********************************************************************************************************************************************************************************************************************************************
                                                             End of: This is all the functions for the 8 buttons

    *********************************************************************************************************************************************************************************************************************************************/



    /*********************************************************************************************************************************************************************************************************************************************
                                                             The Universal Functions

    *********************************************************************************************************************************************************************************************************************************************/

function showFirstTimePopup() {
    if (!localStorage.getItem('firstTimeDownload')) {
        const css = `
        .first-time-popup {
            display: flex;
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.85);
            justify-content: center;
            align-items: center;
            z-index: 1000;
            opacity: 0;
            animation: fadeIn 0.5s ease-in-out forwards;
        }
        .first-time-popup-content {
            background-color: #222;
            padding: 35px;
            border-radius: 20px;
            width: 400px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
            text-align: center;
            position: relative;
            color: #fff;
            transform: scale(0.8);
            animation: scaleUpBounce 0.6s ease-out forwards;
        }
        .first-time-popup-content h1 {
            font-size: 32px;
            font-weight: bold;
            color: #4da6ff;
            margin-bottom: 10px;
        }
        .first-time-popup-content h2 {
            margin-top: 0;
            color: #4da6ff;
            font-size: 28px;
            margin-bottom: 15px;
            font-weight: bold;
        }
        .first-time-popup-content p {
            font-size: 16px;
            color: #ccc;
            margin-bottom: 20px;
        }
        .first-time-popup-content .countdown {
            font-size: 16px;
            color: #aaa;
            font-weight: bold;
        }
        .first-time-popup-content a {
            color: #4da6ff;
            text-decoration: none;
            font-weight: bold;
            transition: color 0.3s ease;
        }
        .first-time-popup-content a:hover {
            color: #80bfff;
            text-decoration: underline;
        }
        .first-time-popup-close {
            position: absolute;
            top: 15px;
            right: 15px;
            font-size: 26px;
            font-weight: bold;
            cursor: pointer;
            color: #fff;
            transition: opacity 0.3s ease;
            opacity: 0.5;
            pointer-events: none;
        }
        .first-time-popup-close.active {
            opacity: 1;
            pointer-events: auto;
        }
        .first-time-popup-close:hover {
            color: #ff4d4d;
        }
        .rolocate-logo {
            position: absolute;
            bottom: 5px;
            right: 10px;
            font-size: 5px;
            color: red;
            font-weight: bold;
        }
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }
        @keyframes fadeOut {
            from { opacity: 1; }
            to { opacity: 0; }
        }
        @keyframes scaleUpBounce {
            0% { transform: scale(0.8); }
            60% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }
        @keyframes scaleDown {
            from { transform: scale(1); }
            to { transform: scale(0.8); }
        }
    `;

        const style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        document.head.appendChild(style);

        const popupHTML = `
        <div class="first-time-popup">
            <div class="first-time-popup-content">
                <span class="first-time-popup-close">&times;</span>
                <h2>Welcome!</h2>
                <p>Check out the <a href="https://oqarshi.github.io/Invite/rolocate/index.html" target="_blank">FAQ website</a>. It can save you a lot of headaches! You can find it again in the credits menu.</p>
                <div class="countdown">Closing is enabled in <span id="countdown-timer"><strong>5</strong></span> seconds...</div>
                <div class="rolocate-logo">Rolocate</div>
            </div>
        </div>
    `;

        const popupContainer = document.createElement('div');
        popupContainer.innerHTML = popupHTML;
        document.body.appendChild(popupContainer);

        const closeButton = document.querySelector('.first-time-popup-close');
        const popup = document.querySelector('.first-time-popup');
        const countdownTimer = document.getElementById('countdown-timer');

        let countdown = 5;
        const countdownInterval = setInterval(() => {
            countdown--;
            countdownTimer.innerHTML = `<strong>${countdown}</strong>`;

            if (countdown <= 0) {
                clearInterval(countdownInterval);
                closeButton.classList.add('active');
                countdownTimer.innerHTML = "<strong>0</strong>";
            }
        }, 1000);

        closeButton.addEventListener('click', () => {
            popup.style.animation = 'fadeOut 0.5s ease-in-out forwards';
            document.querySelector('.first-time-popup-content').style.animation = 'scaleDown 0.5s ease-in-out forwards';
            setTimeout(() => {
                popup.remove();
            }, 500);
        });

        localStorage.setItem('firstTimeDownload', 'true');
    }
}






    /*******************************************************
    name of function: disableLoadMoreButton
    description: Disables the "Load More" button
    *******************************************************/
    function disableLoadMoreButton() {
        const loadMoreButton = document.querySelector('.rbx-running-games-load-more');
        if (loadMoreButton) {
            loadMoreButton.disabled = true;
            loadMoreButton.style.opacity = '0.5'; // Optional: Make the button look disabled
            loadMoreButton.style.cursor = 'not-allowed'; // Optional: Change cursor to indicate disabled state
            loadMoreButton.title = 'Disabled by Roblox Locator'; // Set tooltip text
        } else {
            console.warn('Load More button not found!');
            console.warn('Maybe moved by another extension!');
        }
    }



/*******************************************************
name of function: Loadingbar
description: Shows or hides a loading bar (now using pulsing boxes)
*******************************************************/
function Loadingbar(disable) {
    const serverListSection = document.querySelector('#rbx-running-games');
    const serverCardsContainer = document.querySelector('#rbx-game-server-item-container');

    if (disable) {
        // Remove server cards and disable the "Load More" button
        serverCardsContainer.innerHTML = '';

        // Create and display the loading boxes
        const loadingContainer = document.createElement('div');
        loadingContainer.id = 'loading-bar';
        loadingContainer.style.cssText = `
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 5px;
            margin-top: 10px;
        `;

        for (let i = 0; i < 3; i++) {
            const box = document.createElement('div');
            box.style.cssText = `
                width: 10px;
                height: 10px;
                background-color: white;
                margin: 0 5px;
                border-radius: 2px;
                animation: pulse 1.2s ${i * 0.2}s infinite;
            `;
            loadingContainer.appendChild(box);
        }

        // Add animation keyframes
        const styleSheet = document.createElement('style');
        styleSheet.textContent = `
            @keyframes pulse {
                0%, 100% { transform: scale(1); }
                50% { transform: scale(1.5); }
            }
        `;
        document.head.appendChild(styleSheet);

        serverListSection.appendChild(loadingContainer);
    } else {
        // Remove the loading bar
        const loadingBar = document.querySelector('#loading-bar');
        if (loadingBar) {
            loadingBar.remove();
        }
    }
}




    /*******************************************************
    name of function: fetchPlayerThumbnails
    description: Fetches player thumbnails for up to 5 players. Skips the batch if an error occurs.
    *******************************************************/
    async function fetchPlayerThumbnails(playerTokens) {
        // Limit to the first 5 player tokens
        const limitedTokens = playerTokens.slice(0, 5);

        const body = limitedTokens.map(token => ({
            requestId: `0:${token}:AvatarHeadshot:150x150:png:regular`,
            type: "AvatarHeadShot",
            targetId: 0,
            token,
            format: "png",
            size: "150x150",
        }));

        try {
            const response = await fetch("https://thumbnails.roblox.com/v1/batch", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    Accept: "application/json",
                },
                body: JSON.stringify(body),
            });

            // Check if the response is successful
            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }

            const data = await response.json();
            return data.data || []; // Return the data or an empty array if no data is present
        } catch (error) {
            console.error('Error fetching player thumbnails:', error);
            return []; // Return an empty array if an error occurs
        }
    }


    /*******************************************************
    name of function: disableFilterButton
    description: Disables or enables the filter button based on the input.
    *******************************************************/
    function disableFilterButton(disable) {
        const filterButton = document.querySelector('.RL-filter-button');
        const overlayId = 'filter-button-overlay';

        if (filterButton) {
            const parent = filterButton.parentElement;

            if (disable) {
                // Disable the filter button with an overlay
                filterButton.disabled = true;
                filterButton.style.opacity = '0.5'; // Make the button look disabled
                filterButton.style.cursor = 'not-allowed'; // Change cursor to indicate disabled state

                // Create an overlay if it doesn't exist
                let overlay = document.getElementById(overlayId);
                if (!overlay) {
                    overlay = document.createElement('div');
                    overlay.id = overlayId;
                    overlay.style.position = 'absolute';
                    overlay.style.top = '0';
                    overlay.style.left = '0';
                    overlay.style.width = '100%';
                    overlay.style.height = '100%';
                    overlay.style.backgroundColor = 'transparent'; // Transparent to maintain UI
                    overlay.style.zIndex = '9999'; // High z-index to cover the button
                    overlay.style.pointerEvents = 'all'; // Block all interactions
                    parent.style.position = 'relative'; // Ensure parent is positioned for absolute overlay
                    parent.appendChild(overlay);
                }
            } else {
                // Enable the filter button
                filterButton.disabled = false;
                filterButton.style.opacity = '1'; // Restore opacity
                filterButton.style.cursor = 'pointer'; // Restore cursor

                // Remove the overlay if it exists
                const overlay = document.getElementById(overlayId);
                if (overlay) {
                    overlay.remove();
                }
            }
        } else {
            console.warn('Filter button not found!');
        }
    }



    async function rbx_card(serverId, playerTokens, maxPlayers, playing, gameId) {
        // Fetch player thumbnails (up to 5)
        const thumbnails = await fetchPlayerThumbnails(playerTokens);

        // Create the server card container
        const cardItem = document.createElement('li');
        cardItem.className = 'rbx-game-server-item col-md-3 col-sm-4 col-xs-6';

        // Create the player thumbnails container
        const playerThumbnailsContainer = document.createElement('div');
        playerThumbnailsContainer.className = 'player-thumbnails-container';

        // Add player thumbnails to the container (up to 5)
        thumbnails.forEach(thumbnail => {
            const playerAvatar = document.createElement('span');
            playerAvatar.className = 'avatar avatar-headshot-md player-avatar';

            const thumbnailImage = document.createElement('span');
            thumbnailImage.className = 'thumbnail-2d-container avatar-card-image';

            const img = document.createElement('img');
            img.src = thumbnail.imageUrl;
            img.alt = '';
            img.title = '';

            thumbnailImage.appendChild(img);
            playerAvatar.appendChild(thumbnailImage);
            playerThumbnailsContainer.appendChild(playerAvatar);
        });

        // Add the 6th placeholder for remaining players
        if (playing > 5) {
            const remainingPlayers = playing - 5;
            const placeholder = document.createElement('span');
            placeholder.className = 'avatar avatar-headshot-md player-avatar hidden-players-placeholder';
            placeholder.textContent = `+${remainingPlayers}`;
            placeholder.style.cssText = `
        background-color: #7b7c7d; /* Gray background */
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%; /* Fully round */
        font-size: 16px; /* Larger font size */
        width: 60px; /* Larger width */
        height: 60px; /* Larger height */
        `;
            playerThumbnailsContainer.appendChild(placeholder);
        }

        // Create the server details container
        const serverDetails = document.createElement('div');
        serverDetails.className = 'rbx-game-server-details game-server-details';

        // Add server status (e.g., "15 of 15 people max")
        const serverStatus = document.createElement('div');
        serverStatus.className = 'text-info rbx-game-status rbx-game-server-status text-overflow';
        serverStatus.textContent = `${playing} of ${maxPlayers} people max`;
        serverDetails.appendChild(serverStatus);

        // Add the player count gauge
        const gaugeContainer = document.createElement('div');
        gaugeContainer.className = 'server-player-count-gauge border';

        const gaugeInner = document.createElement('div');
        gaugeInner.className = 'gauge-inner-bar border';
        gaugeInner.style.width = `${(playing / maxPlayers) * 100}%`;

        gaugeContainer.appendChild(gaugeInner);
        serverDetails.appendChild(gaugeContainer);

        // Create a container for the buttons
        const buttonContainer = document.createElement('div');
        buttonContainer.className = 'button-container';
        buttonContainer.style.cssText = `
        display: flex;
        gap: 8px; /* Space between buttons */
    `;

        // Add the "Join" button
        const joinButton = document.createElement('button');
        joinButton.type = 'button';
        joinButton.className = 'btn-full-width btn-control-xs rbx-game-server-join game-server-join-btn btn-primary-md btn-min-width';
        joinButton.textContent = 'Join';

        // Add click event to join the server
        joinButton.addEventListener('click', () => {
            showLoadingOverlay();
            Roblox.GameLauncher.joinGameInstance(gameId, serverId);
        });

        buttonContainer.appendChild(joinButton);

        // Add the "Invite" button
        const inviteButton = document.createElement('button');
        inviteButton.type = 'button';
        inviteButton.className = 'btn-full-width btn-control-xs rbx-game-server-invite game-server-invite-btn btn-secondary-md btn-min-width';
        inviteButton.textContent = 'Invite';

        // Add click event to log the invite link
        inviteButton.addEventListener('click', () => {
            const inviteLink = `https://oqarshi.github.io/Invite/?placeid=${gameId}&serverid=${serverId}`;
            //console.log('Copied invite link:', inviteLink);
            navigator.clipboard.writeText(inviteLink).then(() => {
                notifications('Success! Invite link copied to clipboard!', 'success', '🎉');
                //console.log('Invite link copied to clipboard');
            }).catch(err => {
                console.error('Failed to copy invite link:', err);
            });
        });

        buttonContainer.appendChild(inviteButton);

        // Add the button container to the server details
        serverDetails.appendChild(buttonContainer);

        // Assemble the card
        const cardContainer = document.createElement('div');
        cardContainer.className = 'card-item';
        cardContainer.appendChild(playerThumbnailsContainer);
        cardContainer.appendChild(serverDetails);

        cardItem.appendChild(cardContainer);

        // Add the card to the server list
        const serverList = document.querySelector('#rbx-game-server-item-container');
        serverList.appendChild(cardItem);
    }

    /*********************************************************************************************************************************************************************************************************************************************
                                                                 Modernized Notification Function with Gradient and Smooth Animations
    *********************************************************************************************************************************************************************************************************************************************/

    // Create the toast container
    const toastContainer = document.createElement('div');
    toastContainer.id = 'toast-container';
    document.body.appendChild(toastContainer);

    // Define toast styles
    const styles = `
#toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 99999;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.toast {
    position: relative;
    min-width: 300px;
    padding: 15px 20px;
    margin-bottom: 10px;
    border-radius: 12px;
    color: white;
    font-family: 'Arial', sans-serif;
    font-size: 14px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transform: translateX(100%);
    animation: slideIn 0.5s ease-out forwards, fadeOut 1s ease-out 7s forwards;
    display: flex;
    align-items: center;
    background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
    backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    overflow: hidden; /* Add this to clip the progress bar */
}

.toast.success {
    background: linear-gradient(135deg, rgba(76, 175, 80, 0.9), rgba(76, 175, 80, 0.7));
}

.toast.error {
    background: linear-gradient(135deg, rgba(244, 67, 54, 0.9), rgba(244, 67, 54, 0.7));
}

.toast.warning {
    background: linear-gradient(135deg, rgba(255, 152, 0, 0.9), rgba(255, 152, 0, 0.7));
}

.toast.info {
    background: linear-gradient(135deg, rgba(33, 150, 243, 0.9), rgba(33, 150, 243, 0.7));
}

.toast::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 4px;
    background-color: rgba(255, 255, 255, 0.3);
    animation: progressBar 8s linear forwards;
    border-radius: 0 0 12px 12px; /* Match the toast's border-radius */
}

.toast .icon {
    margin-right: 10px;
    font-size: 20px;
}

@keyframes slideIn {
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

@keyframes fadeOut {
    0% {
        opacity: 1;
        transform: translateX(0);
    }
    100% {
        opacity: 0;
        transform: translateX(100%);
    }
}

@keyframes progressBar {
    to {
        width: 0;
    }
}
`;

    // Add styles to the document
    const styleSheet = document.createElement('style');
    styleSheet.type = 'text/css';
    styleSheet.innerText = styles;
    document.head.appendChild(styleSheet);

    // Function to create a toast
    function notifications(message, type, icon) {
        const toast = document.createElement('div');
        toast.className = `toast ${type}`;

        // Add icon
        const iconElement = document.createElement('span');
        iconElement.className = 'icon';
        iconElement.innerHTML = icon;
        toast.appendChild(iconElement);

        // Add message
        const messageElement = document.createElement('span');
        messageElement.innerText = message;
        toast.appendChild(messageElement);

        toastContainer.appendChild(toast);

        // Remove the toast after the animation ends
        setTimeout(() => {
            toast.remove();
        }, 8000);
    }
    /*********************************************************************************************************************************************************************************************************************************************
                                                             End of function for the notification function

    *********************************************************************************************************************************************************************************************************************************************/


    /*********************************************************************************************************************************************************************************************************************************************
                                                             Launching Function

    *********************************************************************************************************************************************************************************************************************************************/

    function showLoadingOverlay() {
        // Create the content div (no overlay background)
        const content = document.createElement('div');
        content.style.position = 'fixed';
        content.style.top = 'calc(50% - 15px)'; // Move 15px higher
        content.style.left = '50%';
        content.style.transform = 'translate(-50%, -50%)'; // Center the box horizontally
        content.style.width = '400px';
        content.style.height = '250px';
        content.style.backgroundColor = '#1e1e1e'; // Dark background
        content.style.display = 'flex';
        content.style.flexDirection = 'column';
        content.style.justifyContent = 'center';
        content.style.alignItems = 'center';
        content.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.5)'; // Subtle shadow
        content.style.borderRadius = '12px'; // Slightly rounded corners
        content.style.zIndex = '1000000'; // z-index set to 1 million
        content.style.opacity = '0'; // Start with 0 opacity for fade-in
        content.style.transition = 'opacity 0.5s ease'; // Fade-in transition
        content.style.fontFamily = 'Arial, sans-serif'; // Clean font

        // Create the loading text
        const loadingText = document.createElement('p');
        loadingText.textContent = 'Joining Roblox Game...';
        loadingText.style.fontSize = '20px';
        loadingText.style.color = '#fff'; // White text for contrast
        loadingText.style.marginTop = '20px'; // Spacing between image and text
        loadingText.style.fontWeight = 'bold'; // Bold text

        // Create the base64 image
        const base64Image = document.createElement('img');
        base64Image.src = 'data:image/jpeg;base64,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';
        base64Image.style.width = '80px'; // Slightly larger image
        base64Image.style.height = '80px'; // Slightly larger image
        base64Image.style.borderRadius = '8px'; // Rounded corners for the image

        // Create the loading boxes container
        const loadingBoxes = document.createElement('div');
        loadingBoxes.style.display = 'flex';
        loadingBoxes.style.alignItems = 'center';
        loadingBoxes.style.justifyContent = 'center';
        loadingBoxes.style.marginTop = '15px'; // Spacing between text and boxes

        // Create the three loading boxes
        for (let i = 0; i < 3; i++) {
            const box = document.createElement('div');
            box.style.width = '10px';
            box.style.height = '10px';
            box.style.backgroundColor = '#fff'; // White boxes
            box.style.margin = '0 5px'; // Spacing between boxes
            box.style.borderRadius = '2px'; // Slightly rounded corners
            box.style.animation = `pulse 1.2s ${i * 0.2}s infinite`; // Animation with delay
            loadingBoxes.appendChild(box);
        }

        // Define the pulse animation using CSS
        const style = document.createElement('style');
        style.textContent = `
        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.5); }
        }
    `;
        document.head.appendChild(style); // Add the animation to the document

        // Append the image, text, and loading boxes to the content div
        content.appendChild(base64Image);
        content.appendChild(loadingText);
        content.appendChild(loadingBoxes);

        // Append the content div to the body
        document.body.appendChild(content);

        // Trigger fade-in animation
        setTimeout(() => {
            content.style.opacity = '1';
        }, 10); // Small delay to trigger the transition

        // Remove the content after 8 seconds with fade-out animation
        setTimeout(() => {
            content.style.opacity = '0'; // Fade out
            setTimeout(() => {
                document.body.removeChild(content); // Remove after fade-out completes
            }, 500); // Wait for the fade-out transition to finish
        }, 8000); // 8000 milliseconds = 8 seconds
    }


    /*********************************************************************************************************************************************************************************************************************************************
                                                             End of function for the launching function

    *********************************************************************************************************************************************************************************************************************************************/

    const serverRegionsByIp = {
        "128.116.0.0": { city: "Hong Kong", country: { name: "Hong Kong", code: "HK" }, latitude: 22.3193, longitude: 114.1694 },
        "128.116.1.0": { city: "Los Angeles", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 34.0522, longitude: -118.2437 },
        "128.116.2.0": { city: "Warsaw", country: { name: "Poland", code: "PL" }, region: { name: "Mazowieckie", code: "14" }, latitude: 52.2297, longitude: 21.0122 },
        "128.116.3.0": { city: "Warsaw", country: { name: "Poland", code: "PL" }, region: { name: "Mazowieckie", code: "14" }, latitude: 52.2297, longitude: 21.0122 },
        "128.116.4.0": { city: "Paris", country: { name: "France", code: "FR" }, region: { name: "Île-de-France", code: "IDF" }, latitude: 48.8566, longitude: 2.3522 },
        "128.116.5.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.6.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.7.0": { city: "Mumbai", country: { name: "India", code: "IN" }, region: { name: "Mahārāshtra", code: "MH" }, latitude: 19.0760, longitude: 72.8777 },
        "128.116.8.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.9.0": { city: "Mumbai", country: { name: "India", code: "IN" }, region: { name: "Mahārāshtra", code: "MH" }, latitude: 19.0760, longitude: 72.8777 },
        "128.116.10.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.11.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.12.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.13.0": { city: "Amsterdam", country: { name: "Netherlands", code: "NL" }, region: { name: "Noord-Holland", code: "NH" }, latitude: 52.3676, longitude: 4.9041 },
        "128.116.14.0": { city: "Hong Kong", country: { name: "Hong Kong", code: "HK" }, latitude: 22.3193, longitude: 114.1694 },
        "128.116.15.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.16.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.17.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.18.0": { city: "Miami", country: { name: "United States", code: "US" }, region: { name: "Florida", code: "FL" }, latitude: 25.7617, longitude: -80.1918 },
        "128.116.19.0": { city: "Paris", country: { name: "France", code: "FR" }, region: { name: "Île-de-France", code: "IDF" }, latitude: 48.8566, longitude: 2.3522 },
        "128.116.20.0": { city: "Paris", country: { name: "France", code: "FR" }, region: { name: "Île-de-France", code: "IDF" }, latitude: 48.8566, longitude: 2.3522 },
        "128.116.21.0": { city: "Amsterdam", country: { name: "Netherlands", code: "NL" }, region: { name: "Noord-Holland", code: "NH" }, latitude: 52.3676, longitude: 4.9041 },
        "128.116.22.0": { city: "Atlanta", country: { name: "United States", code: "US" }, region: { name: "Georgia", code: "GA" }, latitude: 33.7490, longitude: -84.3880 },
        "128.116.23.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.24.0": { city: "Atlanta", country: { name: "United States", code: "US" }, region: { name: "Georgia", code: "GA" }, latitude: 33.7490, longitude: -84.3880 },
        "128.116.25.0": { city: "Atlanta", country: { name: "United States", code: "US" }, region: { name: "Georgia", code: "GA" }, latitude: 33.7490, longitude: -84.3880 },
        "128.116.26.0": { city: "Paris", country: { name: "France", code: "FR" }, region: { name: "Île-de-France", code: "IDF" }, latitude: 48.8566, longitude: 2.3522 },
        "128.116.27.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.28.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.29.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.30.0": { city: "Hong Kong", country: { name: "Hong Kong", code: "HK" }, latitude: 22.3193, longitude: 114.1694 },
        "128.116.31.0": { city: "Warsaw", country: { name: "Poland", code: "PL" }, region: { name: "Mazowieckie", code: "14" }, latitude: 52.2297, longitude: 21.0122 },
        "128.116.32.0": { city: "New York City", country: { name: "United States", code: "US" }, region: { name: "New York", code: "NY" }, latitude: 40.7128, longitude: -74.0060 },
        "128.116.33.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.34.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.35.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.36.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.37.0": { city: "Miami", country: { name: "United States", code: "US" }, region: { name: "Florida", code: "FL" }, latitude: 25.7617, longitude: -80.1918 },
        "128.116.38.0": { city: "Miami", country: { name: "United States", code: "US" }, region: { name: "Florida", code: "FL" }, latitude: 25.7617, longitude: -80.1918 },
        "128.116.39.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.40.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.41.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.42.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.43.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.44.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.45.0": { city: "Miami", country: { name: "United States", code: "US" }, region: { name: "Florida", code: "FL" }, latitude: 25.7617, longitude: -80.1918 },
        "128.116.46.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.47.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.48.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.49.0": { city: "Los Angeles", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 34.0522, longitude: -118.2437 },
        "128.116.50.0": { city: "Singapore", country: { name: "Singapore", code: "SG" }, latitude: 1.3521, longitude: 103.8198 },
        "128.116.51.0": { city: "Sydney", country: { name: "Australia", code: "AU" }, region: { name: "New South Wales", code: "NSW" }, latitude: -33.8688, longitude: 151.2093 },
        "128.116.52.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.53.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.54.0": { city: "Amsterdam", country: { name: "Netherlands", code: "NL" }, region: { name: "Noord-Holland", code: "NH" }, latitude: 52.3676, longitude: 4.9041 },
        "128.116.55.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.56.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.57.0": { city: "San Jose", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3382, longitude: -121.8863 },
        "128.116.58.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.59.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.60.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.61.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.62.0": { city: "Seattle", country: { name: "United States", code: "US" }, region: { name: "Washington", code: "WA" }, latitude: 47.6062, longitude: -122.3321 },
        "128.116.63.0": { city: "Los Angeles", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 34.0522, longitude: -118.2437 },
        "128.116.64.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.65.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.66.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.67.0": { city: "San Jose", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3382, longitude: -121.8863 },
        "128.116.68.0": { city: "Santa Clara", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3541, longitude: -121.9552 },
        "128.116.69.0": { city: "Santa Clara", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3541, longitude: -121.9552 },
        "128.116.70.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.71.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.72.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.73.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.74.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.75.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.76.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.77.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.78.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.79.0": { city: "Singapore", country: { name: "Singapore", code: "SG" }, latitude: 1.3521, longitude: 103.8198 },
        "128.116.80.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.81.0": { city: "Santa Clara", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3541, longitude: -121.9552 },
        "128.116.82.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.83.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.84.0": { city: "Elk Grove Village", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 42.0039, longitude: -87.9706 },
        "128.116.85.0": { city: "Miami", country: { name: "United States", code: "US" }, region: { name: "Florida", code: "FL" }, latitude: 25.7617, longitude: -80.1918 },
        "128.116.86.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.87.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.88.0": { city: "Elk Grove Village", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 42.0039, longitude: -87.9706 },
        "128.116.89.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.90.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.91.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.92.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.93.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.94.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.95.0": { city: "Dallas", country: { name: "United States", code: "US" }, region: { name: "Texas", code: "TX" }, latitude: 32.7767, longitude: -96.7970 },
        "128.116.96.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.97.0": { city: "Singapore", country: { name: "Singapore", code: "SG" }, latitude: 1.3521, longitude: 103.8198 },
        "128.116.98.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.99.0": { city: "Atlanta", country: { name: "United States", code: "US" }, region: { name: "Georgia", code: "GA" }, latitude: 33.7490, longitude: -84.3880 },
        "128.116.100.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.101.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.102.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.103.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.104.0": { city: "Mumbai", country: { name: "India", code: "IN" }, region: { name: "Mahārāshtra", code: "MH" }, latitude: 19.0760, longitude: 72.8777 },
        "128.116.105.0": { city: "Santa Clara", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3541, longitude: -121.9552 },
        "128.116.106.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.107.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.108.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.109.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.110.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.111.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.112.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.113.0": { city: "Chicago", country: { name: "United States", code: "US" }, region: { name: "Illinois", code: "IL" }, latitude: 41.8781, longitude: -87.6298 },
        "128.116.114.0": { city: "Ashburn", country: { name: "United States", code: "US" }, region: { name: "Virginia", code: "VA" }, latitude: 39.0438, longitude: -77.4874 },
        "128.116.115.0": { city: "Seattle", country: { name: "United States", code: "US" }, region: { name: "Washington", code: "WA" }, latitude: 47.6062, longitude: -122.3321 },
        "128.116.116.0": { city: "Los Angeles", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 34.0522, longitude: -118.2437 },
        "128.116.117.0": { city: "San Jose", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.3382, longitude: -121.8863 },
        "128.116.118.0": { city: "Hong Kong", country: { name: "Hong Kong", code: "HK" }, latitude: 22.3193, longitude: 114.1694 },
        "128.116.119.0": { city: "London", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5072, longitude: 0.1276 },
        "128.116.120.0": { city: "Tokyo", country: { name: "Japan", code: "JP" }, region: { name: "Tokyo", code: "13" }, latitude: 35.6895, longitude: 139.6917 },
        "128.116.121.0": { city: "Amsterdam", country: { name: "Netherlands", code: "NL" }, region: { name: "Noord-Holland", code: "NH" }, latitude: 52.3676, longitude: 4.9041 },
        "128.116.122.0": { city: "Paris", country: { name: "France", code: "FR" }, region: { name: "Île-de-France", code: "IDF" }, latitude: 48.8566, longitude: 2.3522 },
        "128.116.123.0": { city: "Frankfurt am Main", country: { name: "Germany", code: "DE" }, region: { name: "Hessen", code: "HE" }, latitude: 50.1109, longitude: 8.6821 },
        "128.116.124.0": { city: "Warsaw", country: { name: "Poland", code: "PL" }, region: { name: "Mazowieckie", code: "14" }, latitude: 52.2297, longitude: 21.0122 },
        "128.116.125.0": { city: "San Mateo", country: { name: "United States", code: "US" }, region: { name: "California", code: "CA" }, latitude: 37.5630, longitude: -122.3255 },
        "128.116.126.0": { city: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.127.0": { city: "Miami", country: { name: "United States", code: "US" }, region: { name: "Florida", code: "FL" }, latitude: 25.7617, longitude: -80.1918 },
    };

    // Main function does nothing lmao but its ere i guees
    function main() {
        const gameIdMatch = window.location.pathname.match(/\/games\/(\d+)\//);
        if (!gameIdMatch) {
            console.error("Game ID not found in URL!");
            return;
        }

        const gameId = gameIdMatch[1];
    }

    /*******************************************************
    name of function: Initiate the observer
    description: Start observing the document for changes
    *******************************************************/

    // Start observing the document for changes
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
    window.onload = showFirstTimePopup;
    main();
})();