RoSniperX

stream sniper script without using exploits

  1. // ==UserScript==
  2. // @name RoSniperX
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.1
  5. // @description stream sniper script without using exploits
  6. // @author Lukas Dobbles
  7. // @match https://www.roblox.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. "use strict";
  14. const getJSON = (url, args = {}) => {
  15. args.headers = args.headers || {};
  16. args.credentials = "include";
  17.  
  18. return fetch(url, args).then((r) => r.json());
  19. };
  20.  
  21. const search = async (placeId, name, setStatus, cb, setThumb) => {
  22. const userId = await getUserId(name);
  23. const thumbUrl = await getThumb(userId);
  24. setStatus("thumb url: " + thumbUrl);
  25. setThumb(thumbUrl);
  26. let cursor = null;
  27. let searching = true;
  28. let serversScraped = 0;
  29. const startTime = Date.now();
  30.  
  31. const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  32.  
  33. let serverQueue = [];
  34. let retryCount = 0;
  35. const maxRetries = 5;
  36.  
  37. while (searching) {
  38. try {
  39. // Fetch servers data
  40. const servers = await getServer(placeId, cursor);
  41.  
  42. // Reset retry count on success
  43. retryCount = 0;
  44.  
  45. // Update the count of scraped servers
  46. serversScraped += servers.data.length;
  47.  
  48. // Update the cursor for the next page
  49. cursor = servers.nextPageCursor;
  50.  
  51. // Process each server's player tokens
  52. for (const place of servers.data) {
  53. const tokens = place.playerTokens.map((token) => ({ token, place }));
  54. serverQueue = serverQueue.concat(tokens);
  55. }
  56.  
  57. // If there's no next page, exit the loop
  58. if (!cursor) break;
  59.  
  60. // Update the status with the current progress
  61. setStatus(
  62. `Scraped ${serverQueue.length} player tokens from ${serversScraped} servers`
  63. );
  64. } catch (err) {
  65. if (retryCount >= maxRetries) {
  66. setStatus(
  67. `Error fetching servers after ${maxRetries} retries. Please try again later. ${err}`
  68. );
  69. break;
  70. }
  71.  
  72. // Apply exponential backoff
  73. const backoffTime = Math.pow(2, retryCount) * 1000; // Exponential backoff in milliseconds
  74. setStatus(
  75. `Error fetching servers. Retrying in ${backoffTime / 1000} seconds... (${err})`
  76. );
  77. await delay(backoffTime);
  78. retryCount++;
  79. continue;
  80. }
  81. }
  82.  
  83. let found = false;
  84.  
  85. while (serverQueue.length > 0 && !found) {
  86. const tokens = serverQueue.splice(0, 100); // Process tokens in batches of 100
  87.  
  88. try {
  89. const serverThumbs = (await fetchThumbs(tokens.map(({ token }) => token))).data;
  90.  
  91. if (!serverThumbs) {
  92. setStatus(
  93. "Error fetching server thumbnails. Try again or get help at the Discord server: https://discord.gg/7zTCxVj9JD."
  94. );
  95. throw new Error("No thumbnails received");
  96. }
  97.  
  98. for (const thumb of serverThumbs) {
  99. if (thumb && thumb.imageUrl === thumbUrl) {
  100. const thumbToken = thumb.requestId.split(":")[1];
  101. const matchedPlace = tokens.find((x) => x.token === thumbToken)?.place;
  102.  
  103. if (matchedPlace) {
  104. found = true;
  105. setStatus(
  106. `Found them! Completed in ${(Date.now() - startTime) / 1000} seconds`
  107. );
  108.  
  109. cb({
  110. found: true,
  111. place: matchedPlace,
  112. });
  113. return;
  114. }
  115. }
  116. }
  117. } catch (err) {
  118. setStatus(
  119. "There was an error when fetching user thumbnails. Try again or get help at the Discord server: https://discord.gg/7zTCxVj9JD. " +
  120. err
  121. );
  122. }
  123. }
  124.  
  125. // If not found after all tokens
  126. if (!found) {
  127. cb({ found: false });
  128. }
  129. };
  130.  
  131. const getUserId = (name) =>
  132. getJSON("https://users.roblox.com/v1/usernames/users", {
  133. method: "POST",
  134. headers: {
  135. "Content-Type": "application/json",
  136. },
  137. body: JSON.stringify({
  138. usernames: [name],
  139. excludeBannedUsers: true,
  140. }),
  141. }).then((d) => d.data[0]["id"]);
  142.  
  143. const getThumb = (id) =>
  144. getJSON(
  145. `https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds=${id}&format=Png&size=150x150`
  146. ).then((d) => d.data[0].imageUrl);
  147.  
  148. const getServer = (placeId, cursor) => {
  149. let url = `https://games.roblox.com/v1/games/${placeId}/servers/Public?limit=100`;
  150.  
  151. if (cursor) url += "&cursor=" + cursor;
  152. return getJSON(url);
  153. };
  154.  
  155. const fetchThumbs = (tokens) => {
  156. let body = [];
  157.  
  158. tokens.forEach((token) => {
  159. body.push({
  160. requestId: `0:${token}:AvatarHeadshot:150x150:png:regular`,
  161. type: "AvatarHeadShot",
  162. targetId: 0,
  163. token,
  164. format: "png",
  165. size: "150x150",
  166. });
  167. });
  168.  
  169. return getJSON("https://thumbnails.roblox.com/v1/batch", {
  170. method: "POST",
  171. headers: {
  172. "Content-Type": "application/json",
  173. Accept: "application/json",
  174. },
  175. body: JSON.stringify(body),
  176. });
  177. };
  178.  
  179. const instancesContainer = document.getElementById(
  180. "running-game-instances-container"
  181. );
  182. if (instancesContainer) {
  183. const containerHeader = document.createElement("div");
  184. containerHeader.id = "rosniperx";
  185.  
  186. const headerText = document.createElement("h2");
  187. headerText.innerText = "RoSniperX";
  188. headerText.id = "rosniperx-header";
  189. containerHeader.appendChild(headerText);
  190.  
  191. const form = document.createElement("form");
  192.  
  193. const thumbImage = document.createElement("img");
  194. thumbImage.height = "40";
  195. thumbImage.style.display = "none";
  196. containerHeader.appendChild(thumbImage);
  197.  
  198. const usernameInput = document.createElement("input");
  199. usernameInput.classList = "input-field";
  200. usernameInput.placeholder = "Username";
  201. form.appendChild(usernameInput);
  202.  
  203. const submitButton = document.createElement("button");
  204. submitButton.classList = "btn-primary-md";
  205. submitButton.innerText = "Search";
  206. submitButton.disabled = true;
  207. form.appendChild(submitButton);
  208.  
  209. usernameInput.addEventListener("keyup", (e) => {
  210. submitButton.disabled = e.target.value.length === 0;
  211. });
  212.  
  213. const statusText = document.createElement("p");
  214. form.appendChild(statusText);
  215.  
  216. const joinBtn = document.createElement("button");
  217. joinBtn.style.display = "none";
  218. joinBtn.innerText = "Join";
  219. joinBtn.classList =
  220. "btn-control-xs rbx-game-server-join game-server-join-btn btn-primary-md btn-min-width";
  221.  
  222. containerHeader.appendChild(form);
  223. containerHeader.appendChild(joinBtn);
  224. instancesContainer.insertBefore(
  225. containerHeader,
  226. instancesContainer.firstChild
  227. );
  228.  
  229. form.addEventListener("submit", (evt) => {
  230. evt.preventDefault();
  231.  
  232. joinBtn.style.display = "none";
  233.  
  234. const placeId = location.href.match(/\d+/)[0];
  235.  
  236. search(
  237. placeId,
  238. usernameInput.value,
  239. (txt) => {
  240. console.log(txt);
  241. statusText.innerText = txt;
  242. },
  243. (place) => {
  244. if (!place.found) {
  245. statusText.innerText = "couldn't find them";
  246. joinBtn.style.display = "none";
  247. return;
  248. }
  249.  
  250. joinBtn.style.display = "";
  251.  
  252. joinBtn.onclick = () => {
  253. window.Roblox.GameLauncher.joinGameInstance(placeId, place.place.id);
  254. };
  255. },
  256. (src) => {
  257. thumbImage.src = src;
  258. thumbImage.style.display = "";
  259. }
  260. );
  261. });
  262. }
  263. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址