Josiahiscool73

0frameskipping

May 28th, 2025
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 58.24 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Fortnite xCloud Precision Aimbot (MoveNet) - ud
  3. // @description AI-powered aimbot for Fortnite on xCloud with MoveNet pose detection, dynamic frame-skipping, FOV-restricted detection, and instant triggerbot.
  4. // @author Improved Version / Community
  5. // @version 4.2.21
  6. // @match *://*.xbox.com/play/*
  7. // @grant none
  8. // @run-at document-end
  9. // @require https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf-core.min.js
  10. // @require https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf-converter.min.js
  11. // @require https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf-backend-webgl.min.js
  12. // @require https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]/dist/pose-detection.min.js
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // === Configuration Section ===
  19. // This section contains all customizable settings for the aimbot.
  20. // Each option is documented with its purpose, valid values, and how to adjust it.
  21.  
  22. const config = {
  23. // Detection settings for MoveNet AI model
  24. detection: {
  25. enabled: true, // Set to false to disable AI detection (aimbot visuals only)
  26. modelType: poseDetection.SupportedModels.MoveNet, // Do not change unless using a different model
  27. detectorConfig: {
  28. modelType: poseDetection.movenet.modelType.SINGLEPOSE_LIGHTNING, // Model type: SINGLEPOSE_LIGHTNING (fast) or SINGLEPOSE_THUNDER (accurate)
  29. enableSmoothing: true, // Smooths pose detection for less jitter (true/false)
  30. minPoseScore: 0.25 // Minimum confidence score for a detected pose (0.0 to 1.0, lower = more detections)
  31. },
  32. keypointConfidence: 0.20, // Minimum confidence for individual keypoints (0.0 to 1.0, lower = more points detected)
  33. maxDetections: 5, // Maximum number of players to detect (1 to 10, higher = more CPU usage)
  34. processingInterval: 5, // Minimum time (ms) between detection runs (10 to 100, lower = faster but more CPU)
  35. skipFrames: 0, // Base number of frames to skip between detections (0 to 5, 0 = no skip, higher = less CPU usage)
  36. dynamicFrameSkipping: {
  37. enabled: false, // Enable dynamic frame-skipping (true/false)
  38. minSkipFrames: 0, // Minimum frames to skip (0 to 5)
  39. maxSkipFrames: 0, // Maximum frames to skip (0 to 5)
  40. targetFPS: 30, // Target FPS for dynamic adjustment (20 to 60)
  41. highDetectionTimeThreshold: 20, // Detection time (ms) above which skipFrames increases (10 to 50)
  42. lowDetectionTimeThreshold: 10, // Detection time (ms) below which skipFrames decreases (5 to 30)
  43. fpsThresholdLow: 20, // FPS below which skipFrames increases (10 to 50)
  44. fpsThresholdHigh: 40 // FPS above which skipFrames decreases (30 to 60)
  45. },
  46. useWebGL2: true, // Use WebGL2 for faster processing (true/false, false may improve compatibility)
  47. ignoreSelfRegion: {
  48. enabled: true, // Ignore the player's own character in detection (true/false)
  49. xPercent: 0.00, // X position of ignore region (% of video width, 0.0 to 1.0)
  50. yPercent: 0.27, // Y position of ignore region (% of video height, 0.0 to 1.0)
  51. widthPercent: 0.37, // Width of ignore region (% of video width, 0.0 to 1.0)
  52. heightPercent: 0.74 // Height of ignore region (% of video height, 0.0 to 1.0)
  53. // Adjust these to cover your character's position on screen
  54. }
  55. },
  56. // Game interaction settings
  57. game: {
  58. videoSelector: 'video[aria-label="Game Stream for unknown title"]', // HTML selector for game video (do not change unless xCloud changes)
  59. containerSelector: '#game-stream', // HTML selector for game container (do not change unless xCloud changes)
  60. recoilCompensation: true, // Enable manual recoil compensation (true/false)
  61. recoilLevel: 1, // Recoil strength level (1 to 5, higher = stronger compensation)
  62. // Example: Set recoilLevel to 3 for weapons with moderate recoil
  63. recoilPatterns: {
  64. 1: { vertical: 0.1, horizontal: 0.02, recoverySpeed: 0.25 },
  65. 2: { vertical: 0.2, horizontal: 0.04, recoverySpeed: 0.20 },
  66. 3: { vertical: 0.3, horizontal: 0.06, recoverySpeed: 0.15 },
  67. 4: { vertical: 0.5, horizontal: 0.1, recoverySpeed: 0.12 },
  68. 5: { vertical: 0.7, horizontal: 0.15, recoverySpeed: 0.10 }
  69. // Adjust vertical/horizontal for recoil strength, recoverySpeed for how fast it resets (0.0 to 1.0)
  70. },
  71. autoShoot: true, // Automatically shoot when crosshair is in target lock (true/false)
  72. triggerOptions: {
  73. burstMode: false, // Enable burst fire mode (true/false)
  74. burstCount: 3, // Number of shots per burst (1 to 10)
  75. burstInterval: 100 // Time (ms) between burst shots (50 to 500)
  76. },
  77. controlOptions: {
  78. crouchOnShoot: false, // Crouch when shooting (true/false)
  79. crouchKey: 'KeyC', // Key for crouching (e.g., 'KeyC' for C key, see https://keycode.info)
  80. reloadKey: 'KeyR', // Key for reloading (e.g., 'KeyR' for R key)
  81. weaponKeys: ['Digit1', 'Digit2', 'Digit3', 'Digit4', 'Digit5'] // Keys for weapon slots (e.g., 'Digit1' for 1 key)
  82. // Example: Change crouchKey to 'KeyX' to use X for crouching
  83. }
  84. },
  85. // Aiming settings
  86. aim: {
  87. activationKey: 'KeyE', // Key to activate aimbot (e.g., 'KeyE' for E key, 'KeyQ' for Q, etc.)
  88. // Example: Change to 'KeyQ' to use Q key for aiming
  89. fovRadius: 250, // Field of view radius (pixels) for target detection (100 to 1000, larger = wider range)
  90. instantLock: true, // Instantly lock onto target (true/false, false = smoother but slower)
  91. aimPoint: "torso_center", // Target body part: "torso_center", "head", "neck", or "center"
  92. headOffset: 0.15, // Vertical offset for head aiming (% of bounding box height, 0.0 to 1.0)
  93. bodyOffset: 0.4, // Vertical offset for torso/center aiming (% of bounding box height, 0.0 to 1.0)
  94. targetPriority: "center", // Target selection priority: "center" (screen center), "crosshair" (mouse), "distance", or "size"
  95. targetSwitchCooldown: 250, // Time (ms) before switching targets (100 to 1000, higher = less frequent switches)
  96. triggerThreshold: 0.7, // Auto-shoot distance threshold (% of fovRadius, 0.0 to 1.0, lower = closer range)
  97. smoothing: {
  98. enabled: false, // Smooth aim movement (true/false)
  99. amount: 0.15, // Smoothing strength (0.0 to 1.0, higher = smoother but slower)
  100. extrapolation: false // Predict target movement (true/false, experimental)
  101. },
  102. snapOptions: {
  103. strength: 1, // Snap strength (0.0 to 1.0, higher = faster snap)
  104. threshold: 0.9, // Snap activation threshold (0.0 to 1.0, lower = easier snap)
  105. diminishingRange: false // Reduce snap strength at edges (true/false)
  106. }
  107. },
  108. // Visual overlay settings
  109. visual: {
  110. showDebugInfo: true, // Show debug info on screen (true/false)
  111. crosshair: {
  112. enabled: true, // Show crosshair (true/false)
  113. style: 'dot', // Crosshair style: 'dot', 'cross', or 'circle'
  114. color: 'lime', // Crosshair color (e.g., 'lime', 'red', '#FF0000')
  115. size: 3, // Crosshair size (pixels, 1 to 10)
  116. centerOnGameScreen: true // Center crosshair on game screen (true) or mouse (false)
  117. },
  118. boundingBoxes: { enabled: false }, // Show bounding boxes around targets (true/false)
  119. keypoints: {
  120. enabled: false, // Show keypoint dots on targets (true/false)
  121. color: 'cyan', // Keypoint color
  122. radius: 3 // Keypoint size (pixels, 1 to 10)
  123. },
  124. skeleton: {
  125. enabled: false, // Show skeleton lines on targets (true/false)
  126. color: 'rgba(255, 0, 255, 0.9)', // Skeleton color
  127. lineWidth: 2 // Skeleton line thickness (pixels, 1 to 5)
  128. },
  129. targetLock: {
  130. enabled: false, // Show lock-on indicator (true/false)
  131. color: 'yellow', // Indicator color
  132. style: 'corners' // Indicator style: 'corners', 'full', or 'crosshair'
  133. },
  134. fovCircle: {
  135. enabled: true, // Show FOV circle (true/false)
  136. color: 'rgba(255,255,255,0.3)', // Circle color
  137. lineWidth: 1, // Circle thickness (pixels, 1 to 5)
  138. centerOnGameScreen: true, // Center on game screen (true) or mouse (false)
  139. showOnlyWhenAiming: true // Show only when aim key is held (true/false)
  140. },
  141. performanceMetrics: {
  142. enabled: true, // Show FPS and detection time (true/false)
  143. position: 'top-left' // Position: 'top-left', 'top-right', 'bottom-left', 'bottom-right'
  144. },
  145. showRecoilTunerGUI: false // Show on-screen recoil tuning GUI (true/false)
  146. }
  147. };
  148. config.version = '4.2.21'; // Script version (do not change)
  149.  
  150. // === ASCII Art Separator ===
  151. // This visually separates configuration from debugging for clarity
  152. /*
  153. _____ _______ _______
  154. | __ \__ __|__ __|
  155. | |__) | | | | |
  156. | _ / | | | |
  157. | | \ \ | | | |
  158. |_| \_\ |_| |_|
  159.  
  160. Configuration above, Debugging below
  161. */
  162.  
  163. // === Debugging and State Management ===
  164. // This section handles internal state and logging. Modify only if you know what you're doing.
  165.  
  166. const tfState = {
  167. backend: 'webgl', // TensorFlow backend (do not change)
  168. flags: { WEBGL_VERSION: 2, WEBGL_RENDER_FLOAT32_ENABLED: true } // WebGL settings
  169. };
  170.  
  171. const state = {
  172. gameVideo: null, // Game video element
  173. detectionModel: null, // MoveNet model
  174. modelLoaded: false, // Model load status
  175. currentTarget: null, // Current aim target
  176. lastTargetSwitch: 0, // Time of last target switch
  177. frameCount: 0, // Frame counter
  178. lastDetectionTime: 0, // Last detection timestamp
  179. performance: {
  180. fps: 0, // Current FPS
  181. framesThisSecond: 0, // Frames in current second
  182. lastFpsUpdate: 0, // Last FPS update time
  183. detectionTime: 0, // Last detection duration
  184. avgDetectionTime: 0, // Average detection duration
  185. detectionTimeHistory: [] // Detection time history
  186. },
  187. ui: {
  188. overlayCanvas: null, // Overlay canvas
  189. overlayCtx: null, // Overlay context
  190. offscreenCanvas: null, // Offscreen canvas for ignore region
  191. offscreenCtx: null // Offscreen context
  192. },
  193. input: {
  194. lastMouseX: window.innerWidth / 2, // Last mouse X position
  195. lastMouseY: window.innerHeight / 2, // Last mouse Y position
  196. leftButtonDown: false, // Left mouse button state
  197. rightButtonDown: false, // Right mouse button state
  198. activeKeys: new Set() // Active keys
  199. },
  200. recoilState: {
  201. active: false, // Recoil compensation active
  202. offsetX: 0, // Recoil X offset
  203. offsetY: 0, // Recoil Y offset
  204. shotsFired: 0, // Shots fired in current burst
  205. lastShotTime: 0, // Last shot timestamp
  206. lastLeftButtonState: false // Last left button state
  207. },
  208. isShooting: false, // Shooting status
  209. currentWeapon: 0 // Current weapon slot
  210. };
  211.  
  212. const debug = {
  213. log: (...args) => console.log(`[AimbotV${config.version}-MoveNet]`, ...args),
  214. warn: (...args) => console.warn(`[AimbotV${config.version}-MoveNet]`, ...args),
  215. error: (...args) => console.error(`[AimbotV${config.version}-MoveNet]`, ...args)
  216. };
  217.  
  218. // === Utility Functions ===
  219. // These functions handle notifications, TensorFlow setup, and model loading.
  220.  
  221. // Displays on-screen notifications
  222. function showNotification(message, type = 'info', duration = 3000) {
  223. const n = document.createElement('div');
  224. n.style.cssText = `position:fixed;top:20px;left:50%;transform:translateX(-50%);padding:10px 20px;border-radius:5px;color:white;z-index:1000000;font-family:sans-serif;font-size:16px;box-shadow:0 2px 10px rgba(0,0,0,0.2);background-color:${type === 'error' ? 'rgba(255,0,0,0.8)' : type === 'warning' ? 'rgba(255,165,0,0.8)' : 'rgba(0,0,0,0.7)'};`;
  225. n.textContent = message;
  226. document.body.appendChild(n);
  227. setTimeout(() => n.remove(), duration);
  228. }
  229.  
  230. // Sets up TensorFlow.js
  231. async function setupTensorFlow() {
  232. try {
  233. debug.log("Configuring TF.js...");
  234. await tf.setBackend(tfState.backend);
  235. await tf.ready();
  236. for (const f in tfState.flags) tf.env().set(f, tfState.flags[f]);
  237. debug.log(`TF.js backend: ${tf.getBackend()}`);
  238. if (tf.getBackend() === 'webgl') debug.log(`WebGL Version: ${tf.env().get('WEBGL_VERSION')}`);
  239. const sT = performance.now();
  240. const tT = tf.zeros([100, 100, 3]);
  241. await tT.data();
  242. tT.dispose();
  243. debug.log(`TF basic op test: ${(performance.now() - sT).toFixed(2)}ms`);
  244. return true;
  245. } catch (e) {
  246. debug.error("TF setup failed:", e);
  247. return false;
  248. }
  249. }
  250.  
  251. // Loads the MoveNet model
  252. async function loadDetectionModel() {
  253. debug.log("Loading MoveNet model...");
  254. try {
  255. if (!await setupTensorFlow()) throw Error("TF setup failed");
  256. if (typeof poseDetection === "undefined") throw Error("Pose Detection API not loaded.");
  257. state.detectionModel = await poseDetection.createDetector(config.detection.modelType, config.detection.detectorConfig);
  258. const tC = document.createElement('canvas');
  259. tC.width = 192;
  260. tC.height = 192;
  261. await state.detectionModel.estimatePoses(tC);
  262. state.modelLoaded = true;
  263. debug.log("MoveNet model loaded!");
  264. showNotification("AI Model (MoveNet) Loaded!", "info");
  265. return true;
  266. } catch (e) {
  267. debug.error("Failed to load MoveNet model:", e);
  268. showNotification("Error loading AI model (MoveNet)! Check console.", "error");
  269. return false;
  270. }
  271. }
  272.  
  273. // === Detection and Targeting Functions ===
  274. // These functions handle player detection and aim target calculation.
  275.  
  276. // Calculates bounding box from keypoints
  277. function calculateBoundingBoxFromKeypoints(kps) {
  278. if (!kps || kps.length === 0) return null;
  279. let mX = Infinity, mY = Infinity, mAX = -Infinity, mAY = -Infinity, vK = 0;
  280. kps.forEach(k => {
  281. if (k.score && k.score >= config.detection.keypointConfidence) {
  282. mX = Math.min(mX, k.x);
  283. mY = Math.min(mY, k.y);
  284. mAX = Math.max(mAX, k.x);
  285. mAY = Math.max(mAY, k.y);
  286. vK++;
  287. }
  288. });
  289. if (vK < 5) return null;
  290. const w = mAX - mX, h = mAY - mY, pX = 0.1 * w, pY = 0.1 * h;
  291. return { x: Math.max(0, mX - pX), y: Math.max(0, mY - pY), width: mAX - mX + 2 * pX, height: mAY - mY + 2 * pY, validKeypoints: vK };
  292. }
  293.  
  294. // Calculates aim target position
  295. function calculateAimTarget(pred, vRect) {
  296. const [vBx, vBy, vBw, vBh] = pred.bbox;
  297. const sBx = vRect.left + vBx / state.gameVideo.videoWidth * vRect.width;
  298. const sBy = vRect.top + vBy / state.gameVideo.videoHeight * vRect.height;
  299. const sBw = vBw / state.gameVideo.videoWidth * vRect.width;
  300. const sBh = vBh / state.gameVideo.videoHeight * vRect.height;
  301. let tX, tY;
  302. const kps = pred.keypoints;
  303. const gK = n => kps.find(k => k.name === n && k.score >= config.detection.keypointConfidence);
  304. switch (config.aim.aimPoint) {
  305. case "head":
  306. const n = gK('nose'), lE = gK('left_eye'), rE = gK('right_eye');
  307. if (n) {
  308. tX = vRect.left + n.x / state.gameVideo.videoWidth * vRect.width;
  309. tY = vRect.top + n.y / state.gameVideo.videoHeight * vRect.height;
  310. } else if (lE && rE) {
  311. tX = vRect.left + ((lE.x + rE.x) / 2) / state.gameVideo.videoWidth * vRect.width;
  312. tY = vRect.top + ((lE.y + rE.y) / 2) / state.gameVideo.videoHeight * vRect.height;
  313. } else {
  314. tX = sBx + sBw / 2;
  315. tY = sBy + sBh * config.aim.headOffset;
  316. }
  317. break;
  318. case "neck":
  319. const lS_n = gK('left_shoulder'), rS_n = gK('right_shoulder');
  320. if (lS_n && rS_n) {
  321. tX = vRect.left + ((lS_n.x + rS_n.x) / 2) / state.gameVideo.videoWidth * vRect.width;
  322. tY = vRect.top + ((lS_n.y + rS_n.y) / 2 - vBh * 0.05) / state.gameVideo.videoHeight * vRect.height;
  323. } else {
  324. tX = sBx + sBw / 2;
  325. tY = sBy + sBh * (config.aim.headOffset + 0.1);
  326. }
  327. break;
  328. case "torso_center":
  329. const lS_t = gK('left_shoulder'), rS_t = gK('right_shoulder'), lH_t = gK('left_hip'), rH_t = gK('right_hip');
  330. if (lS_t && rS_t && lH_t && rH_t) {
  331. tX = vRect.left + (((lS_t.x + rS_t.x) / 2 + (lH_t.x + rH_t.x) / 2) / 2) / state.gameVideo.videoWidth * vRect.width;
  332. tY = vRect.top + (((lS_t.y + rS_t.y) / 2 + (lH_t.y + rH_t.y) / 2) / 2) / state.gameVideo.videoHeight * vRect.height;
  333. } else {
  334. tX = sBx + sBw / 2;
  335. tY = sBy + sBh * config.aim.bodyOffset;
  336. }
  337. break;
  338. case "center":
  339. default:
  340. tX = sBx + sBw / 2;
  341. tY = sBy + sBh / 2;
  342. break;
  343. }
  344. return { x: tX, y: tY, width: sBw, height: sBh, bboxRaw: pred.bbox, keypoints: pred.keypoints };
  345. }
  346.  
  347. // Finds the best target based on priority, only considering targets within FOV
  348. function findBestTarget(predictions, videoRect) {
  349. if (!predictions || predictions.length === 0 || !state.gameVideo || !videoRect || videoRect.width === 0) return null;
  350. const gameScreenCenterX = videoRect.left + videoRect.width / 2;
  351. const gameScreenCenterY = videoRect.top + videoRect.height / 2;
  352. let bestTarget = null;
  353. let bestScore = Infinity;
  354. const fovCenterX = config.visual.fovCircle.centerOnGameScreen ? gameScreenCenterX : state.input.lastMouseX;
  355. const fovCenterY = config.visual.fovCircle.centerOnGameScreen ? gameScreenCenterY : state.input.lastMouseY;
  356.  
  357. predictions.forEach(prediction => {
  358. const targetInfo = calculateAimTarget(prediction, videoRect);
  359. const dx_fov = targetInfo.x - fovCenterX;
  360. const dy_fov = targetInfo.y - fovCenterY;
  361. // Only consider targets within FOV
  362. if (Math.sqrt(dx_fov * dx_fov + dy_fov * dy_fov) > config.aim.fovRadius) return;
  363.  
  364. let referenceX, referenceY;
  365. if (config.aim.targetPriority === "center") {
  366. referenceX = gameScreenCenterX;
  367. referenceY = gameScreenCenterY;
  368. } else {
  369. referenceX = state.input.lastMouseX;
  370. referenceY = state.input.lastMouseY;
  371. }
  372. const dx = targetInfo.x - referenceX;
  373. const dy = targetInfo.y - referenceY;
  374. const distanceToPriorityPoint = Math.sqrt(dx * dx + dy * dy);
  375.  
  376. let score;
  377. switch (config.aim.targetPriority) {
  378. case "size":
  379. score = targetInfo.width * targetInfo.height > 0 ? 1 / (targetInfo.width * targetInfo.height) : Infinity;
  380. break;
  381. case "distance":
  382. case "center":
  383. case "crosshair":
  384. default:
  385. score = distanceToPriorityPoint;
  386. break;
  387. }
  388. if (score < bestScore) {
  389. bestScore = score;
  390. bestTarget = { prediction, screenPosition: targetInfo, distance: distanceToPriorityPoint, score: prediction.score };
  391. }
  392. });
  393. return bestTarget;
  394. }
  395.  
  396. // === Input Controller ===
  397. // Handles mouse and keyboard input simulation.
  398.  
  399. const InputController = {
  400. init() {
  401. state.input.lastMouseX = window.innerWidth / 2;
  402. state.input.lastMouseY = window.innerHeight / 2;
  403. document.addEventListener('mousemove', e => {
  404. state.input.lastMouseX = e.clientX;
  405. state.input.lastMouseY = e.clientY;
  406. });
  407. this.setupKeyMonitoring();
  408. debug.log("Input controller initialized");
  409. return true;
  410. },
  411. setupKeyMonitoring() {
  412. document.addEventListener('keydown', e => {
  413. state.input.activeKeys.add(e.code);
  414. if (e.code === config.game.controlOptions.crouchKey) debug.log(`Crouch key pressed (${e.code})`);
  415. if (e.code === config.aim.activationKey) debug.log(`Aim activation key (${e.code}) pressed.`);
  416. config.game.controlOptions.weaponKeys.forEach((k, i) => {
  417. if (e.code === k) {
  418. state.currentWeapon = i;
  419. debug.log(`Switched to weapon slot ${i + 1}`);
  420. }
  421. });
  422. });
  423. document.addEventListener('keyup', e => {
  424. state.input.activeKeys.delete(e.code);
  425. if (e.code === config.aim.activationKey) debug.log(`Aim activation key (${e.code}) released.`);
  426. });
  427. document.addEventListener('mousedown', e => {
  428. if (e.button === 0) state.input.leftButtonDown = true;
  429. if (e.button === 2) state.input.rightButtonDown = true;
  430. });
  431. document.addEventListener('mouseup', e => {
  432. if (e.button === 0) state.input.leftButtonDown = false;
  433. if (e.button === 2) state.input.rightButtonDown = false;
  434. });
  435. },
  436. moveMouseTo(tSX, tSY) {
  437. if (!state.gameVideo) return;
  438. const vR = state.gameVideo.getBoundingClientRect();
  439. if (!vR || vR.width === 0) return;
  440. const gVCX = vR.left + vR.width / 2;
  441. const gVCY = vR.top + vR.height / 2;
  442. let mX = tSX - gVCX;
  443. let mY = tSY - gVCY;
  444. if (Math.abs(mX) < 0.1 && Math.abs(mY) < 0.1 && state.recoilState.offsetX === 0 && state.recoilState.offsetY === 0) return;
  445. const sC = document.querySelector(config.game.containerSelector) || state.gameVideo || document.documentElement;
  446. const evt = new PointerEvent('pointermove', {
  447. bubbles: true, cancelable: true, view: window,
  448. clientX: Math.round(state.input.lastMouseX + mX), clientY: Math.round(state.input.lastMouseY + mY),
  449. screenX: Math.round(state.input.lastMouseX + mX), screenY: Math.round(state.input.lastMouseY + mY),
  450. movementX: Math.round(mX), movementY: Math.round(mY),
  451. buttons: (state.input.leftButtonDown ? 1 : 0) | (state.input.rightButtonDown ? 2 : 0),
  452. pointerType: 'mouse', isPrimary: true
  453. });
  454. sC.dispatchEvent(evt);
  455. },
  456. startShooting() {
  457. if (state.isShooting) return;
  458. const sC = document.querySelector(config.game.containerSelector) || state.gameVideo || document.documentElement;
  459. const evt = new PointerEvent('pointerdown', {
  460. bubbles: true, cancelable: true, view: window,
  461. clientX: Math.round(state.input.lastMouseX), clientY: Math.round(state.input.lastMouseY),
  462. button: 0, buttons: 1, pointerType: 'mouse', isPrimary: true
  463. });
  464. sC.dispatchEvent(evt);
  465. state.isShooting = true;
  466. state.recoilState.shotsFired = 0;
  467. debug.log("Shooting started (simulated by aimbot)");
  468. if (config.game.controlOptions.crouchOnShoot && !state.input.activeKeys.has(config.game.controlOptions.crouchKey)) {
  469. this.pressKey(config.game.controlOptions.crouchKey, 0);
  470. }
  471. },
  472. stopShooting() {
  473. if (!state.isShooting) return;
  474. const sC = document.querySelector(config.game.containerSelector) || state.gameVideo || document.documentElement;
  475. const evt = new PointerEvent('pointerup', {
  476. bubbles: true, cancelable: true, view: window,
  477. clientX: Math.round(state.input.lastMouseX), clientY: Math.round(state.input.lastMouseY),
  478. button: 0, buttons: 0, pointerType: 'mouse', isPrimary: true
  479. });
  480. sC.dispatchEvent(evt);
  481. state.isShooting = false;
  482. debug.log("Shooting stopped (simulated by aimbot)");
  483. if (config.game.controlOptions.crouchOnShoot && state.input.activeKeys.has(config.game.controlOptions.crouchKey)) {
  484. this.releaseKey(config.game.controlOptions.crouchKey);
  485. }
  486. },
  487. pressKey(kC, dur = 50) {
  488. const k = kC.replace(/^(Key|Digit)/, '');
  489. const eT = document.activeElement || document.body;
  490. const dE = new KeyboardEvent('keydown', {
  491. code: kC, key: k, keyCode: kC.startsWith('Digit') ? parseInt(k) : k.length === 1 ? k.charCodeAt(0) : 0,
  492. bubbles: true, cancelable: true, view: window
  493. });
  494. eT.dispatchEvent(dE);
  495. state.input.activeKeys.add(kC);
  496. if (dur > 0) setTimeout(() => this.releaseKey(kC), dur);
  497. },
  498. releaseKey(kC) {
  499. const k = kC.replace(/^(Key|Digit)/, '');
  500. const eT = document.activeElement || document.body;
  501. const uE = new KeyboardEvent('keyup', {
  502. code: kC, key: k, keyCode: kC.startsWith('Digit') ? parseInt(k) : k.length === 1 ? k.charCodeAt(0) : 0,
  503. bubbles: true, cancelable: true, view: window
  504. });
  505. eT.dispatchEvent(uE);
  506. state.input.activeKeys.delete(kC);
  507. },
  508. reload() {
  509. this.pressKey(config.game.controlOptions.reloadKey, 50);
  510. debug.log("Reload key pressed");
  511. },
  512. switchWeapon(sI) {
  513. if (sI >= 0 && sI < config.game.controlOptions.weaponKeys.length) {
  514. this.pressKey(config.game.controlOptions.weaponKeys[sI], 50);
  515. state.currentWeapon = sI;
  516. debug.log(`Switched to weapon slot ${sI + 1}`);
  517. }
  518. }
  519. };
  520.  
  521. // === Visual Rendering Functions ===
  522. // These functions handle the overlay canvas and visual elements.
  523.  
  524. function createOverlayCanvas() {
  525. if (state.ui.overlayCanvas) return;
  526. const c = document.createElement('canvas');
  527. c.id = 'xcloud-aimbot-overlay';
  528. c.width = window.innerWidth;
  529. c.height = window.innerHeight;
  530. c.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:99999;';
  531. state.ui.overlayCanvas = c;
  532. state.ui.overlayCtx = c.getContext('2d');
  533. document.body.appendChild(c);
  534. window.addEventListener('resize', () => {
  535. c.width = window.innerWidth;
  536. c.height = window.innerHeight;
  537. });
  538. debug.log("Overlay canvas created");
  539. }
  540.  
  541. function drawCrosshair(vR) {
  542. if (!state.ui.overlayCtx || !config.visual.crosshair.enabled) return;
  543. const ctx = state.ui.overlayCtx;
  544. let cX, cY;
  545. if (config.visual.crosshair.centerOnGameScreen && vR && vR.width > 0) {
  546. cX = vR.left + vR.width / 2;
  547. cY = vR.top + vR.height / 2;
  548. } else {
  549. cX = state.input.lastMouseX;
  550. cY = state.input.lastMouseY;
  551. }
  552. const s = config.visual.crosshair.size;
  553. ctx.strokeStyle = config.visual.crosshair.color;
  554. ctx.fillStyle = config.visual.crosshair.color;
  555. ctx.lineWidth = 1;
  556. switch (config.visual.crosshair.style) {
  557. case 'cross':
  558. ctx.beginPath();
  559. ctx.moveTo(cX - 2 * s, cY);
  560. ctx.lineTo(cX + 2 * s, cY);
  561. ctx.moveTo(cX, cY - 2 * s);
  562. ctx.lineTo(cX, cY + 2 * s);
  563. ctx.stroke();
  564. break;
  565. case 'dot':
  566. ctx.beginPath();
  567. ctx.arc(cX, cY, s, 0, 2 * Math.PI);
  568. ctx.fill();
  569. break;
  570. case 'circle':
  571. ctx.beginPath();
  572. ctx.arc(cX, cY, 2 * s, 0, 2 * Math.PI);
  573. ctx.stroke();
  574. break;
  575. }
  576. return { x: cX, y: cY };
  577. }
  578.  
  579. function drawKeypoints(ps, vR) {
  580. if (!config.visual.keypoints.enabled || !state.ui.overlayCtx || !ps || ps.length === 0 || !vR) return;
  581. const ctx = state.ui.overlayCtx;
  582. ps.forEach(p => {
  583. if (p.keypoints) {
  584. p.keypoints.forEach(kP => {
  585. if (kP.score && kP.score >= config.detection.keypointConfidence) {
  586. const sX = vR.left + kP.x / state.gameVideo.videoWidth * vR.width;
  587. const sY = vR.top + kP.y / state.gameVideo.videoHeight * vR.height;
  588. ctx.beginPath();
  589. ctx.arc(sX, sY, config.visual.keypoints.radius, 0, 2 * Math.PI);
  590. ctx.fillStyle = config.visual.keypoints.color;
  591. ctx.fill();
  592. }
  593. });
  594. }
  595. });
  596. }
  597.  
  598. function drawBoundingBoxes(ps, vR) {
  599. if (!config.visual.boundingBoxes.enabled || !state.ui.overlayCtx || !ps || ps.length === 0 || !vR) return;
  600. const ctx = state.ui.overlayCtx;
  601. ps.forEach(p => {
  602. const [vBx, vBy, vBw, vBh] = p.bbox;
  603. const sX = vR.left + vBx / state.gameVideo.videoWidth * vR.width;
  604. const sY = vR.top + vBy / state.gameVideo.videoHeight * vR.height;
  605. const sW = vBw / state.gameVideo.videoWidth * vR.width;
  606. const sH = vBh / state.gameVideo.videoHeight * vR.height;
  607. ctx.strokeStyle = config.visual.boundingBoxes.color;
  608. ctx.lineWidth = config.visual.boundingBoxes.lineWidth;
  609. ctx.fillStyle = config.visual.boundingBoxes.fillColor;
  610. ctx.fillRect(sX, sY, sW, sH);
  611. ctx.strokeRect(sX, sY, sW, sH);
  612. if (config.visual.boundingBoxes.showInfo) {
  613. ctx.fillStyle = config.visual.boundingBoxes.color;
  614. ctx.font = '12px Arial';
  615. const sT = `${(100 * p.score).toFixed(0)}%`;
  616. ctx.fillText(sT, sX + 5, sY + 15);
  617. if (p.keypoints && config.visual.boundingBoxes.fromKeypoints) {
  618. const kC = p.keypoints.filter(kP => kP.score >= config.detection.keypointConfidence).length;
  619. ctx.fillText(`KPs: ${kC}`, sX + 5, sY + 30);
  620. }
  621. }
  622. });
  623. }
  624.  
  625. const SKELETON_CONNECTIONS = [
  626. ['left_shoulder', 'right_shoulder'], ['left_hip', 'right_hip'], ['left_shoulder', 'left_hip'], ['right_shoulder', 'right_hip'],
  627. ['left_shoulder', 'left_elbow'], ['left_elbow', 'left_wrist'], ['right_shoulder', 'right_elbow'], ['right_elbow', 'right_wrist'],
  628. ['left_hip', 'left_knee'], ['left_knee', 'left_ankle'], ['right_hip', 'right_knee'], ['right_knee', 'right_ankle'],
  629. ];
  630.  
  631. function drawSkeleton(players, videoRect) {
  632. if (!config.visual.skeleton.enabled || !state.ui.overlayCtx || !players || players.length === 0 || !videoRect) return;
  633. const ctx = state.ui.overlayCtx;
  634. ctx.strokeStyle = config.visual.skeleton.color;
  635. ctx.lineWidth = config.visual.skeleton.lineWidth;
  636. players.forEach(player => {
  637. if (player.keypoints) {
  638. const keypointsMap = new Map();
  639. player.keypoints.forEach(kp => {
  640. if (kp.score && kp.score >= config.detection.keypointConfidence) {
  641. keypointsMap.set(kp.name, {
  642. x: videoRect.left + (kp.x / state.gameVideo.videoWidth) * videoRect.width,
  643. y: videoRect.top + (kp.y / state.gameVideo.videoHeight) * videoRect.height
  644. });
  645. }
  646. });
  647. SKELETON_CONNECTIONS.forEach(pair => {
  648. const kp1 = keypointsMap.get(pair[0]);
  649. const kp2 = keypointsMap.get(pair[1]);
  650. if (kp1 && kp2) {
  651. ctx.beginPath();
  652. ctx.moveTo(kp1.x, kp1.y);
  653. ctx.lineTo(kp2.x, kp2.y);
  654. ctx.stroke();
  655. }
  656. });
  657. }
  658. });
  659. }
  660.  
  661. function drawTargetLockIndicator(t, vR) {
  662. if (!config.visual.targetLock.enabled || !state.ui.overlayCtx || !t || !vR) return null;
  663. const ctx = state.ui.overlayCtx;
  664. const [vBx, vBy, vBw, vBh] = t.prediction.bbox;
  665. const bSX = vR.left + vBx / state.gameVideo.videoWidth * vR.width;
  666. const bSY = vR.top + vBy / state.gameVideo.videoHeight * vR.height;
  667. const bSW = vBw / state.gameVideo.videoWidth * vR.width;
  668. const bSH = vBh / state.gameVideo.videoHeight * vR.height;
  669. ctx.strokeStyle = config.visual.targetLock.color;
  670. ctx.lineWidth = 2;
  671. const cS = 0.2 * Math.min(bSW, bSH);
  672. switch (config.visual.targetLock.style) {
  673. case 'full':
  674. ctx.strokeRect(bSX, bSY, bSW, bSH);
  675. break;
  676. case 'corners':
  677. ctx.beginPath();
  678. ctx.moveTo(bSX + cS, bSY); ctx.lineTo(bSX, bSY); ctx.lineTo(bSX, bSY + cS);
  679. ctx.moveTo(bSX + bSW - cS, bSY); ctx.lineTo(bSX + bSW, bSY); ctx.lineTo(bSX + bSW, bSY + cS);
  680. ctx.moveTo(bSX + cS, bSY + bSH); ctx.lineTo(bSX, bSY + bSH); ctx.lineTo(bSX, bSY + bSH - cS);
  681. ctx.moveTo(bSX + bSW - cS, bSY + bSH); ctx.lineTo(bSX + bSW, bSY + bSH); ctx.lineTo(bSX + bSW, bSY + bSH - cS);
  682. ctx.stroke();
  683. break;
  684. case 'crosshair':
  685. const cSz = 10;
  686. ctx.beginPath();
  687. ctx.moveTo(t.screenPosition.x - cSz, t.screenPosition.y);
  688. ctx.lineTo(t.screenPosition.x + cSz, t.screenPosition.y);
  689. ctx.moveTo(t.screenPosition.x, t.screenPosition.y - cSz);
  690. ctx.lineTo(t.screenPosition.x, t.screenPosition.y + cSz);
  691. ctx.stroke();
  692. break;
  693. }
  694. return { x: bSX, y: bSY, width: bSW, height: bSH };
  695. }
  696.  
  697. function drawFOVCircle(vR) {
  698. if (!config.visual.fovCircle.enabled || !state.ui.overlayCtx) return;
  699. if (config.visual.fovCircle.showOnlyWhenAiming && !state.input.activeKeys.has(config.aim.activationKey)) return;
  700. const ctx = state.ui.overlayCtx;
  701. let cX, cY;
  702. if (config.visual.fovCircle.centerOnGameScreen && vR && vR.width > 0) {
  703. cX = vR.left + vR.width / 2;
  704. cY = vR.top + vR.height / 2;
  705. } else {
  706. cX = state.input.lastMouseX;
  707. cY = state.input.lastMouseY;
  708. }
  709. ctx.strokeStyle = config.visual.fovCircle.color;
  710. ctx.lineWidth = config.visual.fovCircle.lineWidth;
  711. ctx.beginPath();
  712. ctx.arc(cX, cY, config.aim.fovRadius, 0, 2 * Math.PI);
  713. ctx.stroke();
  714. }
  715.  
  716. function drawPerformanceMetrics() {
  717. if (!config.visual.performanceMetrics.enabled || !state.ui.overlayCtx) return;
  718. const ctx = state.ui.overlayCtx;
  719. const ms = [
  720. `FPS: ${state.performance.fps}`,
  721. `Detect: ${state.performance.detectionTime.toFixed(1)}ms (Avg: ${state.performance.avgDetectionTime.toFixed(1)}ms)`,
  722. `Skip Frames: ${config.detection.skipFrames}`
  723. ];
  724. ctx.font = '14px Arial';
  725. ctx.fillStyle = 'rgba(0,255,0,0.8)';
  726. const lH = 16;
  727. let sX = 10, sY = 20;
  728. switch (config.visual.performanceMetrics.position) {
  729. case 'top-right':
  730. sX = state.ui.overlayCanvas.width - 200;
  731. break;
  732. case 'bottom-left':
  733. sY = state.ui.overlayCanvas.height - ms.length * lH - 10;
  734. break;
  735. case 'bottom-right':
  736. sX = state.ui.overlayCanvas.width - 200;
  737. sY = state.ui.overlayCanvas.height - ms.length * lH - 10;
  738. break;
  739. }
  740. ms.forEach((m, i) => ctx.fillText(m, sX, sY + i * lH));
  741. }
  742.  
  743. function drawDebugInfo() {
  744. if (!config.visual.showDebugInfo || !state.ui.overlayCtx) return;
  745. const ctx = state.ui.overlayCtx;
  746. const aimingActive = state.input.activeKeys.has(config.aim.activationKey);
  747. const dL = [
  748. `Target: ${state.currentTarget ? `Yes (Score: ${state.currentTarget.score.toFixed(2)})` : "No"}`,
  749. `Shooting: ${state.isShooting ? "Yes" : "No"} | Aiming (${config.aim.activationKey.replace('Key', '')})${aimingActive ? " (Active)" : " (Inactive)"}`,
  750. `Recoil X: ${state.recoilState.offsetX.toFixed(2)} Y: ${state.recoilState.offsetY.toFixed(2)}`,
  751. `OS Mouse: X:${state.input.lastMouseX.toFixed(0)} Y:${state.input.lastMouseY.toFixed(0)}`
  752. ];
  753. ctx.font = '12px Arial';
  754. ctx.fillStyle = 'rgba(255,255,0,0.8)';
  755. const lH = 15;
  756. let sY = 80;
  757. if (config.visual.performanceMetrics.enabled && config.visual.performanceMetrics.position === 'top-left') {
  758. sY = 20 + (state.performance.fps > 0 ? 3 : 2) * 16 + 20;
  759. }
  760. let sX = 10;
  761. if (config.visual.performanceMetrics.enabled && config.visual.performanceMetrics.position === 'bottom-left' && config.visual.showDebugInfo) {
  762. sY = state.ui.overlayCanvas.height - (state.performance.fps > 0 ? 3 : 2) * 16 - 10 - dL.length * lH - 10;
  763. }
  764. dL.forEach((l, i) => ctx.fillText(l, sX, sY + i * lH));
  765. }
  766.  
  767. function drawVisuals(players, currentTarget, hasTargetInFOV) {
  768. if (!state.ui.overlayCtx) return;
  769. const ctx = state.ui.overlayCtx;
  770. const canvas = state.ui.overlayCanvas;
  771. ctx.clearRect(0, 0, canvas.width, canvas.height);
  772. const videoRect = state.gameVideo ? state.gameVideo.getBoundingClientRect() : null;
  773. const isAimKeyHeld = state.input.activeKeys.has(config.aim.activationKey);
  774.  
  775. // Always draw crosshair and FOV circle (if enabled and aim key is held)
  776. const crosshairPos = config.visual.crosshair.enabled ? drawCrosshair(videoRect) : null;
  777. if (config.visual.fovCircle.enabled && (!config.visual.fovCircle.showOnlyWhenAiming || isAimKeyHeld)) {
  778. drawFOVCircle(videoRect);
  779. }
  780.  
  781. // Draw performance metrics and debug info regardless of targets
  782. if (config.visual.performanceMetrics.enabled) drawPerformanceMetrics();
  783. if (config.visual.showDebugInfo) drawDebugInfo();
  784.  
  785. // Only draw player-related visuals if there is a target in FOV and aim key is held
  786. if (hasTargetInFOV && isAimKeyHeld && videoRect && videoRect.width > 0) {
  787. if (config.visual.keypoints.enabled) drawKeypoints(players, videoRect);
  788. if (config.visual.skeleton.enabled) drawSkeleton(players, videoRect);
  789. if (config.visual.targetLock.enabled && currentTarget) {
  790. const targetLockRect = drawTargetLockIndicator(currentTarget, videoRect);
  791. // Check if crosshair is inside target lock for instant shooting
  792. if (config.game.autoShoot && crosshairPos && targetLockRect && isAimKeyHeld) {
  793. const { x: cX, y: cY } = crosshairPos;
  794. const { x: tX, y: tY, width: tW, height: tH } = targetLockRect;
  795. if (cX >= tX && cX <= tX + tW && cY >= tY && cY <= tY + tH) {
  796. if (!state.isShooting) {
  797. InputController.startShooting();
  798. }
  799. } else if (state.isShooting && !config.game.triggerOptions.burstMode) {
  800. InputController.stopShooting();
  801. }
  802. }
  803. }
  804. } else if (state.isShooting && !config.game.triggerOptions.burstMode) {
  805. InputController.stopShooting();
  806. }
  807. }
  808.  
  809. // === Recoil and Aiming Logic ===
  810. // Handles recoil compensation and aiming mechanics.
  811.  
  812. function applyRecoilCompensation() {
  813. if (!config.game.recoilCompensation) {
  814. if (state.recoilState.offsetX !== 0 || state.recoilState.offsetY !== 0) {
  815. const rS = config.game.recoilPatterns[config.game.recoilLevel] || config.game.recoilPatterns[1];
  816. state.recoilState.offsetX *= (1 - rS.recoverySpeed);
  817. state.recoilState.offsetY *= (1 - rS.recoverySpeed);
  818. if (Math.abs(state.recoilState.offsetX) < 0.01) state.recoilState.offsetX = 0;
  819. if (Math.abs(state.recoilState.offsetY) < 0.01) state.recoilState.offsetY = 0;
  820. }
  821. return;
  822. }
  823. const rS = config.game.recoilPatterns[config.game.recoilLevel] || config.game.recoilPatterns[1];
  824. const now = performance.now();
  825. if (state.input.leftButtonDown && !state.recoilState.lastLeftButtonState) {
  826. state.recoilState.shotsFired = 0;
  827. state.recoilState.active = true;
  828. }
  829. state.recoilState.lastLeftButtonState = state.input.leftButtonDown;
  830. if (state.input.leftButtonDown && state.recoilState.active) {
  831. if (state.recoilState.shotsFired === 0 || now - state.recoilState.lastShotTime > 200) {
  832. const kM = 1.0;
  833. state.recoilState.offsetY = -(rS.vertical * kM);
  834. state.recoilState.offsetX = (Math.random() - 0.5) * 2 * rS.horizontal * kM;
  835. } else {
  836. state.recoilState.offsetY -= rS.vertical * (0.2 + 0.5 * Math.random());
  837. state.recoilState.offsetX += (Math.random() - 0.5) * rS.horizontal * 1.5;
  838. }
  839. state.recoilState.offsetY = Math.max(state.recoilState.offsetY, -(rS.vertical * 4));
  840. state.recoilState.offsetX = Math.min(Math.abs(state.recoilState.offsetX), rS.horizontal * 2.5) * (state.recoilState.offsetX < 0 ? -1 : 1);
  841. if ((Math.abs(state.recoilState.offsetX) > 0.01 || Math.abs(state.recoilState.offsetY) > 0.01) && state.gameVideo) {
  842. const evt = new PointerEvent('pointermove', {
  843. bubbles: true, cancelable: true, view: window,
  844. movementX: Math.round(state.recoilState.offsetX), movementY: Math.round(state.recoilState.offsetY),
  845. buttons: (state.input.leftButtonDown ? 1 : 0) | (state.input.rightButtonDown ? 2 : 0),
  846. pointerType: 'mouse', isPrimary: true
  847. });
  848. (document.querySelector(config.game.containerSelector) || state.gameVideo || document.documentElement).dispatchEvent(evt);
  849. }
  850. state.recoilState.shotsFired++;
  851. state.recoilState.lastShotTime = now;
  852. state.recoilState.offsetX *= (1 - (rS.recoverySpeed * 1.5));
  853. state.recoilState.offsetY *= (1 - (rS.recoverySpeed * 1.5));
  854. } else {
  855. state.recoilState.active = false;
  856. if (state.recoilState.offsetX !== 0 || state.recoilState.offsetY !== 0) {
  857. state.recoilState.offsetX *= (1 - rS.recoverySpeed);
  858. state.recoilState.offsetY *= (1 - rS.recoverySpeed);
  859. if (Math.abs(state.recoilState.offsetX) < 0.01) state.recoilState.offsetX = 0;
  860. if (Math.abs(state.recoilState.offsetY) < 0.01) state.recoilState.offsetY = 0;
  861. }
  862. }
  863. }
  864.  
  865. async function processAiming(timestamp) {
  866. if (config.game.recoilCompensation) {
  867. applyRecoilCompensation();
  868. }
  869. const isAimKeyHeld = state.input.activeKeys.has(config.aim.activationKey);
  870. if (!isAimKeyHeld || !config.detection.enabled || !state.modelLoaded) {
  871. state.currentTarget = null;
  872. drawVisuals([], null, false);
  873. if (state.isShooting && !config.game.triggerOptions.burstMode) {
  874. InputController.stopShooting();
  875. }
  876. return;
  877. }
  878. const videoRect = state.gameVideo ? state.gameVideo.getBoundingClientRect() : null;
  879. const players = await detectPlayers(videoRect);
  880. const newTarget = findBestTarget(players, videoRect);
  881. const hasTargetInFOV = newTarget !== null;
  882.  
  883. if (newTarget) {
  884. if (!state.currentTarget || newTarget.prediction !== state.currentTarget.prediction) {
  885. const now = performance.now();
  886. if (!state.currentTarget || now - state.lastTargetSwitch > config.aim.targetSwitchCooldown) {
  887. debug.log(`New target acquired: Score ${newTarget.score.toFixed(2)}, dist: ${newTarget.distance.toFixed(0)}px`);
  888. state.currentTarget = newTarget;
  889. state.lastTargetSwitch = now;
  890. }
  891. } else {
  892. state.currentTarget = newTarget;
  893. }
  894. } else {
  895. state.currentTarget = null;
  896. }
  897. drawVisuals(players, state.currentTarget, hasTargetInFOV);
  898. if (state.currentTarget) {
  899. let { x: targetX, y: targetY } = state.currentTarget.screenPosition;
  900. InputController.moveMouseTo(targetX, targetY);
  901. }
  902. }
  903.  
  904. async function detectPlayers(videoRect) {
  905. if (!state.input.activeKeys.has(config.aim.activationKey)) {
  906. return [];
  907. }
  908. if (!state.gameVideo || !state.modelLoaded || !state.detectionModel ||
  909. state.gameVideo.paused || state.gameVideo.ended ||
  910. state.gameVideo.videoWidth === 0 || state.gameVideo.videoHeight === 0 || !videoRect) {
  911. return [];
  912. }
  913. if (state.frameCount % (config.detection.skipFrames + 1) !== 0) {
  914. state.frameCount++;
  915. return [];
  916. }
  917. state.frameCount++;
  918. const now = performance.now();
  919. if (now - state.lastDetectionTime < config.detection.processingInterval) {
  920. return [];
  921. }
  922. let videoSource = state.gameVideo;
  923. if (config.detection.ignoreSelfRegion.enabled) {
  924. if (!state.ui.offscreenCanvas) {
  925. state.ui.offscreenCanvas = document.createElement('canvas');
  926. state.ui.offscreenCtx = state.ui.offscreenCanvas.getContext('2d');
  927. }
  928. if (state.ui.offscreenCanvas.width !== state.gameVideo.videoWidth || state.ui.offscreenCanvas.height !== state.gameVideo.videoHeight) {
  929. state.ui.offscreenCanvas.width = state.gameVideo.videoWidth;
  930. state.ui.offscreenCanvas.height = state.gameVideo.videoHeight;
  931. }
  932. const ctx = state.ui.offscreenCtx;
  933. ctx.drawImage(state.gameVideo, 0, 0, state.gameVideo.videoWidth, state.gameVideo.videoHeight);
  934. const region = config.detection.ignoreSelfRegion;
  935. const rectX = state.gameVideo.videoWidth * region.xPercent;
  936. const rectY = state.gameVideo.videoHeight * region.yPercent;
  937. const rectW = state.gameVideo.videoWidth * region.widthPercent;
  938. const rectH = state.gameVideo.videoHeight * region.heightPercent;
  939. ctx.fillStyle = 'rgba(0, 0, 0, 1)';
  940. ctx.fillRect(rectX, rectY, rectW, rectH);
  941. videoSource = state.ui.offscreenCanvas;
  942. }
  943. try {
  944. const detectionStart = performance.now();
  945. const poses = await state.detectionModel.estimatePoses(videoSource, { flipHorizontal: false });
  946. const detectionEnd = performance.now();
  947. state.performance.detectionTime = detectionEnd - detectionStart;
  948. state.performance.detectionTimeHistory.push(state.performance.detectionTime);
  949. if (state.performance.detectionTimeHistory.length > 30) state.performance.detectionTimeHistory.shift();
  950. state.performance.avgDetectionTime = state.performance.detectionTimeHistory.reduce((a, b) => a + b, 0) / state.performance.detectionTimeHistory.length;
  951. state.lastDetectionTime = now;
  952.  
  953. // Dynamic Frame-Skipping Logic
  954. if (config.detection.dynamicFrameSkipping.enabled) {
  955. const dynConfig = config.detection.dynamicFrameSkipping;
  956. const prevSkipFrames = config.detection.skipFrames;
  957.  
  958. // Increase skipFrames if performance is poor
  959. if (state.performance.avgDetectionTime > dynConfig.highDetectionTimeThreshold || state.performance.fps < dynConfig.fpsThresholdLow) {
  960. config.detection.skipFrames = Math.min(config.detection.skipFrames + 1, dynConfig.maxSkipFrames);
  961. }
  962. // Decrease skipFrames if performance is good
  963. else if (state.performance.avgDetectionTime < dynConfig.lowDetectionTimeThreshold && state.performance.fps > dynConfig.fpsThresholdHigh) {
  964. config.detection.skipFrames = Math.max(config.detection.skipFrames - 1, dynConfig.minSkipFrames);
  965. }
  966.  
  967. // Log changes to skipFrames
  968. if (prevSkipFrames !== config.detection.skipFrames) {
  969. debug.log(`Dynamic frame-skipping adjusted: skipFrames=${config.detection.skipFrames} (FPS: ${state.performance.fps}, Avg Detect: ${state.performance.avgDetectionTime.toFixed(1)}ms)`);
  970. }
  971. }
  972.  
  973. const results = [];
  974. if (poses && poses.length > 0) {
  975. const fovCenterX = config.visual.fovCircle.centerOnGameScreen ? (videoRect.left + videoRect.width / 2) : state.input.lastMouseX;
  976. const fovCenterY = config.visual.fovCircle.centerOnGameScreen ? (videoRect.top + videoRect.height / 2) : state.input.lastMouseY;
  977.  
  978. for (const pose of poses) {
  979. if (pose.score && pose.score >= config.detection.detectorConfig.minPoseScore) {
  980. const bbox = calculateBoundingBoxFromKeypoints(pose.keypoints);
  981. if (bbox && bbox.width > 0 && bbox.height > 0) {
  982. // Calculate center of bounding box in screen coordinates
  983. const sX = videoRect.left + (bbox.x + bbox.width / 2) / state.gameVideo.videoWidth * videoRect.width;
  984. const sY = videoRect.top + (bbox.y + bbox.height / 2) / state.gameVideo.videoHeight * videoRect.height;
  985. const dx_fov = sX - fovCenterX;
  986. const dy_fov = sY - fovCenterY;
  987. // Only include poses within FOV
  988. if (Math.sqrt(dx_fov * dx_fov + dy_fov * dy_fov) <= config.aim.fovRadius) {
  989. results.push({ class: 'person', score: pose.score, bbox: [bbox.x, bbox.y, bbox.width, bbox.height], keypoints: pose.keypoints });
  990. }
  991. }
  992. }
  993. }
  994. }
  995. return results.slice(0, config.detection.maxDetections);
  996. } catch (err) {
  997. debug.error("Error during pose estimation:", err);
  998. return [];
  999. }
  1000. }
  1001.  
  1002. // === GUI and Initialization ===
  1003. // Handles the recoil tuning GUI and aimbot startup.
  1004.  
  1005. function createRecoilTuningGUI() {
  1006. if (!config.visual.showRecoilTunerGUI) return;
  1007. const guiContainer = document.createElement('div');
  1008. guiContainer.id = 'aimbot-recoil-gui';
  1009. guiContainer.style.cssText = `position: fixed; top: 280px; right: 10px; background-color: rgba(30, 30, 30, 0.85); border: 1px solid #555; border-radius: 5px; padding: 10px; color: white; font-family: Arial, sans-serif; font-size: 12px; z-index: 1000001; display: flex; flex-direction: column; gap: 8px; width: 250px;`;
  1010. guiContainer.innerHTML = '<h4 style="margin:0 0 8px 0; text-align:center; font-size: 14px;">Anti-Recoil Tuner</h4>';
  1011. const levelDiv = document.createElement('div');
  1012. levelDiv.style.display = 'flex';
  1013. levelDiv.style.alignItems = 'center';
  1014. levelDiv.style.justifyContent = 'space-between';
  1015. const levelLabel = document.createElement('label');
  1016. levelLabel.textContent = 'Recoil Level:';
  1017. levelLabel.htmlFor = 'recoilLevelSlider';
  1018. levelLabel.style.marginRight = '8px';
  1019. levelLabel.style.whiteSpace = 'nowrap';
  1020. const levelSlider = document.createElement('input');
  1021. levelSlider.type = 'range';
  1022. levelSlider.id = 'recoilLevelSlider';
  1023. levelSlider.min = 1;
  1024. levelSlider.max = 5;
  1025. levelSlider.step = 1;
  1026. levelSlider.value = config.game.recoilLevel;
  1027. levelSlider.style.width = '100px';
  1028. levelSlider.style.flexGrow = '1';
  1029. const levelValueDisplay = document.createElement('span');
  1030. levelValueDisplay.textContent = config.game.recoilLevel;
  1031. levelValueDisplay.style.marginLeft = '8px';
  1032. levelValueDisplay.style.width = '24px';
  1033. levelValueDisplay.style.textAlign = 'right';
  1034. levelSlider.addEventListener('input', () => {
  1035. config.game.recoilLevel = parseInt(levelSlider.value);
  1036. levelValueDisplay.textContent = levelSlider.value;
  1037. debug.log(`Recoil level set to: ${config.game.recoilLevel}`);
  1038. });
  1039. levelDiv.appendChild(levelLabel);
  1040. levelDiv.appendChild(levelSlider);
  1041. levelDiv.appendChild(levelValueDisplay);
  1042. guiContainer.appendChild(levelDiv);
  1043. document.body.appendChild(guiContainer);
  1044. debug.log("Recoil tuning GUI created.");
  1045. }
  1046.  
  1047. function startAimbotLoop() {
  1048. debug.log("Starting main aimbot loop");
  1049. let loopActive = true;
  1050. async function mainLoop(timestamp) {
  1051. if (!loopActive) return;
  1052. requestAnimationFrame(mainLoop);
  1053. state.performance.framesThisSecond++;
  1054. if (timestamp - state.performance.lastFpsUpdate >= 1000) {
  1055. state.performance.fps = state.performance.framesThisSecond;
  1056. state.performance.framesThisSecond = 0;
  1057. state.performance.lastFpsUpdate = timestamp;
  1058. }
  1059. if (!state.gameVideo || state.gameVideo.paused || state.gameVideo.ended || state.gameVideo.videoWidth === 0) {
  1060. if (state.isShooting) InputController.stopShooting();
  1061. if (state.ui.overlayCtx) state.ui.overlayCtx.clearRect(0, 0, state.ui.overlayCanvas.width, state.ui.overlayCanvas.height);
  1062. state.currentTarget = null;
  1063. return;
  1064. }
  1065. await processAiming(timestamp);
  1066. }
  1067. requestAnimationFrame(mainLoop);
  1068. }
  1069.  
  1070. async function initializeAimbot() {
  1071. debug.log(`Initializing Aimbot V${config.version} (MoveNet)...`);
  1072. state.gameVideo = document.querySelector(config.game.videoSelector);
  1073. if (!state.gameVideo) {
  1074. debug.error("Game video element not found. Retrying...");
  1075. showNotification("Error: Game video not found! Aimbot cannot start.", "error", 5000);
  1076. setTimeout(initializeAimbot, 3000);
  1077. return;
  1078. }
  1079. debug.log("Game video element found:", state.gameVideo);
  1080. if (state.gameVideo.readyState < state.gameVideo.HAVE_METADATA) {
  1081. debug.log("Waiting for video metadata...");
  1082. try {
  1083. await new Promise((rs, rj) => {
  1084. state.gameVideo.onloadedmetadata = rs;
  1085. state.gameVideo.onerror = rj;
  1086. });
  1087. debug.log(`Video metadata loaded: ${state.gameVideo.videoWidth}x${state.gameVideo.videoHeight}`);
  1088. } catch (vE) {
  1089. debug.error("Error loading video metadata:", vE);
  1090. showNotification("Error loading video. Aimbot might not work correctly.", "error");
  1091. setTimeout(initializeAimbot, 5000);
  1092. return;
  1093. }
  1094. } else {
  1095. debug.log(`Video dimensions readily available: ${state.gameVideo.videoWidth}x${state.gameVideo.videoHeight}`);
  1096. }
  1097. createOverlayCanvas();
  1098. if (config.visual.showRecoilTunerGUI) {
  1099. createRecoilTuningGUI();
  1100. }
  1101. if (!InputController.init()) {
  1102. debug.error("Input controller failed to initialize.");
  1103. showNotification("Error: Input controller init failed!", "error");
  1104. return;
  1105. }
  1106. if (config.detection.enabled) {
  1107. if (!await loadDetectionModel()) debug.error("Detection model (MoveNet) failed to load. Detection features disabled.");
  1108. } else {
  1109. debug.log("Detection is disabled in config.");
  1110. showNotification("AI Detection is disabled.", "info");
  1111. }
  1112. startAimbotLoop();
  1113. debug.log("Aimbot (MoveNet) initialized and main loop started.");
  1114. showNotification(`Precision Aimbot V${config.version} (MoveNet) Initialized!`, "info");
  1115. }
  1116.  
  1117. if (document.readyState === 'complete' || document.readyState === 'interactive') {
  1118. setTimeout(initializeAimbot, 2500);
  1119. } else {
  1120. window.addEventListener('load', () => setTimeout(initializeAimbot, 2500));
  1121. }
  1122. })();
Add Comment
Please, Sign In to add comment