RoLocate

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

目前为 2025-02-08 提交的版本。查看 最新版本

// ==UserScript==
// @name         RoLocate
// @namespace    https://oqarshi.github.io/
// @version      27.3
// @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

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

    /*******************************************************
    name of function: createPopup
    description: Creates a popup with server filtering options and interactive 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: "**Rolocate will find 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;
    }


    /*******************************************************
    name of function: ServerHop
    description: Handles server hopping by fetching and joining a random server, excluding recently joined servers.
    *******************************************************/
    // 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
    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 {
                // Use GM_xmlhttpRequest to fetch server data from the Roblox API
                const response = await new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `https://games.roblox.com/v1/games/${gameId}/servers/0?sortOrder=1&excludeFullGames=true&limit=100`,
                        onload: function(response) {
                            if (response.status === 429) {
                                reject(new Error('429: Too Many Requests'));
                            } else if (response.status >= 200 && response.status < 300) {
                                resolve(response);
                            } else {
                                reject(new Error(`HTTP error! status: ${response.status}`));
                            }
                        },
                        onerror: function(error) {
                            reject(error);
                        }
                    });
                });

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

                // 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 5 seconds...');
                    await new Promise(resolve => setTimeout(resolve, 5000)); // Wait for 5 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 {
                // Use GM_xmlhttpRequest to fetch server data from the Roblox API
                const response = await new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `https://games.roblox.com/v1/games/${gameId}/servers/0?sortOrder=2&excludeFullGames=true&limit=100`,
                        onload: function(response) {
                            if (response.status === 429) {
                                reject(new Error('429: Too Many Requests'));
                            } else if (response.status >= 200 && response.status < 300) {
                                resolve(response);
                            } else {
                                reject(new Error(`HTTP error! status: ${response.status}`));
                            }
                        },
                        onerror: function(error) {
                            reject(error);
                        }
                    });
                });

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

                // 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() {
        // Check if the max player count has already been determined
        if (!player_count_tab.maxPlayers) {
            // Try to find the element containing the player count information
            const playerCountElement = document.querySelector('.text-info.rbx-game-status.rbx-game-server-status.text-overflow');
            if (playerCountElement) {
                const playerCountText = playerCountElement.textContent.trim();
                const match = playerCountText.match(/(\d+) of (\d+) people max/);
                if (match) {
                    const maxPlayers = parseInt(match[2], 10);
                    if (!isNaN(maxPlayers) && maxPlayers > 1) {
                        player_count_tab.maxPlayers = maxPlayers;
                        console.log("Found text element with max playercount");
                    }
                }
            } else {
                // If the element is not found, extract the gameId from the URL
                const gameIdMatch = window.location.href.match(/games\/(\d+)/);
                if (gameIdMatch && gameIdMatch[1]) {
                    const gameId = gameIdMatch[1];
                    // Send a request to the Roblox API to get server information
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: `https://games.roblox.com/v1/games/${gameId}/servers/public?sortOrder=1&excludeFullGames=true&limit=100`,
                        onload: function(response) {
                            try {
                                if (response.status === 429) {
                                    // Rate limit error, default to 100
                                    console.log("Rate limited defaulting to 100.");
                                    player_count_tab.maxPlayers = 100;
                                } else {
                                    console.log("Valid api response");
                                    const data = JSON.parse(response.responseText);
                                    if (data.data && data.data.length > 0) {
                                        const maxPlayers = data.data[0].maxPlayers;
                                        if (!isNaN(maxPlayers) && maxPlayers > 1) {
                                            player_count_tab.maxPlayers = maxPlayers;
                                        }
                                    }
                                }
                                // Update the slider range if the popup is already created
                                const slider = document.querySelector('.player-count-popup input[type="range"]');
                                if (slider) {
                                    slider.max = player_count_tab.maxPlayers ? (player_count_tab.maxPlayers - 1).toString() : '100';
                                    slider.style.background = `
                        linear-gradient(
                            to right,
                            #00A2FF 0%,
                            #00A2FF ${slider.value}%,
                            #444 ${slider.value}%,
                            #444 100%
                        );
                    `;
                                }
                            } catch (error) {
                                console.error('Failed to parse API response:', error);
                                // Default to 100 if parsing fails
                                player_count_tab.maxPlayers = 100;
                                const slider = document.querySelector('.player-count-popup input[type="range"]');
                                if (slider) {
                                    slider.max = '100';
                                    slider.style.background = `
                        linear-gradient(
                            to right,
                            #00A2FF 0%,
                            #00A2FF ${slider.value}%,
                            #444 ${slider.value}%,
                            #444 100%
                        );
                    `;
                                }
                            }
                        },
                        onerror: function(error) {
                            console.error('Failed to fetch server information:', error);
                            console.log('Fallback to 100 players.');
                            // Default to 100 if the request fails
                            player_count_tab.maxPlayers = 100;
                            const slider = document.querySelector('.player-count-popup input[type="range"]');
                            if (slider) {
                                slider.max = '100';
                                slider.style.background = `
                    linear-gradient(
                        to right,
                        #00A2FF 0%,
                        #00A2FF ${slider.value}%,
                        #444 ${slider.value}%,
                        #444 100%
                    );
                `;
                            }
                        }
                    });
                }
            }
        }
        // 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 = player_count_tab.maxPlayers ? (player_count_tab.maxPlayers - 1).toString() : '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: Click the slider and use the arrow keys for more accuracy.';
        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="https://greasyfork.org/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();
})();