RoSniperX

The only working stream sniper script without using exploits

目前为 2024-11-25 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name RoSniperX
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.4
  5. // @description The only working 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.  
  15. const getJSON = (url, args = {}) => {
  16. args.headers = args.headers || {};
  17. return fetch(url, args)
  18. .then((r) => r.json())
  19. .catch((e) => console.log(e));
  20. };
  21.  
  22. const search = async (placeId, name, setStatus, cb, setThumb) => {
  23. const userId = await getUserId(name);
  24. const thumbUrl = await getThumb(userId);
  25. setStatus("thumb url: " + thumbUrl);
  26. setThumb(thumbUrl);
  27. let cursor = null;
  28. let searching = true;
  29. let allPlayerTokens = [];
  30.  
  31. while (searching) {
  32. const servers = await getServer(placeId, cursor);
  33.  
  34. cursor = servers.nextPageCursor;
  35. for (let i = 0; i < servers.data.length; i++) {
  36. const place = servers.data[i];
  37. allPlayerTokens = allPlayerTokens.concat(
  38. place.playerTokens.map((token) => ({
  39. token,
  40. place,
  41. }))
  42. );
  43. }
  44.  
  45. if (!cursor) break;
  46.  
  47. setStatus("next server...");
  48. }
  49.  
  50. const chunkSize = 100;
  51. let i = 0;
  52.  
  53. let found = false;
  54.  
  55. const nextThumbChunk = () => {
  56. if (found) return;
  57.  
  58. let chunk;
  59. if (i + chunkSize > allPlayerTokens.length) {
  60. chunk = allPlayerTokens.slice(i);
  61. } else {
  62. chunk = allPlayerTokens.slice(i, i + chunkSize);
  63. }
  64. i += chunkSize;
  65.  
  66. setStatus(
  67. `searching servers ${Math.floor((i / allPlayerTokens.length) * 100)}%`
  68. );
  69.  
  70. fetchThumbs(chunk.map(({ token }) => token)).then(
  71. ({ data: serverThumbs }) => {
  72. if (!serverThumbs) setStatus("error: " + serverThumbs);
  73. else {
  74. for (let k = 0; k < serverThumbs.length; k++) {
  75. const thumb = serverThumbs[k];
  76. if (thumb && thumb.imageUrl === thumbUrl) {
  77. found = true;
  78.  
  79. setStatus(thumb.imageUrl);
  80. setStatus("FOUND THEM!");
  81.  
  82. const thumbToken = thumb.requestId.split(":")[1];
  83. cb({
  84. found: true,
  85. place: chunk.filter((x) => x.token === thumbToken)[0].place,
  86. });
  87. }
  88. }
  89.  
  90. if (i + chunkSize > allPlayerTokens.length && !found)
  91. cb({ found: false });
  92. else if (!found) nextThumbChunk();
  93. }
  94. }
  95. );
  96. };
  97.  
  98. [...Array(10)].map(() => nextThumbChunk());
  99. };
  100.  
  101. const getUserId = (name) =>
  102. fetch("https://www.roblox.com/users/profile?username=" + name).then((r) => {
  103. if (!r.ok) throw "User not found";
  104. return r.url.match(/\d+/)[0];
  105. });
  106.  
  107. const getThumb = (id) =>
  108. getJSON(
  109. `https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds=${id}&format=Png&size=150x150`
  110. ).then((d) => d.data[0].imageUrl);
  111.  
  112. const getServer = (placeId, cursor) => {
  113. let url = `https://games.roblox.com/v1/games/${placeId}/servers/Public?limit=100`;
  114.  
  115. if (cursor) url += "&cursor=" + cursor;
  116. return getJSON(url).catch(() => null);
  117. };
  118.  
  119. const fetchThumbs = (tokens) => {
  120. let body = [];
  121.  
  122. tokens.forEach((token) => {
  123. body.push({
  124. requestId: `0:${token}:AvatarHeadshot:150x150:png:regular`,
  125. type: "AvatarHeadShot",
  126. targetId: 0,
  127. token,
  128. format: "png",
  129. size: "150x150",
  130. });
  131. });
  132.  
  133. return getJSON("https://thumbnails.roblox.com/v1/batch", {
  134. method: "POST",
  135. headers: {
  136. "Content-Type": "application/json",
  137. Accept: "application/json",
  138. },
  139. body: JSON.stringify(body),
  140. });
  141. };
  142.  
  143. const instancesContainer = document.getElementById(
  144. "running-game-instances-container"
  145. );
  146. if (instancesContainer) {
  147. const containerHeader = document.createElement("div");
  148. containerHeader.classList = "section";
  149.  
  150. const headerText = document.createElement("h2");
  151. headerText.innerText = "RoSniperX";
  152. containerHeader.appendChild(headerText);
  153.  
  154. const form = document.createElement("form");
  155.  
  156. const thumbImage = document.createElement("img");
  157. thumbImage.height = "40";
  158. thumbImage.display = "none";
  159. containerHeader.appendChild(thumbImage);
  160.  
  161. const usernameInput = document.createElement("input");
  162. usernameInput.classList = "input-field";
  163. usernameInput.placeholder = "Username";
  164. form.appendChild(usernameInput);
  165.  
  166. const submitButton = document.createElement("button");
  167. submitButton.classList = "btn-primary-md";
  168. submitButton.innerText = "Search";
  169. submitButton.disabled = true;
  170. form.appendChild(submitButton);
  171.  
  172. usernameInput.addEventListener("keyup", (e)=> {
  173. submitButton.disabled = e.target.value.length === 0;
  174. })
  175.  
  176. const statusText = document.createElement("p");
  177. form.appendChild(statusText);
  178.  
  179. const joinBtn = document.createElement("button");
  180. joinBtn.style.display = "none";
  181. joinBtn.innerText = "Join";
  182. joinBtn.classList =
  183. "btn-control-xs rbx-game-server-join game-server-join-btn btn-primary-md btn-min-width";
  184.  
  185. const donateButton = document.createElement("a");
  186. donateButton.href =
  187. "https://www.buymeacoffee.com/lukasdobbl3";
  188. donateButton.target = "blank";
  189. donateButton.style.marginTop = "0.2rem";
  190. donateButton.classList = "btn-secondary-md";
  191. donateButton.innerText = "buy me a coffee";
  192.  
  193. containerHeader.appendChild(form);
  194. containerHeader.appendChild(joinBtn);
  195. containerHeader.appendChild(donateButton);
  196. instancesContainer.insertBefore(
  197. containerHeader,
  198. instancesContainer.firstChild
  199. );
  200.  
  201. const placeId = location.href.match(/\d+/)[0];
  202.  
  203. form.addEventListener("submit", (evt) => {
  204. evt.preventDefault();
  205.  
  206. joinBtn.display = "none";
  207.  
  208. search(
  209. placeId,
  210. usernameInput.value,
  211. (txt) => {
  212. console.log(txt);
  213. statusText.innerText = txt;
  214. },
  215. (place) => {
  216. if (!place.found) {
  217. statusText.innerText = "couldn't find them";
  218. return;
  219. }
  220.  
  221. joinBtn.style.display = "";
  222. joinBtn.onclick = () => {
  223. window.Roblox.GameLauncher.joinGameInstance(
  224. placeId,
  225. place.place.id
  226. );
  227. };
  228. },
  229. (src)=> {
  230. thumbImage.src = src;
  231. thumbImage.display = "";
  232. }
  233. );
  234. });
  235. }
  236. })();

QingJ © 2025

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