shellshock.io aimbot. Hold RMB to snap to nearest enemy (with optional lead/prediction). Press V to toggle red wireframe ESP boxes + tracers (see through walls). Press ` (backtick) to show/hide the settings menu.
// ==UserScript== // @name Shell Shockers Aimbot + ESP // @namespace https://greasyfork.org/users/1603179-caringjellyemu // @version 2.1 // @author caringjellyemu // @license GPL-3.0-only // @match https://shellshock.io/* // @grant unsafeWindow // @run-at document-start // @require https://cdn.jsdelivr.net/npm/[email protected]/babylon.min.js // @description shellshock.io aimbot. Hold RMB to snap to nearest enemy (with optional lead/prediction). Press V to toggle red wireframe ESP boxes + tracers (see through walls). Press ` (backtick) to show/hide the settings menu. // @supportURL https://greasyfork.org/users/1603179-caringjellyemu // ==/UserScript== /* * Shell Shockers Aimbot + ESP * Copyright (c) 2026 caringjellyemu. All rights reserved where applicable. * * Licensed under the GNU General Public License v3.0 only (GPL-3.0-only). * You are free to use, study, modify, and redistribute this software under * the terms of that license, PROVIDED THAT: * 1. This copyright notice and the attribution below are preserved intact * in all copies and derivative works. * 2. Any redistribution or derivative work remains licensed under * GPL-3.0-only and discloses its complete corresponding source. * 3. The original author(s) are credited and not misrepresented as the * author of an unmodified or trivially-modified copy. * * Removing or altering these notices, or republishing this work (in whole or * in part) under different authorship, violates the GPL-3.0 license and is * grounds for a takedown / attribution complaint. * * ── Attribution / lineage ────────────────────────────────────────────────── * This script is a derivative work. Portions originate from: * • onlypuppy7 — "LibertyMutualV1" (GPL-3.0) * https://github.com/onlypuppy7/LibertyMutualShellShockers/ * • StateFarm client — `predictPosition` lead/gravity algorithm (ported) * Original authorship of the modifications and additions herein: * • caringjellyemu — 2026 * ──────────────────────────────────────────────────────────────────────────── */ (function () { 'use strict'; // ──────────────────────────────────────────────────────────────────────── // STATE + SETTINGS // ──────────────────────────────────────────────────────────────────────── let RMB = false; let H = {}; const ss = {}; // Per-frame snapshot. `hasLock` is true only on frames where RMB is held // and a valid enemy was picked — it drives the overlay's // "locked, idle / lead / waiting" state line. `me` is a cached reference // to the local player (used by the Nyx banner). const _aim = { hasLock: false, me: null, }; const _pred = { enabled: false, active: false, airborne: false, speed: 0, t: 0, leadDist: 0, projSpeed: 0, }; let nyxBannerEl = null; // Tuning constants — picked, not exposed in the menu. const SENSITIVITY = 0.0025; // mouse-pixels → yaw radians const PROJECTILE_SPEED = 80; // fallback bullet speed when weapon lookup fails // Prediction now runs in the game's native PER-TICK units inside // predictPositionSF (gravity -0.012/tick², terminal 0.29/tick, +1-tick lead // bias), reading the game's own velocity vector — no per-second conversion // or mesh-derived velocity tracking is needed anymore. const SETTINGS_KEY = 'ssh_settings_v1'; const DEFAULT_SETTINGS = { aimEnabled: true, crosshairTarget: false, // ON = target the enemy nearest your crosshair; OFF = nearest by distance onlyVisible: false, // ON = never target enemies behind walls; OFF = prioritise visible, fall back to nearest espEnabled: false, predEnabled: true, unlockSkins: true, itemEsp: true, menuVisible: true, }; const settings = Object.assign({}, DEFAULT_SETTINGS); try { const saved = JSON.parse(localStorage.getItem(SETTINGS_KEY) || '{}'); Object.assign(settings, saved); delete settings.noSpread; // removed: old spread-zero flag delete settings.antiBloom; // removed: anti-bloom feature delete settings.antiBloomManual; // removed: anti-bloom manual mode } catch (e) {} function saveSettings() { try { localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings)); } catch (e) {} // Mirror to the page's global so bundle-side patches can read these // flags without crossing the userscript sandbox. try { unsafeWindow.ssh_skinUnlock = settings.unlockSkins; } catch (e) {} } try { unsafeWindow.ssh_skinUnlock = settings.unlockSkins; } catch (e) {} let refreshMenu = () => {}; // replaced by buildMenu() once DOM exists const log = (...a) => console.log('%cShellhax', 'color:#000;background:#ff0;padding:2px 6px;border-radius:4px;font-weight:bold', ...a); log('started'); // Scan an object's own properties for one whose value has `propName` set. // Used to discover the obfuscated `actor` key dynamically — much more // robust than relying on a regex that may not match every build. // // `skip` excludes known false-positive keys. `weapon` carries its own // `.mesh` (the gun model), and was previously matching first — making // the prediction read gun-tip position instead of the body actor, so // velocity tracked gun rotation rather than player movement. function findKeyWithProperty(obj, propName, skip) { for (const k in obj) { if (!obj.hasOwnProperty(k)) continue; if (skip && skip.indexOf(k) !== -1) continue; const v = obj[k]; if (v && typeof v === 'object' && v.hasOwnProperty(propName)) return k; } return null; } // ──────────────────────────────────────────────────────────────────────── // INPUT — RMB for aim, V for ESP, ` to toggle menu // ──────────────────────────────────────────────────────────────────────── document.addEventListener('mousedown', e => { if (e.button === 2) RMB = true; }, true); document.addEventListener('mouseup', e => { if (e.button === 2) RMB = false; }, true); document.addEventListener('keydown', e => { const t = document.activeElement; if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA')) return; if (e.repeat) return; if (e.code === 'KeyV') { settings.espEnabled = !settings.espEnabled; saveSettings(); refreshMenu(); log('ESP', settings.espEnabled ? 'ON' : 'OFF'); } else if (e.code === 'Backquote') { settings.menuVisible = !settings.menuVisible; saveSettings(); refreshMenu(); } }, true); // ──────────────────────────────────────────────────────────────────────── // MENU — tiny on-screen panel, persists to localStorage. // ──────────────────────────────────────────────────────────────────────── function buildMenu() { if (document.getElementById('ssh-menu')) return; if (!document.body) { setTimeout(buildMenu, 50); return; } // Collapsible-category styling: each header is clickable and toggles // its body open/closed. Everything else matches the original panel. const css = document.createElement('style'); css.textContent = ` #ssh-menu .ssh-cat-hdr{cursor:pointer;padding:4px 0;font-weight:bold; border-top:1px solid #333;display:flex;justify-content:space-between;align-items:center} #ssh-menu .ssh-cat-body{display:none;padding-left:6px} #ssh-menu .ssh-cat.open .ssh-cat-body{display:block} #ssh-menu .ssh-arr{transition:transform .2s;font-size:9px;opacity:0.6} #ssh-menu .ssh-cat.open .ssh-arr{transform:rotate(90deg)} `; document.head.appendChild(css); const wrap = document.createElement('div'); wrap.id = 'ssh-menu'; wrap.style.cssText = [ 'position:fixed', 'top:12px', 'left:12px', 'z-index:2147483647', 'background:rgba(0,0,0,0.82)', 'color:#fff', 'font:12px/1.4 -apple-system,system-ui,sans-serif', 'padding:10px 12px', 'border-radius:6px', 'min-width:210px', 'border:1px solid #000000', 'user-select:none', 'box-shadow:0 2px 10px rgba(101, 0, 0, 0)', ].join(';'); wrap.innerHTML = ` <div style="font-weight:bold;color:#ff3b3b;margin-bottom:6px;display:flex;justify-content:space-between;align-items:center;"> <span>Shellhax</span> <span style="opacity:0.55;font-weight:normal;font-size:11px;">\` to hide</span> </div> <div class="ssh-cat open"> <div class="ssh-cat-hdr">Combat <span class="ssh-arr">▶</span></div> <div class="ssh-cat-body"> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="aimEnabled"> Aimbot <span style="opacity:0.55;">(hold RMB)</span></label> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="crosshairTarget"> Target Crosshair <span style="opacity:0.55;">(else closest)</span></label> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="onlyVisible"> Only Visible <span style="opacity:0.55;">(else prioritise)</span></label> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="predEnabled"> Prediction</label> </div> </div> <div class="ssh-cat open"> <div class="ssh-cat-hdr">ESP <span class="ssh-arr">▶</span></div> <div class="ssh-cat-body"> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="espEnabled"> ESP <span style="opacity:0.55;">(V)</span></label> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="itemEsp"> Item ESP <span style="opacity:0.55;">(ammo · grenades)</span></label> </div> </div> <div class="ssh-cat"> <div class="ssh-cat-hdr">Skins <span class="ssh-arr">▶</span></div> <div class="ssh-cat-body"> <label style="display:block;margin:3px 0;"><input type="checkbox" data-k="unlockSkins"> Unlock Skins</label> </div> </div> <div id="ssh-nyx" style="margin-top:6px;padding:6px 8px;border-radius:4px;background:rgba(180,80,255,0.18);border:1px solid rgba(180,80,255,0.55);color:#e9d5ff;font-size:11px;line-height:1.35;"> Join the <b>Nyx</b> wave — start your name with <b>Nyx</b> so we can spot each other. </div> `; document.body.appendChild(wrap); nyxBannerEl = wrap.querySelector('#ssh-nyx'); const inputs = wrap.querySelectorAll('[data-k]'); // Collapsible categories: clicking a header toggles its body open/closed. wrap.querySelectorAll('.ssh-cat-hdr').forEach(hdr => { hdr.addEventListener('click', () => hdr.parentElement.classList.toggle('open')); }); refreshMenu = () => { inputs.forEach(el => { const k = el.dataset.k; if (el.type === 'checkbox') el.checked = !!settings[k]; else el.value = settings[k]; }); wrap.style.display = settings.menuVisible ? '' : 'none'; }; refreshMenu(); inputs.forEach(el => { el.addEventListener('input', () => { const k = el.dataset.k; if (el.type === 'checkbox') { settings[k] = el.checked; } else { const n = parseFloat(el.value); settings[k] = Number.isFinite(n) ? n : DEFAULT_SETTINGS[k]; } saveSettings(); refreshMenu(); }); }); // Stop menu interactions from bleeding into the game. ['keydown','keyup','mousedown','mouseup','wheel','contextmenu'].forEach(ev => wrap.addEventListener(ev, e => e.stopPropagation(), true)); log('menu built'); } if (document.body) buildMenu(); else document.addEventListener('DOMContentLoaded', buildMenu); // ──────────────────────────────────────────────────────────────────────── // YAW/PITCH MECHANISM (trimmed port of babylon.js's `yawpitch` helper) // // shellshock.io's camera state lives in WASM. You cannot move the camera // by mutating player.yaw / player.pitch directly — the WASM module is the // source of truth. The only thing that DOES affect the camera is the // game's `pointermove` listener (named "real" in the bundle), which // converts movementX/Y into WASM look deltas. // // Steps: // 1. Hook addEventListener early to capture that listener. // 2. To turn the camera N radians, synthesize a fake pointermove event // with movementX = N/sensitivity and call the listener directly. // 3. After moving, read back the resulting yaw/pitch from the bundle's // `unsafeWindow.get_yaw_pitch()` helper. // ──────────────────────────────────────────────────────────────────────── let realPointerListener = null; const _origAEL = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function (type, listener, options) { try { if (type === 'pointermove' && listener && listener.name === 'real') { realPointerListener = listener; log('captured real pointermove listener'); } } catch (e) { /* never break the page's own event hooks */ } return _origAEL.call(this, type, listener, options); }; function getCurrentYawPitch() { try { return unsafeWindow.get_yaw_pitch(); } catch (e) { return null; } } function movePointer(mx, my) { mx = Math.round(mx); my = Math.round(my); if (mx === 0 && my === 0) return; if (!realPointerListener) return; realPointerListener({ movementX: mx, movementY: my, x: 1, isTrusted: true }); } // Signed shortest-arc difference between two angles, in (-π, π]. function radianDiff(a, b) { const TAU = 2 * Math.PI; a = ((a % TAU) + TAU) % TAU; b = ((b % TAU) + TAU) % TAU; let d = Math.abs(a - b); d = Math.min(d, TAU - d); return (((a - b + TAU) % TAU) > Math.PI) ? -d : d; } // Aim camera at the given yaw/pitch (in radians, get_yaw_pitch convention). function setToYawPitch(targetYaw, targetPitch) { const cur = getCurrentYawPitch(); if (!cur) return; const dy = radianDiff(cur.yaw, targetYaw); const dp = radianDiff(cur.pitch, targetPitch); movePointer(dy / SENSITIVITY, dp / SENSITIVITY); } // ──────────────────────────────────────────────────────────────────────── // SHARED AIM MATH — yaw/pitch of a direction vector, in the game's // RotationYawPitchRoll basis (matches StateFarm's calculateYaw/calculatePitch). // Used by the aimbot to convert a (me → target) vector into the yaw/pitch the // camera should hold. // ──────────────────────────────────────────────────────────────────────── const _mod = (a, n) => ((a % n) + n) % n; const _setPrecision = (v) => Math.round(v * 8192) / 8192; // game's shot precision const _calcYaw = (pos) => _setPrecision(_mod(Math.atan2(pos.x, pos.z), 2 * Math.PI)); const _calcPitch = (pos) => _setPrecision(-Math.atan2(pos.y, Math.hypot(pos.x, pos.z)) % 1.5); // Resolve the weapon's static config (bullet velocity, range, mesh name). // babylon2 reads it off `weapon.subClass`; older/other builds expose the // same data on `weapon.constructor` (where StateFarm reads it). function _weaponConfig(w) { return (w && w.subClass) || (w && w.constructor) || {}; } // ──────────────────────────────────────────────────────────────────────── // BUNDLE INTERCEPTION — same pattern as babylon.js (which works). // ──────────────────────────────────────────────────────────────────────── const _origReplace = String.prototype.replace; String.prototype.sshReplace = function () { return _origReplace.apply(this, arguments); }; const CB_NAME = 'ssh_' + Math.random().toString(36).slice(2, 10); const DEFAULTS = { x: 'Fh', y: 'Qh', z: 'Th', dz: 'dz', // per-tick velocity z (dx/dy are usually plain props; dz can be minified) yaw: 'Eh', pitch: '$h', coords: 'aa', playing: 'Gh', actor: 'eh', mesh: 'mesh', weapon: 'Ah', renderingGroupId: 'renderingGroupId', SCENE: 'eI', PLAYERS: 'rI', CULL: 'Xw', items: 'kr', }; function extractKeys(js) { const out = Object.assign({}, DEFAULTS); try { let m; // WASM mouse-look bridge: `(zO.Kw=e.yaw,zO.Ew=e.pitch,zO.Qz=e.coords)` m = /\(([a-zA-Z_$0-9]+)\.([a-zA-Z_$0-9]+)=e\.yaw,\1\.([a-zA-Z_$0-9]+)=e\.pitch,\1\.([a-zA-Z_$0-9]+)=e\.coords\)/.exec(js); if (m) { out.yaw = m[2]; out.pitch = m[3]; out.coords = m[4]; } // Players-array iteration m = /for\s*\(\s*(?:var|let)\s+\w+=0;\w+<([a-zA-Z_$0-9]+);\w+\+\+\)\s*\{\s*(?:var|let)\s+\w+=([a-zA-Z_$0-9]+)\[\w+\];\s*\w+&&\w+\.([a-zA-Z_$0-9]+)&&/.exec(js); if (m) { out.PLAYERS = m[2]; out.playing = m[3]; } // Spectator-info builder pos fields m = /posX:[a-zA-Z_$0-9]+\.([a-zA-Z_$0-9]+),posY:[a-zA-Z_$0-9]+\.([a-zA-Z_$0-9]+),posZ:[a-zA-Z_$0-9]+\.([a-zA-Z_$0-9]+)/.exec(js); if (m) { out.x = m[1]; out.y = m[2]; out.z = m[3]; } // Actor + mesh m = /actorX:[a-zA-Z_$0-9]+\.([a-zA-Z_$0-9]+)\.([a-zA-Z_$0-9]+)\.position\.x/.exec(js); if (m) { out.actor = m[1]; out.mesh = m[2]; } // SCENE: first render() in the two-render() pattern m = /([a-zA-Z_$0-9]+)\.render\(\),[a-zA-Z_$0-9]+\.render\(\)\}\)\)/.exec(js); if (m) out.SCENE = m[1]; // Items manager: the network-protocol handler calls // `<X>.spawnItem(s,p,m,v,y);break;` with exactly those 5 args. // Capture <X> as the items-manager instance. m = /([a-zA-Z_$0-9]+)\.spawnItem\([a-zA-Z_$0-9]+,[a-zA-Z_$0-9]+,[a-zA-Z_$0-9]+,[a-zA-Z_$0-9]+,[a-zA-Z_$0-9]+\);break;/.exec(js); if (m) out.items = m[1]; } catch (e) { log('key extraction error:', e); } return out; } function patchBundle(js) { H = extractKeys(js); log('H map:', H); const argFields = Object.keys(H) .map(k => `${k}:(()=>{try{return ${H[k]}}catch(_){return null}})()`) .join(','); const find = H.SCENE + '.render'; const replace = `window["${CB_NAME}"]({${argFields}},true)||${H.SCENE}.render`; const before = js; js = js.sshReplace(find, replace); if (before === js) log('WARNING: SCENE.render patch did not match'); else log('SCENE.render hook installed'); // Cull inhibition: the bundle hides off-screen / occluded players via // `{if(<CULL>)`. Patch to `{if(true)` so all players keep rendering // even when behind walls — otherwise our ESP boxes (parented to the // player mesh) disappear with them. const cullBefore = js; js = js.sshReplace('{if(' + H.CULL + ')', '{if(true)'); if (cullBefore === js) log('WARNING: cull-inhibition patch did not match (H.CULL=' + H.CULL + ')'); else log('cull inhibition installed'); // ── Item ESP hooks (ammo + grenade drops) ── // Anchor on the items-manager prototype methods. Both spawnItem // and collectItem have a stable shape: // spawnItem(e,t,i,r,n){var a=this.pools[t].retrieve(e); ...} // collectItem(e,t){var i=this.pools[e]; i.recycle(...); ...} // Param names are captured generically so renaming between builds // doesn't break the patch. // Anchor on the function body (`var a=this.pools[t].retrieve(e);`) // and accept both `<Cls>.prototype.spawnItem=function(...)` (old // bundle style) and `spawnItem(...){` (ES6 class syntax). The body // pattern is what disambiguates from call sites like // `kr.spawnItem(s,p,m,v,y);`. const spawnItemBefore = js; js = js.sshReplace( /((?:\.prototype\.spawnItem=function|\bspawnItem)\(([a-zA-Z_$0-9]+),([a-zA-Z_$0-9]+),([a-zA-Z_$0-9]+),([a-zA-Z_$0-9]+),([a-zA-Z_$0-9]+)\)\{var ([a-zA-Z_$0-9]+)=this\.pools\[\3\]\.retrieve\(\2\);)/, '$1window.ssh_onItemSpawn&&window.ssh_onItemSpawn($7,$3,$4,$5,$6);' ); if (spawnItemBefore === js) log('WARNING: spawnItem pattern not found — item ESP disabled'); else log('spawnItem hook installed'); const collectItemBefore = js; js = js.sshReplace( /((?:\.prototype\.collectItem=function|\bcollectItem)\(([a-zA-Z_$0-9]+),([a-zA-Z_$0-9]+)\)\{var ([a-zA-Z_$0-9]+)=this\.pools\[\2\];)/, '$1window.ssh_onItemCollect&&window.ssh_onItemCollect($2,$4.objects[$3]);' ); if (collectItemBefore === js) log('WARNING: collectItem pattern not found'); else log('collectItem hook installed'); // ── Skin unlock ── // The bundle's "do I own this skin?" check is: // `inventory[X].id===Y.id) return true; return false` // Patch the trailing comparison so it ALSO passes when our flag // `window.ssh_skinUnlock` is set — every skin then appears owned. // Gated client-side; the server may still validate at use, but the // shop/inventory UI will let you try them on. const skinBefore = js; js = js.sshReplace( /inventory\[[a-zA-Z$_]+\]\.id===[a-zA-Z$_]+\.id\)return!0;return!1/, (m) => m + '||window.ssh_skinUnlock' ); if (skinBefore === js) log('WARNING: skin-unlock pattern not found in this bundle'); else log('skin-unlock hook installed'); return js; } const _origAppendChild = HTMLElement.prototype.appendChild; HTMLElement.prototype.appendChild = function (node) { if (node && node.tagName === 'SCRIPT' && node.innerHTML && node.innerHTML.startsWith('(()=>{')) { log('intercepting bundle, ' + node.innerHTML.length + ' chars'); node.innerHTML = patchBundle(node.innerHTML); } return _origAppendChild.call(this, node); }; // ──────────────────────────────────────────────────────────────────────── // ESP — wireframe box per enemy, parented to their mesh so it follows // smoothly. Created on first sight; visibility toggled per frame. // ──────────────────────────────────────────────────────────────────────── let _espWarned = false; // Tracks every player we've created an ESP box for. Used by the sweep // in the per-frame callback to dispose orphan boxes when a player leaves // the match (no longer in ss.PLAYERS) or switches to our team. const _espPlayers = new Set(); function disposeEspFor(P) { if (P._ssh_box) { try { P._ssh_box.dispose(); } catch (e) {} P._ssh_box = null; } if (P._ssh_tracer) { try { P._ssh_tracer.dispose(); } catch (e) {} P._ssh_tracer = null; } _espPlayers.delete(P); } // ESP color palette. Default enemies render in red; players whose name // starts with "Nyx" render in purple so the community is visible at a // glance across the map. Reused across boxes + tracers; one Color3 // instance each so we don't allocate per-frame. const ESP_COLOR_RED = (typeof BABYLON !== 'undefined') ? new BABYLON.Color3(1.0, 0.2, 0.2) : null; const ESP_COLOR_NYX = (typeof BABYLON !== 'undefined') ? new BABYLON.Color3(0.7, 0.3, 1.0) : null; const ESP_COLOR_AMMO = (typeof BABYLON !== 'undefined') ? new BABYLON.Color3(1.0, 0.95, 0.2) : null; const ESP_COLOR_GRENADE = (typeof BABYLON !== 'undefined') ? new BABYLON.Color3(1.0, 0.5, 0.0) : null; const _isNyxName = (n) => typeof n === 'string' && n.toLowerCase().startsWith('nyx'); // Item ESP — markers for ammo/grenade pickups. The bundle's items // manager pools meshes (Qo.constructors = [Yo, Ko] → type 0 = ammo, // type 1 = grenade), so we keep our marker keyed by the pooled mesh // and dispose it on collect. // Map (not WeakMap) so we can iterate it each frame to dispose markers // whose item went inactive without us seeing the collect event. const itemMarkers = new Map(); function makeItemMarker(x, y, z, color) { if (typeof BABYLON === 'undefined' || !ss.SCENE) return null; const s = 0.35; const V = BABYLON.Vector3; const m = BABYLON.MeshBuilder.CreateLineSystem( 'sshitem_' + Math.random().toString(36).slice(2, 8), { lines: [ [new V(-s, 0, 0), new V(s, 0, 0)], [new V(0, -s, 0), new V(0, s, 0)], [new V(0, 0, -s), new V(0, 0, s)], ]}, ss.SCENE ); m.color = color; m.position.x = x; m.position.y = y; m.position.z = z; m[H.renderingGroupId] = 1; m.alwaysSelectAsActiveMesh = true; m.isPickable = false; pierceWalls(m); return m; } unsafeWindow.ssh_onItemSpawn = function (item, type, x, y, z) { try { if (!settings.itemEsp) return; if (!item || !item.mesh) return; // Clean up any leftover marker for this pooled mesh. const old = itemMarkers.get(item.mesh); if (old) { try { old.dispose(); } catch (e) {} itemMarkers.delete(item.mesh); } const color = (type === 0 ? ESP_COLOR_AMMO : ESP_COLOR_GRENADE) || new BABYLON.Color3(1, 1, 1); const marker = makeItemMarker(x, y, z, color); if (marker) itemMarkers.set(item.mesh, marker); } catch (e) {} }; unsafeWindow.ssh_onItemCollect = function (_type, item) { try { if (!item || !item.mesh) return; const marker = itemMarkers.get(item.mesh); if (marker) { try { marker.dispose(); } catch (e) {} itemMarkers.delete(item.mesh); } } catch (e) {} }; // Force a mesh to ignore the depth buffer entirely while rendering. This // is what actually makes the box/tracer punch through walls — neither // renderingGroupId nor setRenderingAutoClearDepthStencil is reliable on // its own in this Babylon version. function pierceWalls(mesh) { if (!mesh || mesh._ssh_pierced) return; mesh._ssh_pierced = true; let saved = null; mesh.onBeforeRenderObservable.add(() => { try { const eng = ss.SCENE && ss.SCENE.getEngine && ss.SCENE.getEngine(); if (!eng) return; saved = eng.getDepthFunction(); eng.setDepthFunction(BABYLON.Engine.ALWAYS); } catch (e) {} }); mesh.onAfterRenderObservable.add(() => { try { const eng = ss.SCENE && ss.SCENE.getEngine && ss.SCENE.getEngine(); if (!eng || saved === null) return; eng.setDepthFunction(saved); saved = null; } catch (e) {} }); } function ensureEspBox(P) { if (P._ssh_box) return P._ssh_box; if (typeof BABYLON === 'undefined') { if (!_espWarned) { _espWarned = true; log('ESP: BABYLON not loaded'); } return null; } if (!ss.SCENE) { if (!_espWarned) { _espWarned = true; log('ESP: no SCENE'); } return null; } // Build geometry in local space (centered around 0, 0, 0). Position is // set per-frame from network coords below — no parenting, so we don't // inherit the game's interpolation freeze when it thinks the enemy // is occluded. const w = 0.4, h = 0.65, d = 0.4; const V = BABYLON.Vector3; const v = [ new V(-w/2, 0, -d/2), new V(w/2, 0, -d/2), new V( w/2, h, -d/2), new V(-w/2, h, -d/2), new V(-w/2, 0, d/2), new V(w/2, 0, d/2), new V( w/2, h, d/2), new V(-w/2, h, d/2), ]; const lines = []; for (let i = 0; i < 4; i++) { lines.push([v[i], v[(i+1)%4]]); lines.push([v[i+4], v[(i+1)%4+4]]); lines.push([v[i], v[i+4]]); } const box = BABYLON.MeshBuilder.CreateLineSystem( 'sshesp_' + Math.random().toString(36).slice(2, 8), { lines }, ss.SCENE ); box.color = ESP_COLOR_RED || new BABYLON.Color3(1.0, 0.2, 0.2); box[H.renderingGroupId] = 1; box.alwaysSelectAsActiveMesh = true; box.isPickable = false; pierceWalls(box); P._ssh_box = box; _espPlayers.add(P); log('ESP: built box for', P.name || P.nickname || '?'); return box; } // Tracer line from each enemy to a point 5 units BEHIND the camera (so it // appears to converge at your eye and project outward to the enemy). function ensureEspTracer(P) { if (P._ssh_tracer) return P._ssh_tracer; if (typeof BABYLON === 'undefined' || !ss.SCENE) return null; const placeholder = [new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(0,0,0)]; const tr = BABYLON.MeshBuilder.CreateLines( 'sshtracer_' + Math.random().toString(36).slice(2, 8), { points: placeholder, updatable: true }, ss.SCENE ); tr.color = ESP_COLOR_RED || new BABYLON.Color3(1.0, 0.2, 0.2); tr.isPickable = false; tr.alwaysSelectAsActiveMesh = true; tr.doNotSyncBoundingInfo = true; tr[H.renderingGroupId] = 1; pierceWalls(tr); P._ssh_tracer = tr; return tr; } function updateEspTracer(P, crosshairs) { const tr = ensureEspTracer(P); if (!tr) return null; // Use network coords (always live) rather than mesh.position (freezes // when the game thinks the enemy is occluded). const from = new BABYLON.Vector3(P[H.x], P[H.y] + 0.4, P[H.z]); BABYLON.MeshBuilder.CreateLines(undefined, { points: [from, crosshairs.clone()], instance: tr, updatable: true, }); return tr; } // Per-weapon bullet speed (Crackshot ≈150, EggK-47 ≈80…). Big difference // in long-range lead — fixed-time lead under/overshoots across weapons. function getProjectileSpeed(me) { try { const w = me && me[H.weapon]; if (w && w.subClass && typeof w.subClass.velocity === 'number' && w.subClass.velocity > 0) { return w.subClass.velocity; } } catch (e) {} return PROJECTILE_SPEED; } // Best-effort floor height under (x, z): cast a ray straight down from just // above the target and return the first solid hit's y. "other script" uses // the game's map-only collider (Collider.grenadeCollidesWithCell) for this; // that filtered collider isn't exposed to us, so we pick the nearest solid // below via the scene — excluding our own ESP geometry. Returns null when // the scene/ray isn't available (then the caller skips the clamp). function getGroundY(x, z, fromY) { if (!ss.SCENE || typeof BABYLON === 'undefined') return null; try { const origin = new BABYLON.Vector3(x, fromY + 0.5, z); const ray = new BABYLON.Ray(origin, new BABYLON.Vector3(0, -1, 0), 60); const pick = ss.SCENE.pickWithRay(ray, (mesh) => { if (!mesh || mesh.isPickable === false) return false; if (mesh._ssh_box || mesh._ssh_tracer || mesh._ssh_pierced) return false; return true; }); return (pick && pick.hit && pick.pickedPoint) ? pick.pickedPoint.y : null; } catch (e) { return null; } } // Lead prediction — faithful port of StateFarm's `predictPosition`. // // Works in the game's PER-TICK units (gravity -0.012/tick², terminal fall // 0.29/tick, +1-tick lead bias). Reads the game's native velocity vector // (player.dx/.dy/.dz) and the network position (H.x/y/z) rather than // deriving velocity from mesh deltas — this is what StateFarm does and is // what the user asked to replicate. Returns the predicted WORLD position to // aim at; the y is gravity-integrated and clamped to the floor when the // target is airborne, left at the network y when grounded. function predictPositionSF(player, me) { const base = { x: player[H.x], y: player[H.y], z: player[H.z] }; try { const meMesh = me[H.actor] && me[H.actor][H.mesh]; const pMesh = player[H.actor] && player[H.actor][H.mesh]; if (!meMesh || !pMesh) return base; const mp = meMesh.position, tp = pMesh.position; // Native per-tick velocity. dx/dy are usually plain props; dz can be // minified, so fall back to the discovered H.dz key, then 0. const vx = (typeof player.dx === 'number') ? player.dx : 0; const vy = (typeof player.dy === 'number') ? player.dy : 0; const vz = (typeof player.dz === 'number') ? player.dz : (typeof player[H.dz] === 'number') ? player[H.dz] : 0; const cfg = _weaponConfig(me[H.weapon]); const bulletSpeed = (cfg && typeof cfg.velocity === 'number' && cfg.velocity > 0) ? cfg.velocity : PROJECTILE_SPEED; // Mesh-based 3D distance (StateFarm distancePlayers, yMultiplier 1). const dist = Math.hypot(tp.x - mp.x, tp.y - mp.y, tp.z - mp.z); const timeDiff = dist / bulletSpeed + 1; // ticks (+1-tick lead bias) const nx = base.x + vx * timeDiff; const nz = base.z + vz * timeDiff; let ny = base.y; // Terminal-velocity model: StateFarm caps (vx, 0.29, vz) to the // terminal speed (0.29/tick) and takes -y as the terminal fall — so // the faster you move horizontally, the slower you fall. Replicated // here since the game's Math.capVector3 isn't exposed to us. const TERMINAL = 0.29; const cmag = Math.hypot(vx, TERMINAL, vz); const cappedY = (cmag > TERMINAL) ? TERMINAL * (TERMINAL / cmag) : TERMINAL; const terminalVelocity = -cappedY; // Only predict vertical motion when airborne (onGround === 0). When // grounded, y stays at the network y (it won't change). if (player.onGround == 0) { const g = -0.012; // per-tick² const timeAccel = Math.min(timeDiff, (terminalVelocity - vy) / g); const predictedY = vy * timeAccel + timeAccel * timeAccel * g / 2 + ny + terminalVelocity * Math.max(timeDiff - timeAccel, 0); const groundY = getGroundY(nx, nz, Math.max(ny, predictedY)); ny = Math.max(groundY != null ? groundY : 0, predictedY) - 0.072; _pred.airborne = true; } else { _pred.airborne = false; } _pred.active = true; _pred.speed = Math.hypot(vx, vy, vz); _pred.t = timeDiff; _pred.leadDist = Math.hypot(nx - base.x, nz - base.z); return { x: nx, y: ny, z: nz }; } catch (e) { return base; } } // Line-of-sight test — faithful in spirit to StateFarm's getLineOfSight: // cast a ray from our eye toward the target and report whether the MAP // blocks it. StateFarm uses the game's map-only collider; that filtered // collider isn't exposed to us, so we pick against the scene and skip // (a) our own ESP/marker geometry and (b) skinned character meshes — walls // and floors aren't skinned, so excluding skinned meshes leaves map // geometry as the only occluder. Returns true when nothing solid is closer // than the target (or when the scene/ray isn't available to test). function hasLineOfSight(me, player) { if (!ss.SCENE || typeof BABYLON === 'undefined') return true; try { const meMesh = me[H.actor] && me[H.actor][H.mesh]; const pMesh = player[H.actor] && player[H.actor][H.mesh]; if (!meMesh || !pMesh) return false; const eye = new BABYLON.Vector3( meMesh.position.x, meMesh.position.y + 0.3, meMesh.position.z); const to = pMesh.position; const dx = to.x - eye.x, dy = to.y - eye.y, dz = to.z - eye.z; const dist = Math.hypot(dx, dy, dz); if (dist <= 0.001) return true; const ux = dx / dist, uy = dy / dist, uz = dz / dist; // Skip the first ~1.2 units so our own (rigid, non-skinned) gun // viewmodel / body right at the origin can't register as a wall. const skip = Math.min(1.2, dist * 0.5); const len = dist - skip; const ray = new BABYLON.Ray( new BABYLON.Vector3(eye.x + ux * skip, eye.y + uy * skip, eye.z + uz * skip), new BABYLON.Vector3(ux, uy, uz), len); const pick = ss.SCENE.pickWithRay(ray, (mesh) => { if (!mesh || mesh.isPickable === false) return false; if (mesh._ssh_box || mesh._ssh_tracer || mesh._ssh_pierced) return false; if (mesh.skeleton) return false; // character model, not the map return true; }); if (!pick || !pick.hit) return true; // Visible if the first solid hit is essentially at/past the target. return pick.distance >= len - 1.0; } catch (e) { return true; } } // Nyx-tag banner: visible until the local player's in-game name starts // with "Nyx" (case-insensitive). The banner lives inside the menu and is // hidden once the player adopts the tag — no menu spam after they // comply. Hidden also when the menu itself is hidden via backtick. function updateNyxBanner() { if (!nyxBannerEl) return; const name = _aim.me && typeof _aim.me.name === 'string' ? _aim.me.name : ''; const hasTag = name.toLowerCase().startsWith('nyx'); nyxBannerEl.style.display = hasTag ? 'none' : ''; } // ──────────────────────────────────────────────────────────────────────── // PER-FRAME CALLBACK — ESP refresh + aim // ──────────────────────────────────────────────────────────────────────── unsafeWindow[CB_NAME] = function (vars) { try { Object.assign(ss, vars); if (!ss.PLAYERS) return false; // Find local player (the one with the .ws WebSocket attached). let me = null; for (const P of ss.PLAYERS) { if (P && P.hasOwnProperty('ws')) { me = P; break; } } if (!me) return false; // Discover the obfuscated `actor` key dynamically — it's whichever // key on the player object has a `.mesh` child, excluding the // weapon key (whose `.mesh` is the gun model, NOT the body — // picking it up made our velocity tracker derive from gun-tip // motion and sent the lead in the gun's facing direction). // Always run the scan — if H.actor was previously set to the // weapon key, the guard `me[H.actor].mesh` would otherwise pass // and the bad key would stick. const actorKey = findKeyWithProperty(me, H.mesh, [H.weapon]); if (actorKey && actorKey !== H.actor) { log('actor key resolved:', H.actor, '→', actorKey); H.actor = actorKey; } // One-time scene tweak: clear the depth buffer between rendering // group 0 (world) and group 1 (our boxes/tracers). if (ss.SCENE && !ss.SCENE._ssh_depthCleared && typeof BABYLON !== 'undefined') { try { ss.SCENE.setRenderingAutoClearDepthStencil(1, true, true, true); ss.SCENE._ssh_depthCleared = true; log('depth-clear enabled for renderingGroupId=1 (see through walls)'); } catch (e) { log('depth-clear setup failed:', e && e.message); } } // Crosshair convergence point: 5 units in front of the camera, so // tracer lines from each enemy visually fan out from the center of // your view. let crosshairs = null; const cur = getCurrentYawPitch(); if (cur && typeof BABYLON !== 'undefined' && me[H.actor] && me[H.actor][H.mesh]) { crosshairs = new BABYLON.Vector3(); crosshairs.copyFrom(me[H.actor][H.mesh].position); crosshairs.y += 0.4; const yaw = cur.yaw; const pitch = -cur.pitch; const off = -5; crosshairs.x += Math.sin(yaw) * Math.cos(pitch) * off; crosshairs.y += Math.sin(pitch) * off; crosshairs.z += Math.cos(yaw) * Math.cos(pitch) * off; } // ── ESP cleanup sweep ── // The main loop below only visits players who are STILL valid // enemies. Anyone who left the match (gone from ss.PLAYERS) or // switched onto our team would otherwise keep an orphan box at // their last position forever. Build the set of who should // currently have ESP, then dispose everything else we're tracking. const _shouldHaveEsp = new Set(); for (const P of ss.PLAYERS) { if (!P || P === me) continue; if (me.team !== 0 && P.team === me.team) continue; _shouldHaveEsp.add(P); } for (const P of _espPlayers) { if (!_shouldHaveEsp.has(P)) disposeEspFor(P); } // ── ESP boxes + tracers ── for (const P of ss.PLAYERS) { if (!P || P === me) continue; if (me.team !== 0 && P.team === me.team) continue; if (!P[H.playing]) { if (P._ssh_box) P._ssh_box.visibility = 0; if (P._ssh_tracer) P._ssh_tracer.visibility = 0; continue; } // Recolor based on whether this enemy is a Nyx user. Cache // the last-applied state on the player so we only touch the // mesh color when it actually changes (cheap most frames). const nyx = _isNyxName(P.name); const desiredColor = nyx ? ESP_COLOR_NYX : ESP_COLOR_RED; const box = ensureEspBox(P); if (box) { box.position.x = P[H.x]; box.position.y = P[H.y]; box.position.z = P[H.z]; box.visibility = settings.espEnabled ? 1 : 0; if (P._ssh_nyxColor !== nyx) { box.color = desiredColor; P._ssh_nyxColor = nyx; } } if (crosshairs) { const tr = updateEspTracer(P, crosshairs); if (tr) { tr.visibility = settings.espEnabled ? 1 : 0; if (tr._ssh_nyxColor !== nyx) { tr.color = desiredColor; tr._ssh_nyxColor = nyx; } } } } // Reset per-frame state read by the overlay. _aim.hasLock = false; _aim.me = me; // Clear aim-smoothing memory when RMB is up so the next press // snaps onto target instantly instead of easing in from a stale // cached point. if (!RMB) _aim.smoothTarget = null; _pred.enabled = !!settings.predEnabled; _pred.active = false; _pred.airborne = false; _pred.speed = 0; _pred.t = 0; _pred.leadDist = 0; _pred.projSpeed = getProjectileSpeed(me); // ── Aim: RMB held + aimbot enabled → snap to the best enemy ── // Target mode: "Target Crosshair" ON picks the enemy nearest your // crosshair (smallest angle); OFF picks the nearest by (y-weighted) // 3D distance. Either way the visibility filter applies: prefer // enemies with line-of-sight, and with "Only Visible" ON never // target one behind a wall (otherwise fall back to the best overall). if (RMB && settings.aimEnabled) { const meMesh = me[H.actor] && me[H.actor][H.mesh]; if (meMesh && meMesh.position) { const meP = meMesh.position; // Camera-forward unit vector — only needed for crosshair mode. let fwdX = 0, fwdY = 0, fwdZ = 0, haveFwd = false; if (settings.crosshairTarget) { const cur = getCurrentYawPitch(); if (cur) { const cp = Math.cos(cur.pitch); fwdX = -Math.sin(cur.yaw) * cp; fwdY = Math.sin(cur.pitch); fwdZ = -Math.cos(cur.yaw) * cp; haveFwd = true; } } let bestVis = null, bestVisRank = Infinity, bestVisMesh = null; let bestAny = null, bestAnyRank = Infinity, bestAnyMesh = null; for (const P of ss.PLAYERS) { if (!P || P === me) continue; if (!P[H.playing]) continue; if (me.team !== 0 && P.team === me.team) continue; const pMesh = P[H.actor] && P[H.actor][H.mesh]; if (!pMesh || !pMesh.position) continue; const pp = pMesh.position; const ex = pp.x - meP.x, ey = pp.y - meP.y, ez = pp.z - meP.z; // Rank, lower = better. Crosshair mode → angular distance // from the crosshair (1 - dot, 0 = dead-on). Else the // (y-weighted ×2) 3D distance, which prefers an enemy on // your level over one above/below at the same range. let rank; if (haveFwd) { const elen = Math.hypot(ex, ey, ez) || 1; rank = 1 - (fwdX * ex + fwdY * ey + fwdZ * ez) / elen; } else { rank = Math.hypot(ex, ey * 2, ez); if (rank <= 0) continue; // self / exact overlap } if (rank < bestAnyRank) { bestAnyRank = rank; bestAny = P; bestAnyMesh = pp; } if (rank < bestVisRank && hasLineOfSight(me, P)) { bestVisRank = rank; bestVis = P; bestVisMesh = pp; } } // Prefer the best visible; fall back to the best overall only // when Only Visible is off. let best = bestVis, bestMeshPos = bestVisMesh; if (!best && !settings.onlyVisible) { best = bestAny; bestMeshPos = bestAnyMesh; } if (best && bestMeshPos) { // Aim point: prediction ON → StateFarm's network-velocity // lead solve; OFF → the target's current mesh position. let aimX, aimY, aimZ; if (settings.predEnabled) { const pred = predictPositionSF(best, me); aimX = pred.x; aimY = pred.y; aimZ = pred.z; } else { aimX = bestMeshPos.x; aimY = bestMeshPos.y; aimZ = bestMeshPos.z; _pred.active = false; } // Aim-point smoothing — absorbs the ~20 Hz network-coord // stepping so the predicted point (and the camera) don't // jitter. Reset on target switch so the first snap is // instant. This filters the target/prediction only, never // the aim motion itself (see memory). const AIM_SMOOTH = 0.35; if (_aim.smoothTarget !== best) { _aim.smoothTarget = best; _aim.smoothX = aimX; _aim.smoothY = aimY; _aim.smoothZ = aimZ; } else { _aim.smoothX += (aimX - _aim.smoothX) * AIM_SMOOTH; _aim.smoothY += (aimY - _aim.smoothY) * AIM_SMOOTH; _aim.smoothZ += (aimZ - _aim.smoothZ) * AIM_SMOOTH; aimX = _aim.smoothX; aimY = _aim.smoothY; aimZ = _aim.smoothZ; } // Direction to target — StateFarm's getDirectionVectorFacingTarget // with offsetY -0.05; yaw/pitch via the shared calc helpers // (atan2(x,z) basis, pitch clamped %1.5). const dirV = { x: -(aimX - meP.x), y: -(aimY - meP.y - 0.05), z: -(aimZ - meP.z), }; const targetYaw = _calcYaw(dirV); const targetPitch = _calcPitch(dirV); _aim.hasLock = true; // A single big synthetic movement gets clamped by the game's // mouse-input pipeline; several smaller ones converge cleanly. for (let i = 0; i < 5; i++) setToYawPitch(targetYaw, targetPitch); } } } // Item ESP sweep — runs every frame so markers track items that // existed before our spawnItem hook installed (pre-join state), // and cleans up markers whose item became inactive via any // code path the collectItem hook didn't catch. if (settings.itemEsp && ss.items && ss.items.pools && typeof BABYLON !== 'undefined') { const seen = new Set(); for (let t = 0; t < ss.items.pools.length; t++) { const pool = ss.items.pools[t]; if (!pool || typeof pool.forEachActive !== 'function') continue; const poolColor = (t === 0 ? ESP_COLOR_AMMO : ESP_COLOR_GRENADE); pool.forEachActive((it) => { if (!it || !it.mesh) return; seen.add(it.mesh); if (!itemMarkers.has(it.mesh)) { const pos = it.mesh.position; const m = makeItemMarker(pos.x, pos.y, pos.z, poolColor); if (m) itemMarkers.set(it.mesh, m); } }); } for (const [meshKey, marker] of itemMarkers) { if (!seen.has(meshKey)) { try { marker.dispose(); } catch (e) {} itemMarkers.delete(meshKey); } } } else if (!settings.itemEsp && itemMarkers.size > 0) { for (const marker of itemMarkers.values()) { try { marker.dispose(); } catch (e) {} } itemMarkers.clear(); } updateNyxBanner(); return false; } catch (e) { log('per-frame error:', e && e.message); return false; } }; // ──────────────────────────────────────────────────────────────────────── // NOTES // ──────────────────────────────────────────────────────────────────────── // • Hold RMB → aim at the best enemy. "Target Crosshair" picks the one // nearest your crosshair; otherwise the nearest by distance. "Only // Visible" never targets through walls; off, it falls back to the best // enemy overall when none have line-of-sight. // • Press V → toggle red wireframe ESP on enemies. // • Press ` → show/hide the settings menu (top-left). // • Prediction is a faithful port of StateFarm's predictPosition: it reads // the game's native per-tick velocity (player.dx/dy/dz) + network position // and does a single-pass lead (t = dist/bulletSpeed + 1 tick) with a // gravity + terminal-velocity vertical drop model and a ground clamp. // • If aim under/overshoots, your in-game mouse sensitivity differs from // the menu's "Sensitivity" value (default 0.0025); tweak it. })();