RoLocate

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

当前为 2025-01-15 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         RoLocate
// @namespace    https://oqarshi.github.io/
// @version      21.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      MIT
// @icon         data:image/jpeg;base64,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
// @grant        GM_xmlhttpRequest
// ==/UserScript==



(function() {
	'use strict';

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

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

    function createPopup() {
    const popup = document.createElement('div');
    popup.className = 'server-filters-dropdown-box'; // Unique class name
    popup.style.cssText = `
        position: absolute;
        width: 210px;
        height: 382px;
        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 and tooltips for each button
    const buttonData = [{
            name: "Smallest Servers",
            tooltip: "**Reverses the order of the server list.** The emptiest servers will be displayed first."
        },
        {
            name: "Available Space",
            tooltip: "**Filters out servers which are full.** Servers with space will only be shown."
        },
        {
            name: "Player Count",
            tooltip: "**Roblox Locator finds servers with your specified player count or fewer.** Searching for up to 3 minutes. If no exact match is found, it shows servers closest to the target."
        },
        {
            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."
        },
        {
            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."
        },
        {
            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."
        },
        {
            name: "Auto 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."
        },
        {
            name: "About",
            tooltip: "**The Credits.** Rolocate was created by Oqarshi. Special thanks to BTRoblox ❤️. Enjoy using Rolocate!"
        }
    ];

    // Create buttons with unique names and tooltips
    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;

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

        buttonContainer.addEventListener('mouseover', () => {
            tooltip.style.display = 'block';
            buttonContainer.style.backgroundColor = '#4A4C4E'; // Hover effect
        });
        buttonContainer.addEventListener('mouseout', () => {
            tooltip.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:
                    credits();
                    break;
            }
        });

        popup.appendChild(buttonContainer);
    });

    return popup;
}


	/*******************************************************
	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 to load
	const observer = new MutationObserver((mutations, obs) => {
		const serverListOptions = document.querySelector('.server-list-options');
		if (serverListOptions) {
			// 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'; // Unique class name
			buttonText.textContent = 'Filters';
			filterButton.appendChild(buttonText);

			// Add the icon (three horizontal dashes)
			const icon = document.createElement('span');
			icon.className = 'RL-filter-icon'; // Unique class name
			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(); // Prevent event bubbling
				if (popup) {
					popup.remove(); // Remove the popup if it already exists
					popup = null;
				} else {
					popup = createPopup();
					// Position the popup next to the filter button
					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;
				}
			});

			// Stop observing once the button is added
			obs.disconnect();
		}
	})

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

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


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

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


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

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

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

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

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

				const data = await response.json();

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

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

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

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



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

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


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

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

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

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

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

				const data = await response.json();

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

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

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

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

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

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


	/*******************************************************
	name of function: player_count_tab
	description: Opens a popup for the user to select the max player count using a slider and filters servers accordingly.
	*******************************************************/
	function player_count_tab() {
		// Create the 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: 5px;
        z-index: 10000;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 10px;
    `;

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

		// Add a slider
		const slider = document.createElement('input');
		slider.type = 'range';
		slider.min = '1';
		slider.max = '100';
		slider.value = '1'; // Default value
		slider.style.cssText = `
        width: 200px;
        cursor: pointer;
    `;
		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;
    `;
		popup.appendChild(sliderValue);

		// Update the slider value display when the slider changes
		slider.addEventListener('input', () => {
			sliderValue.textContent = slider.value;
		});

		// Add a submit button
		const submitButton = document.createElement('button');
		submitButton.textContent = 'Search';
		submitButton.style.cssText = `
        padding: 5px 10px;
        font-size: 16px;
        background-color: #00A2FF;
        color: white;
        border: none;
        border-radius: 3px;
        cursor: pointer;
    `;
		popup.appendChild(submitButton);

		// Add a close button
		const closeButton = document.createElement('button');
		closeButton.textContent = 'Close';
		closeButton.style.cssText = `
        padding: 5px 10px;
        font-size: 16px;
        background-color: #555;
        color: white;
        border: none;
        border-radius: 3px;
        cursor: pointer;
    `;
		popup.appendChild(closeButton);

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

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

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

	/*******************************************************
	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() {
		// 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 stupid thingy black screen*/
.overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7); /* Dark semi-transparent background */
    z-index: 1000; /* Ensure overlay is below the popup */
}

/* Popup Container for the server region*/
.filter-popup {
    background-color: #2d2d2d; /* Dark background */
    color: #ffffff; /* White text */
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
    width: 300px;
    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 */
}

/* Close Button  for the server selector*/
#closePopup {
    position: absolute;
    top: 10px;
    right: 10px;
    background: #ff4444; /* Red background */
    border: none;
    color: white;
    font-size: 16px;
    cursor: pointer;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

#closePopup:hover {
    background: #cc0000; /* Darker red on hover */
}

/* Label */
.filter-popup label {
    display: block;
    margin-bottom: 10px;
    font-size: 16px;
    color: #ffffff;
}

/* Dropdown */
.filter-popup select {
    background-color: #444; /* Dark gray background */
    color: #ffffff; /* White text */
    padding: 8px;
    border-radius: 5px;
    border: 1px solid #666; /* Gray border */
    width: 100%;
    margin-bottom: 10px;
    font-size: 14px;
}

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

/* Custom Input */
.filter-popup input[type="number"] {
    background-color: #444; /* Dark gray background */
    color: #ffffff; /* White text */
    padding: 8px;
    border-radius: 5px;
    border: 1px solid #666; /* Gray border */
    width: 100%;
    margin-bottom: 10px;
    font-size: 14px;
}

.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: 8px 16px;
    border: 1px solid #666; /* Gray border */
    border-radius: 5px;
    cursor: pointer;
    font-size: 14px;
    width: 100%;
    transition: background-color 0.3s ease;
}

#confirmServerCount:hover {
    background-color: #666; /* Lighter gray on hover */
}
        .rbx-game-server-item.highlighted {
            border: 2px solid green;
            border-radius: 8px;
        }
        .fetch-button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }
    `;
	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>
        <label for="serverCount">Enter the number of servers to search (higher values yield more location variety).</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() {
			document.body.removeChild(overlay);
			document.body.removeChild(popup);
		}
	}

	// 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';

		const countryDropdown = document.createElement('select');
		countryDropdown.id = 'countryFilter';
		countryDropdown.innerHTML = '<option value="">All Countries</option>';
		countryDropdown.style.backgroundColor = '#333'; // Dark gray background
		countryDropdown.style.color = '#fff'; // White text
		countryDropdown.style.borderRadius = '8px'; // Rounded corners
		countryDropdown.style.padding = '8px'; // Increase size
		countryDropdown.style.fontSize = '16px'; // Increase font size
		countryDropdown.style.border = 'none'; // Remove default border

		const cityDropdown = document.createElement('select');
		cityDropdown.id = 'cityFilter';
		cityDropdown.innerHTML = '<option value="">All Cities</option>';
		cityDropdown.style.backgroundColor = '#333'; // Dark gray background
		cityDropdown.style.color = '#fff'; // White text
		cityDropdown.style.borderRadius = '8px'; // Rounded corners
		cityDropdown.style.padding = '8px'; // Increase size hehehehe
		cityDropdown.style.fontSize = '16px'; // Increase font size
		cityDropdown.style.border = 'none'; // Remove default border
		cityDropdown.style.marginLeft = '5px'; // move right cause im too lazy to fix

		// 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 make users life easier
				// wow ik i made the users life easier for once thats crazy!!! :OOOOO
				const cities = Object.keys(cityCounts);
				if (cities.length === 1) {
					cityDropdown.value = cities[0];
					// displayFilteredServers(selectedCountry, cities[0]); // if this breaks something which it doesent seem like it i will enable it later
				}
			}
		});

		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) {
			// Ask for the user's location
			const userLocation = await getUserLocation();
			if (!userLocation) {
				//notifications('Error: Unable to fetch your location. Please enable location access.', 'error', '⚠️');
				return;
			}

			// Fetch 50 servers
			const servers = await fetchPublicServers(gameId, 50);
			if (servers.length === 0) {
				notifications('Error: No servers found. Please try again later.', 'error', '⚠️');
				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
				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.', 'error', '⚠️');
			}

			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}")`);
						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
					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 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: #000;
                padding: 20px;
                border-radius: 10px;
                width: 300px;
                box-shadow: 0 5px 15px rgba(255, 255, 255, 0.1);
                text-align: center;
                position: relative;
                color: #fff;
            }
            .credits-popup-content h2 {
                margin-top: 0;
                color: #fff;
            }
            .credits-popup-content .version {
                font-size: 14px;
                color: #aaa;
                margin-bottom: 10px;
            }
            .credits-popup-content ul {
                list-style-type: none;
                padding: 0;
            }
            .credits-popup-content ul li {
                margin: 10px 0;
                color: #bbb;
            }
            .credits-popup-content a {
                color: #4da6ff;
                text-decoration: none;
            }
            .credits-popup-content a:hover {
                text-decoration: underline;
            }
            .credits-popup-close {
                position: absolute;
                top: 10px;
                right: 10px;
                font-size: 24px;
                font-weight: bold;
                cursor: pointer;
                color: #fff;
            }
            .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 21.3</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>Source Code for Roblox Locate is available at <a href="https://greasyfork.org/en/scripts/522164-roblox-locate" target="_blank">GreasyFork</a></li>
                        <li>Source Code for the invite feature is available at <a href="https://github.com/Oqarshi/Invite" target="_blank">Github</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

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


	/*******************************************************
	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!');
		}
	}



	/*******************************************************
	name of function: Loadingbar
	description: Shows or hides a loading bar
	*******************************************************/
	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 bar
			const loadingBar = document.createElement('div');
			loadingBar.id = 'loading-bar';
			loadingBar.style.cssText = `
            width: 100%;
            height: 4px;
            background-color: #1E1E1E;
            position: relative;
            overflow: hidden;
            border-radius: 2px;
            margin-top: 10px;
            `;

			const loadingBarInner = document.createElement('div');
			loadingBarInner.style.cssText = `
            width: 50%;
            height: 100%;
            background-color: #00A2FF;
            position: absolute;
            animation: loading 1.5s infinite ease-in-out;
            border-radius: 2px;
            `;

			// Add animation keyframes
			const styleSheet = document.createElement('style');
			styleSheet.textContent = `
            @keyframes loading {
            0% { left: -50%; }
            100% { left: 100%; }
            }
            `;
			document.head.appendChild(styleSheet);

			loadingBar.appendChild(loadingBarInner);
			serverListSection.appendChild(loadingBar);
		} 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', () => {
			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);
	}

	/*********************************************************************************************************************************************************************************************************************************************
	                                                         The function for the notification function

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

	// 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: 9999;
            display: flex;
            flex-direction: column;
            align-items: flex-end;
        }

        .toast {
            position: relative;
            min-width: 250px;
            padding: 15px 20px;
            margin-bottom: 10px;
            border-radius: 5px;
            color: white;
            font-family: 'Arial', sans-serif;
            font-size: 14px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            opacity: 0;
            transform: translateX(100%);
            animation: slideIn 0.5s ease-out forwards, bounce 0.5s ease-out, fadeOut 0.5s ease-out 7.5s forwards;
            display: flex;
            align-items: center;
        }

        .toast.success {
            background-color: #4CAF50;
        }

        .toast.error {
            background-color: #F44336;
        }

        .toast.warning {
            background-color: #FF9800;
        }

        .toast.info {
            background-color: #2196F3;
        }

        .toast::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 4px;
            background-color: rgba(255, 255, 255, 0.5);
            animation: progressBar 8s linear forwards;
        }

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

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

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

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

        @keyframes bounce {
            0%, 20%, 50%, 80%, 100% {
                transform: translateY(0);
            }
            40% {
                transform: translateY(-20px);
            }
            60% {
                transform: translateY(-10px);
            }
        }
    `;

	// 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

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

    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: "Secaucus", country: { name: "United States", code: "US" }, region: { name: "New Jersey", code: "NJ" }, latitude: 40.7895, longitude: -74.0565 },
        "128.116.33.0": { city: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "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: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "128.116.36.0": { city: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "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: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "128.116.73.0": { city: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "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: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "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: "Slough", country: { name: "United Kingdom", code: "GB" }, region: { name: "England", code: "ENG" }, latitude: 51.5105, longitude: -0.5950 },
        "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
	});
	main();
})();