// ==UserScript== // @name Meeland Enhancement Suite // @namespace meeland-script // @version 8.1.0 // @description The ultimate Meeland.io mod — fly, go invisible, steal pets hands-free, teleport, noclip, auto-lock, auto-fountain, and more. Fully configurable. Works on 60+ sites including CrazyGames, Miniplay, KBH Games, and meeland.io. // @match *://*/* // @run-at document-end // @license MIT // @grant none // @downloadURL none // ==/UserScript== (async function () { 'use strict'; const W = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window; for (let i = 0; i < 150 && !W.pc?.app?.root; i++) await new Promise(r => setTimeout(r, 100)); if (!W.pc?.app?.root) return; const STORE_KEY = 'ml_wp'; const CFG_KEY = 'ml_cfg'; const isMobile = ('ontouchstart' in window || navigator.maxTouchPoints > 0) && window.matchMedia('(pointer: coarse)').matches; let ACCEL = 6; let FLY_MIN_SPEED = 10; let SPEED_CAP = 100; let GRAVITY = -18; let SPEED_DEFAULT = 7; let flyActive = false; let _flyStartTime = 0; let _flyEmoteTimer = null; const _FLY_EMOTES = ['Waving','Breakdance','Macarena','Shuffle','Smooth Moves','Techno']; const slots = new Array(10).fill(null); let flyUp = false; let flyDown = false; let flyVelY = 0; let prevTick = Date.now(); let sprinting = false; let sprintSpeed = SPEED_DEFAULT; let homePos = null; let backPos = null; let _pendingBaseCapture = false; let _roomJoinTime = 0; let cuddleTarget = null; let cuddling = false; let accelEnabled = true; let featFly = true; let featSprint = true; let featWaypoints = true; let featCuddle = true; let featCuddleFollow = true; let featPets = true; let featAutoLock = true; let featAntiKnockback = true; let featNoclip = false; let featFreeMoney = true; let featAutoCollect = true; let featInvincible = true; let featGhostMode = true; let featFreeStars = true; let featAutoAttack = true; let featAutoFountain = true; let featInvisible = false; let featProTips = true; let _freeStarsTimer = null; let _fountainTimer = null; let autoCollectInterval = 30; let snipeFilter = 'exclusive'; let snipeActive = false; let snipeAutoDrop = true; let snipeAutoHop = !!sessionStorage.getItem('ml_snipeAutoHop'); let _snipeHopNoMatchStart = 0; let _snipeCooldown = 0; let _snipeWasHolding = false; const autoRefresh = true; const refreshInterval = 5; let kbListeningRow = null; let petFilter = 'wild'; let petSortCol = 'price'; let petSortDir = -1; let petAutoRefresh = true; let petRefreshInterval = 1; const KEYBINDS = { fly: 'Space', flyDown: 'KeyF', setHome: 'KeyQ', home: 'Backquote', back: 'KeyZ', cuddle: 'KeyJ', settings: 'KeyM', pets: 'KeyK', slots: 'KeyI', help: 'Slash', snipe: 'KeyU', attack: 'KeyG', invisible:'KeyX', }; const DEFAULT_KEYBINDS = { ...KEYBINDS }; function saveSettings() { try { localStorage.setItem(CFG_KEY, JSON.stringify({ ACCEL, SPEED_CAP, SPEED_DEFAULT, accelEnabled, featFly, featSprint, featWaypoints, featCuddle, featCuddleFollow, featPets, featAutoLock, featAntiKnockback, featNoclip, featFreeMoney, featAutoCollect, featInvincible, featGhostMode, featFreeStars, featAutoAttack, featAutoFountain, featInvisible, featProTips, autoCollectInterval, snipeFilter, snipeAutoDrop, snipeActive, keybinds: { ...KEYBINDS }, petFilter, petSortCol, petSortDir, petAutoRefresh, petRefreshInterval, })); } catch (_) {} } function loadSettings() { try { const raw = localStorage.getItem(CFG_KEY); if (!raw) return; const d = JSON.parse(raw); const assign = (key, fn) => { if (d[key] !== undefined) fn(d[key]); }; assign('ACCEL', v => ACCEL = v); assign('SPEED_CAP', v => SPEED_CAP = v); assign('SPEED_DEFAULT', v => SPEED_DEFAULT = v); assign('accelEnabled', v => accelEnabled = v); assign('featFly', v => featFly = v); assign('featSprint', v => featSprint = v); assign('featWaypoints', v => featWaypoints = v); assign('featCuddle', v => featCuddle = v); assign('featVisit', v => featCuddle = v); assign('featCuddleFollow', v => featCuddleFollow = v); assign('featStalk', v => featCuddleFollow = v); assign('featPets', v => featPets = v); assign('featAutoLock', v => featAutoLock = v); assign('featAntiKnockback', v => featAntiKnockback = v); assign('featNoclip', v => featNoclip = v); assign('featFreeMoney', v => featFreeMoney = v); assign('featAutoCollect', v => featAutoCollect = v); assign('featInvincible', v => featInvincible = v); assign('featGhostMode', v => featGhostMode = v); assign('featFreeStars', v => featFreeStars = v); assign('featAutoAttack', v => featAutoAttack = v); assign('featAutoFountain', v => featAutoFountain = v); assign('featInvisible', v => featInvisible = v); assign('featProTips', v => featProTips = v); assign('autoCollectInterval', v => autoCollectInterval = v); assign('snipeFilter', v => snipeFilter = v); assign('snipeAutoDrop', v => snipeAutoDrop = v); assign('snipeActive', v => snipeActive = v); assign('petFilter', v => petFilter = v); assign('petSortCol', v => petSortCol = v); assign('petSortDir', v => petSortDir = v); assign('petAutoRefresh', v => petAutoRefresh = v); assign('petRefreshInterval', v => petRefreshInterval = v); if (d.keybinds) { for (const k of Object.keys(KEYBINDS)) { if (typeof d.keybinds[k] === 'string') KEYBINDS[k] = d.keybinds[k]; } } } catch (_) {} } loadSettings(); let _playerCache = null, _playerCacheTime = 0; const getPlayer = () => { const now = Date.now(); if (_playerCacheTime && now - _playerCacheTime < 200) return _playerCache; _playerCache = W.pc?.app?.root?.findByName('Player') ?? null; if (_playerCache) _playerCacheTime = now; return _playerCache; }; const getKcc = p => p?.script?.kcc ?? null; const getPC = p => p?.script?.playerController ?? null; const $ = id => document.getElementById(id); const flash = id => { const el = $(id); if (el) { el.classList.add('fresh'); setTimeout(() => el.classList.remove('fresh'), 400); } if (_nativeHud) { const idMap = { 'ml-fly': 'fly', 'ml-spr': 'spr', 'ml-home': 'home', 'ml-go': 'go', 'ml-back': 'back', 'ml-slots': 'slots', 'ml-lock': 'lock' }; const k = idMap[id]; if (k && _nativeHud[k]) { _nativeHud[k].classList.add('fresh'); setTimeout(() => _nativeHud[k].classList.remove('fresh'), 400); } } }; const syncSlider = (id, valId, v, uom) => { const el = $(id), ve = $(valId); if (el) el.value = v; if (ve) ve.textContent = uom ? v + uom : v; }; const vec3 = v => ({ x: v.x, y: v.y, z: v.z }); const getCamera = () => W.pc?.app?.root?.findByName('Camera') ?? null; function capturePos(player) { const p = player.getPosition(); const r = player.getEulerAngles(); const camera = getCamera(); const cam = camera?.getEulerAngles(); let se = null; for (const inst of (camera?.script?._scripts || [])) { if (inst.eulers) { se = vec3(inst.eulers); break; } } return { x: p.x, y: p.y, z: p.z, rot: vec3(r), cam: cam ? vec3(cam) : null, se }; } function restoreCam(posData) { if (!posData?.cam) return; const camera = getCamera(); if (!camera) return; let scriptRestored = false; for (const inst of (camera.script?._scripts || [])) { if ('_yaw' in inst) { inst._yaw = posData.cam.y; scriptRestored = true; } if ('_pitch' in inst) { inst._pitch = posData.cam.x; scriptRestored = true; } if ('yaw' in inst) { inst.yaw = posData.cam.y; scriptRestored = true; } if ('pitch' in inst) { inst.pitch = posData.cam.x; scriptRestored = true; } if (inst.eulers && posData.se) { inst.eulers.x = posData.se.x; inst.eulers.y = posData.se.y; inst.eulers.z = posData.se.z; scriptRestored = true; } } if (!scriptRestored) camera.setEulerAngles(posData.cam.x, posData.cam.y, posData.cam.z); } const FEAT_IDS = ['ml-f-fly','ml-f-sprint','ml-f-waypoints','ml-f-cuddle','ml-f-cuddle-follow','ml-f-pets','ml-f-autolock','ml-f-antiknockback','ml-f-noclip','ml-f-freemoney','ml-f-autocollect','ml-f-invincible','ml-f-ghostmode','ml-f-freestars','ml-f-autoattack','ml-f-autofountain','ml-f-invisible','ml-f-protips']; const MOVE_KEYS = new Set(['KeyW','KeyA','KeyS','KeyD','ArrowUp','ArrowDown','ArrowLeft','ArrowRight']); function getPlayerState() { const nm = W.pc?.app?.root?.findByName('NetworkManager')?.script?.networkManager; if (!nm?.room?.state?.players) return null; return nm.room.state.players.get(nm.room.sessionId) ?? null; } const setSpeed = (pc, kcc, v) => { if (pc) { pc.currentSpeed = v; pc.speed = v; } if (kcc.speed !== undefined) kcc.speed = v; const ps = getPlayerState(); if (ps && ps.movementSpeed !== undefined) ps.movementSpeed = v / SPEED_DEFAULT; }; function teleport(player, pos) { player.setPosition(pos.x, pos.y, pos.z); player.rigidbody?.teleport(pos.x, pos.y, pos.z); if (pos.rot) player.setEulerAngles(pos.rot.x, pos.rot.y, pos.rot.z); restoreCam(pos); } function serializePos(p) { if (!p) return null; const o = vec3(p); if (p.rot) o.rot = vec3(p.rot); if (p.cam) o.cam = vec3(p.cam); if (p.se) o.se = vec3(p.se); return o; } function saveWaypoints() { try { localStorage.setItem(STORE_KEY, JSON.stringify({ home: serializePos(homePos), back: serializePos(backPos), slots: slots.map(s => serializePos(s)), })); } catch (_) {} } function loadWaypoints() { try { const raw = localStorage.getItem(STORE_KEY); if (!raw) return; const d = JSON.parse(raw); if (d.home) homePos = d.home; if (d.back) backPos = d.back; if (Array.isArray(d.slots)) d.slots.forEach((s, i) => { if (s) slots[i] = s; }); } catch (_) {} } function flyOn(kcc, hover) { flyActive = true; _flyStartTime = Date.now(); kcc.gravity = 0; if (hover) { flyUp = false; flyDown = false; flyVelY = 0; kcc._velY = 0; } else { flyUp = true; flyVelY = FLY_MIN_SPEED; kcc._velY = FLY_MIN_SPEED; } _flyEmoteLoop(); } function flyOff(kcc, resetVel = true) { flyActive = false; flyUp = false; flyDown = false; flyVelY = 0; kcc.gravity = GRAVITY; if (resetVel) kcc._velY = 0; _flyEmoteStop(); } function _flyEmoteLoop() { clearTimeout(_flyEmoteTimer); _flyEmoteTimer = null; if (!flyActive) return; const app = W.pc?.app; if (!app) return; const name = _FLY_EMOTES[Math.random() * _FLY_EMOTES.length | 0]; app.fire('NetworkManager:Send', 'emotePlay', name); const asset = app.assets?.find('Emote-' + name + '.glb', 'animation'); const dur = asset?.resource?.duration || 4; _flyEmoteTimer = setTimeout(_flyEmoteLoop, dur * 1000 + 200); } function _flyEmoteStop() { clearTimeout(_flyEmoteTimer); _flyEmoteTimer = null; const app = W.pc?.app; if (app) app.fire('NetworkManager:Send', 'emoteStop'); } const DESCRIPTION = `

Meeland Enhancement Suite

The ultimate Meeland.io mod. Fly, teleport, steal pets effortlessly, go invisible, and dominate every game mode. Works on 60+ sites including CrazyGames, Miniplay, KBH Games, and more.

PC + Mobile. Keyboard shortcuts on desktop, tap-friendly HUD buttons on mobile.

100% free, always. Got feedback? Leave a ⭐ positive review — that's what keeps updates coming.

What You Get

Keys

All rebindable in Settings.

Install

  1. Get Tampermonkey or Violentmonkey
  2. Click Install above
  3. Open any Meeland game — it just works

60+ Supported Sites

meeland.io, CrazyGames, Miniplay.com, MiniPlay.io, PlayMiniGames, RocketGames.io, KBH Games, Gamenora, WooGames.io, TwoPlayerGames.org, KizGame, OmiGames, PlayingFunGames, Gameflare.com, Free AI Games, ZapGames.io, Play-Games.com, GoGy Games, iogames.games, Sprunki-Game.io, 1000Games.io, Play-IOGames.com, ArcadeHippo, Sleepy Arcade, HotGames.io, geodashlite.io, YoPlay.io, Geometry-Free.com, Sprunki.org, Gombis.com, Wordle Unlimited, Games-Kids.com, spacewavesgame.io, amongusfree.io, Veck IO, geometrylitegame.org, Geometry Dash Subzero, Dinosaur-Game.io, Crossy-Road.io, Snow Rider 3D, Drive Mad 3, geometrylitegame.io, That's Not My Neighbor, Melon Playground, Capybara Game, FNF Games, 8Games.net, CrazyGames.tools, LoveMoneyGames.com, Zahraj.cz, iogames.onl, 1Games.io, TrendGames.io, StickmanHook2.io, GeometryDashSpam.io, SGameS.org, robbrainrot.io, Animalverse.social, BasketRandom.io, YupGames.io, GameDistribution CDN, + any site embedding Meeland in an iframe

Privacy

Disclaimer

For educational and entertainment purposes. Use at your own risk.

`; let _savedPointerLock = false; let _intentionalPointerExit = false; const anyPanelOpen = () => $('ml-plist')?.classList.contains('open') || $('ml-settings')?.classList.contains('open') || $('ml-pets')?.classList.contains('open') || $('ml-dialog')?.classList.contains('open') || $('ml-slots-pop')?.classList.contains('open'); function panelPause() { _savedPointerLock = _savedPointerLock || !!document.pointerLockElement; if (document.pointerLockElement) { _intentionalPointerExit = true; document.exitPointerLock(); } } function panelResume() { if (anyPanelOpen()) return; if (_savedPointerLock) { const app = W.pc?.app; if (app) app.fire('GameManager:LockMouse', 'GameManager:GameResumed', null, 'GameManager:GamePause'); } _savedPointerLock = false; } let _ptCache = null, _ptCacheTime = 0; let _etCache = null, _etCacheTime = 0; function _getPetTycoon() { const now = Date.now(); if (_ptCacheTime && now - _ptCacheTime < 5000) return _ptCache; _ptCacheTime = now; const app = W.pc?.app; if (!app) return (_ptCache = null); const e = app.root?.findByName('PetTycoonRoom')?.script?.petTycoon || app.root?.find(e => e.script?.petTycoon)?.[0]?.script?.petTycoon; _ptCache = e || null; return _ptCache; } function _getEscapeTsunami() { const now = Date.now(); if (_etCacheTime && now - _etCacheTime < 5000) return _etCache; _etCacheTime = now; const app = W.pc?.app; if (!app) return (_etCache = null); const e = app.root?.findByName('EscapeTsunamiRoom')?.script?.escapeTsunamiRoom || app.root?.find(e => e.script?.escapeTsunamiRoom)?.[0]?.script?.escapeTsunamiRoom; _etCache = e || null; return _etCache; } let _nmCache = null, _nmCacheTime = 0; let _bmCache = null, _bmCacheTime = 0; function _getNetworkManager() { const now = Date.now(); if (_nmCacheTime && now - _nmCacheTime < 5000) return _nmCache; _nmCacheTime = now; _nmCache = W.pc?.app?.root?.findByName('NetworkManager')?.script?.networkManager || null; return _nmCache; } function _getBasesManager() { const now = Date.now(); if (_bmCacheTime && now - _bmCacheTime < 5000) return _bmCache; _bmCacheTime = now; _bmCache = W.pc?.app?.root?.findByName('Bases')?.script?.petTycoonBasesManager || null; return _bmCache; } const _serverLockedSessions = new Set(); let _lockDataReceived = false; function createHUD() { if ($('ml-hud')) return; const s = document.createElement('style'); s.textContent = [ '#ml-hud{display:none}', '#ml-dialog{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.75);z-index:100000;display:none;overflow:auto;padding:40px 20px;box-sizing:border-box;scrollbar-width:auto;scrollbar-color:rgba(160,120,240,.5) rgba(255,255,255,.06);-webkit-overflow-scrolling:touch;touch-action:pan-y}', '#ml-dialog::-webkit-scrollbar{width:8px}', '#ml-dialog::-webkit-scrollbar-track{background:rgba(255,255,255,.06);border-radius:4px}', '#ml-dialog::-webkit-scrollbar-thumb{background:rgba(160,120,240,.5);border-radius:4px;border:1px solid rgba(255,255,255,.08)}', '#ml-dialog::-webkit-scrollbar-thumb:hover{background:rgba(160,120,240,.7)}', '#ml-dialog.open{display:block}', '#ml-inner{background:#181818;color:#ccc;max-width:580px;margin:0 auto;border-radius:8px;padding:24px 28px;font-family:sans-serif;font-size:14px;line-height:1.65;position:relative}', '#ml-inner h1{color:#fff;font-size:1.2em;margin:0 0 10px}', '#ml-inner h2{color:#aaa;font-size:.85em;text-transform:uppercase;letter-spacing:.08em;margin:18px 0 6px;border-top:1px solid #333;padding-top:12px}', '#ml-inner li{margin:4px 0}', '#ml-inner kbd{background:#2a2a2a;border:1px solid #444;border-radius:3px;padding:1px 5px;font-family:monospace;font-size:.9em}', '#ml-inner a{color:#4af}', '#ml-inner blockquote{border-left:3px solid #333;margin:8px 0 0;padding:6px 12px;color:#888;font-size:.9em}', '#ml-close{position:absolute;top:10px;right:14px;cursor:pointer;color:#555;font-size:20px;background:none;border:none;font-family:monospace;line-height:1}', '#ml-close:hover{color:#fff}', '#ml-plist{position:fixed;top:50%;right:20px;transform:translateY(-50%);width:260px;max-height:70vh;display:none;z-index:100001;pointer-events:auto;overflow:hidden;border-radius:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:linear-gradient(170deg,rgba(55,45,80,.92) 0%,rgba(45,38,72,.94) 40%,rgba(40,32,65,.95) 100%);border:1.5px solid rgba(160,120,240,.3);box-shadow:0 8px 32px rgba(0,0,0,.4),0 0 0 1px rgba(80,50,140,.2),0 0 60px rgba(120,80,200,.1);user-select:none}', '#ml-plist::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#7c3aed,#a855f7,#c084fc,#a855f7,#7c3aed);border-radius:16px 16px 0 0;z-index:1}', '#ml-plist.open{display:flex;flex-direction:column}', '#ml-plist-head{padding:14px 14px 10px;display:flex;align-items:center;justify-content:space-between}', '#ml-plist-title{font-size:14px;font-weight:800;color:rgba(255,250,255,.97);letter-spacing:.02em}', '#ml-plist-timer{font-size:10px;color:rgba(190,155,245,.65);font-variant-numeric:tabular-nums;margin-left:6px;font-weight:600}', '#ml-plist-refresh{cursor:pointer;background:rgba(140,100,220,.12);border:1px solid rgba(140,100,220,.25);color:rgba(200,170,255,.8);font-size:12px;padding:3px 9px;border-radius:8px;font-family:inherit;transition:all .15s}', '#ml-plist-refresh:hover{background:rgba(140,100,220,.22);color:rgba(240,220,255,.95);border-color:rgba(140,100,220,.4)}', '#ml-plist-close{cursor:pointer;background:rgba(255,255,255,.08);border:none;color:rgba(220,200,245,.6);font-size:16px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:8px;font-family:inherit;line-height:1;transition:all .15s}', '#ml-plist-close:hover{color:#ff6b6b;background:rgba(255,80,80,.15)}', '#ml-plist-body{overflow-y:auto;flex:1;padding:4px 8px 6px;scrollbar-width:auto;scrollbar-color:rgba(160,120,240,.5) rgba(255,255,255,.06);-webkit-overflow-scrolling:touch;touch-action:pan-y}', '#ml-plist-body::-webkit-scrollbar{width:8px}', '#ml-plist-body::-webkit-scrollbar-track{background:rgba(255,255,255,.06);border-radius:4px}', '#ml-plist-body::-webkit-scrollbar-thumb{background:rgba(160,120,240,.5);border-radius:4px;border:1px solid rgba(255,255,255,.08)}', '#ml-plist-body::-webkit-scrollbar-thumb:hover{background:rgba(160,120,240,.7)}', '#ml-plist-empty{color:rgba(190,155,245,.5);text-align:center;padding:20px 8px;font-size:12px;font-style:italic}', '.ml-prow{display:flex;align-items:center;gap:8px;padding:7px 10px;margin:2px 0;border-radius:10px;cursor:pointer;transition:all .15s;border:1px solid transparent;background:rgba(140,100,220,.04)}', '.ml-prow:hover{background:rgba(140,100,220,.1);border-color:rgba(140,100,220,.15)}', '.ml-prow:active{background:rgba(140,100,220,.18);transform:scale(.98);border-color:rgba(140,100,220,.25)}', '.ml-pnum{font-size:10px;color:rgba(168,130,230,.6);font-weight:700;min-width:16px;text-align:right;font-variant-numeric:tabular-nums}', '.ml-pinfo{flex:1;overflow:hidden}', '.ml-pname{font-size:12.5px;font-weight:600;color:rgba(255,250,255,.97);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.3}', '.ml-pdist{font-size:10px;color:rgba(168,130,230,.55);line-height:1.2}', '.ml-parrow{color:rgba(140,100,220,.3);font-size:14px;transition:all .15s}', '.ml-prow:hover .ml-parrow{color:rgba(168,130,230,.75);transform:translateX(3px)}', '#ml-settings{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:320px;max-height:80vh;display:none;z-index:100002;pointer-events:auto;overflow:hidden;border-radius:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;user-select:none;background:linear-gradient(170deg,rgba(55,45,80,.92) 0%,rgba(45,38,72,.94) 40%,rgba(40,32,65,.95) 100%);border:1.5px solid rgba(160,120,240,.3);box-shadow:0 8px 32px rgba(0,0,0,.4),0 0 0 1px rgba(80,50,140,.2),0 0 60px rgba(120,80,200,.1)}', '#ml-settings::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#7c3aed,#a855f7,#c084fc,#a855f7,#7c3aed);border-radius:16px 16px 0 0;z-index:1}', '#ml-settings.open{display:flex;flex-direction:column}', '#ml-settings-head{position:relative;padding:18px 18px 14px;display:flex;align-items:center;justify-content:space-between}', '#ml-settings-title{font-size:16px;font-weight:800;color:rgba(255,250,255,.97);letter-spacing:.02em}', '#ml-settings-close{cursor:pointer;background:rgba(255,255,255,.08);border:none;color:rgba(220,200,245,.6);font-size:16px;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:8px;font-family:inherit;line-height:1;transition:all .15s}', '#ml-settings-close:hover{color:#ff6b6b;background:rgba(255,80,80,.15)}', '#ml-settings-reset{cursor:pointer;background:rgba(255,255,255,.08);border:1px solid rgba(160,120,240,.25);color:rgba(220,200,245,.7);font-size:10px;padding:5px 14px;border-radius:8px;font-family:inherit;font-weight:600;transition:all .15s}', '#ml-settings-reset:hover{color:rgba(240,220,255,.9);background:rgba(140,100,220,.15);border-color:rgba(140,100,220,.4)}', '#ml-settings-body{position:relative;overflow-y:auto;flex:1;padding:2px 12px 14px;scrollbar-width:auto;scrollbar-color:rgba(160,120,240,.5) rgba(255,255,255,.06);-webkit-overflow-scrolling:touch;touch-action:pan-y}', '#ml-settings-body::-webkit-scrollbar{width:8px}', '#ml-settings-body::-webkit-scrollbar-track{background:rgba(255,255,255,.06);border-radius:4px}', '#ml-settings-body::-webkit-scrollbar-thumb{background:rgba(160,120,240,.5);border-radius:4px;border:1px solid rgba(255,255,255,.08)}', '#ml-settings-body::-webkit-scrollbar-thumb:hover{background:rgba(160,120,240,.7)}', '.ml-sgroup{margin:0 0 2px}', '#ml-tabs{display:flex;gap:4px;padding:0 16px 12px;margin-bottom:2px;border-bottom:1px solid rgba(160,120,240,.15)}', '.ml-tab{flex:1;padding:8px 0;font-size:11px;font-weight:700;text-align:center;color:rgba(200,180,240,.5);cursor:pointer;transition:all .2s;border-radius:10px;background:rgba(255,255,255,.05);border:1px solid transparent;font-family:inherit}', '.ml-tab:hover{color:rgba(200,180,240,.7);background:rgba(140,100,220,.08)}', '.ml-tab.active{color:#fff;background:linear-gradient(135deg,rgba(140,90,230,.45) 0%,rgba(110,70,210,.35) 100%);border-color:rgba(160,110,240,.35);box-shadow:0 2px 12px rgba(130,80,220,.25),inset 0 1px 0 rgba(255,255,255,.1)}', '.ml-tab-content{display:none;min-height:380px}', '.ml-tab-content.active{display:block}', '.ml-srow{display:flex;align-items:center;justify-content:space-between;padding:9px 10px;border-radius:10px;transition:all .12s;margin:1px 0}', '.ml-srow:hover{background:rgba(140,100,220,.06)}', '.ml-srow-label{font-size:13px;color:rgba(245,238,255,.92);flex:1;font-weight:500}', '.ml-srow-value{font-size:11px;color:rgba(190,155,245,.9);font-variant-numeric:tabular-nums;min-width:34px;text-align:right;margin-right:8px;font-weight:700}', '.ml-toggle{position:relative;width:40px;height:22px;border-radius:11px;background:rgba(255,255,255,.12);border:1.5px solid rgba(255,255,255,.15);cursor:pointer;transition:all .2s;flex-shrink:0}', '.ml-toggle::after{content:"";position:absolute;top:3px;left:3px;width:14px;height:14px;border-radius:7px;background:rgba(255,255,255,.35);transition:all .2s;box-shadow:0 1px 3px rgba(0,0,0,.3)}', '.ml-toggle.on{background:linear-gradient(135deg,#7c3aed 0%,#a855f7 100%);border-color:rgba(168,85,247,.5)}', '.ml-toggle.on::after{left:21px;background:#fff;box-shadow:0 1px 4px rgba(120,60,220,.4),0 0 8px rgba(168,85,247,.3)}', '.ml-slider{-webkit-appearance:none;appearance:none;width:90px;height:6px;border-radius:3px;background:rgba(255,255,255,.12);outline:none;cursor:pointer;border:none}', '.ml-slider::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:9px;background:linear-gradient(135deg,#a855f7 0%,#7c3aed 100%);border:2px solid rgba(255,255,255,.25);box-shadow:0 2px 8px rgba(120,60,220,.4);cursor:pointer;transition:all .15s}', '.ml-slider::-webkit-slider-thumb:hover{transform:scale(1.1);box-shadow:0 2px 12px rgba(120,60,220,.5)}', '.ml-slider::-moz-range-thumb{width:18px;height:18px;border-radius:9px;background:linear-gradient(135deg,#a855f7 0%,#7c3aed 100%);border:2px solid rgba(255,255,255,.25);box-shadow:0 2px 8px rgba(120,60,220,.4);cursor:pointer}', '#ml-keybinds-body{padding:0}', '.ml-krow{display:flex;align-items:center;justify-content:space-between;padding:9px 10px;border-radius:10px;cursor:pointer;transition:all .12s;margin:1px 0}', '.ml-krow:hover{background:rgba(140,100,220,.06)}', '.ml-krow.listening{background:rgba(255,180,40,.1);border:1px solid rgba(255,180,40,.35);border-radius:10px}', '.ml-krow-action{font-size:13px;color:rgba(245,238,255,.92);font-weight:500}', '.ml-krow-key{font-size:11px;color:rgba(190,155,245,.9);font-weight:700;padding:4px 10px;border-radius:8px;background:rgba(140,100,220,.1);border:1px solid rgba(140,100,220,.2);min-width:40px;text-align:center;transition:all .15s}', '.ml-krow.listening .ml-krow-key{color:rgba(255,200,80,.9);background:rgba(120,80,0,.15);border-color:rgba(255,180,40,.4)}', '#ml-pets{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:680px;max-height:82vh;display:none;z-index:100004;pointer-events:auto;overflow:hidden;border-radius:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;user-select:none;background:linear-gradient(170deg,rgba(55,45,80,.92) 0%,rgba(45,38,72,.94) 40%,rgba(40,32,65,.95) 100%);border:1.5px solid rgba(160,120,240,.3);box-shadow:0 8px 32px rgba(0,0,0,.4),0 0 0 1px rgba(80,50,140,.2),0 0 60px rgba(120,80,200,.1)}', '#ml-pets::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#7c3aed,#a855f7,#c084fc,#a855f7,#7c3aed);border-radius:16px 16px 0 0;z-index:1}', '#ml-pets.open{display:flex;flex-direction:column}', '#ml-pets-head{position:relative;padding:16px 18px 12px;display:flex;align-items:center;justify-content:space-between}', '#ml-pets-title{font-size:16px;font-weight:800;color:rgba(255,250,255,.97);letter-spacing:.02em}', '#ml-pets-count{font-size:10px;color:rgba(190,155,245,.7);margin-left:8px;font-weight:600}', '#ml-pets-close{cursor:pointer;background:rgba(255,255,255,.08);border:none;color:rgba(220,200,245,.6);font-size:16px;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:8px;font-family:inherit;line-height:1;transition:all .15s}', '#ml-pets-close:hover{color:#ff6b6b;background:rgba(255,80,80,.15)}', '#ml-pets-filter{position:relative;padding:8px 14px;border-bottom:1px solid rgba(160,120,240,.15)}', '#ml-pets-search{width:100%;background:rgba(255,255,255,.07);border:1.5px solid rgba(160,120,240,.25);color:rgba(240,230,255,.9);font-size:11px;padding:7px 12px;border-radius:10px;font-family:inherit;outline:none;box-sizing:border-box;transition:all .15s}', '#ml-pets-search:focus{border-color:rgba(140,100,220,.45);box-shadow:0 0 8px rgba(120,70,200,.12)}', '#ml-pets-search::placeholder{color:rgba(168,130,230,.35)}', '#ml-pets-body{position:relative;overflow-y:auto;flex:1;padding:0;scrollbar-width:auto;scrollbar-color:rgba(160,120,240,.5) rgba(255,255,255,.06);-webkit-overflow-scrolling:touch;touch-action:pan-y}', '#ml-pets-body::-webkit-scrollbar{width:8px}', '#ml-pets-body::-webkit-scrollbar-track{background:rgba(255,255,255,.06);border-radius:4px}', '#ml-pets-body::-webkit-scrollbar-thumb{background:rgba(160,120,240,.5);border-radius:4px;border:1px solid rgba(255,255,255,.08)}', '#ml-pets-body::-webkit-scrollbar-thumb:hover{background:rgba(160,120,240,.7)}', '#ml-ptable{width:100%;border-collapse:collapse;font-size:11px}', '#ml-ptable th{position:sticky;top:0;background:linear-gradient(180deg,rgba(55,45,80,.98),rgba(45,38,72,.95));color:rgba(168,130,230,.7);font-size:9.5px;text-transform:uppercase;letter-spacing:.15em;padding:7px 8px;text-align:left;cursor:pointer;border-bottom:1px solid rgba(140,100,220,.15);white-space:nowrap;transition:color .12s;z-index:1;font-weight:700}', '#ml-ptable th:hover{color:rgba(200,170,255,.95)}', '#ml-ptable th.sort-asc::after{content:" ▲";font-size:8px}', '#ml-ptable th.sort-desc::after{content:" ▼";font-size:8px}', '#ml-ptable td{padding:5px 8px;border-bottom:1px solid rgba(160,120,240,.08);color:rgba(245,238,255,.85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:140px}', '#ml-ptable tr:hover td{background:rgba(140,100,220,.08)}', '#ml-ptable .own-you{color:rgba(80,255,120,.9);font-weight:600}', '#ml-ptable .own-wild{color:rgba(255,190,60,.85);font-style:italic}', '#ml-ptable .pet-var{color:rgba(180,140,255,.85);font-style:italic}', '#ml-ptable .pet-mut-Golden{color:rgba(255,215,0,.95)}', '#ml-ptable .pet-mut-Diamond{color:rgba(185,242,255,.95)}', '#ml-ptable .pet-mut-Emerald{color:rgba(80,255,120,.95)}', '#ml-ptable .pet-mut-Rainbow{color:rgba(255,120,200,.95)}', '#ml-ptable .pet-mut-Galaxy{color:rgba(200,140,255,.95)}', '#ml-ptable .pet-rar{font-size:10px;letter-spacing:.05em}', '.pet-tp{background:rgba(140,100,220,.15);border:1px solid rgba(140,100,220,.3);color:rgba(200,170,255,.8);font-size:11px;padding:3px 8px;border-radius:8px;cursor:pointer;transition:all .12s;line-height:1}', '.pet-tp:hover{background:rgba(140,100,220,.3);color:#fff;border-color:rgba(168,120,255,.6)}', '.pet-grab{background:rgba(60,200,60,.15);border:1px solid rgba(60,200,60,.3);color:rgba(140,255,140,.8);font-size:11px;padding:3px 8px;border-radius:8px;cursor:pointer;transition:all .12s;line-height:1;margin-left:3px}', '.pet-grab:hover{background:rgba(60,200,60,.3);color:#fff;border-color:rgba(80,230,80,.6)}', '#ml-pets-empty{color:rgba(190,155,245,.5);text-align:center;padding:30px 8px;font-size:12px;font-style:italic}', '#ml-slots-pop{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:300px;max-height:70vh;display:none;z-index:100003;pointer-events:auto;overflow:hidden;border-radius:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;user-select:none;background:linear-gradient(170deg,rgba(55,45,80,.92) 0%,rgba(45,38,72,.94) 40%,rgba(40,32,65,.95) 100%);border:1.5px solid rgba(160,120,240,.3);box-shadow:0 8px 32px rgba(0,0,0,.4),0 0 0 1px rgba(80,50,140,.2),0 0 60px rgba(120,80,200,.1)}', '#ml-slots-pop::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#7c3aed,#a855f7,#c084fc,#a855f7,#7c3aed);border-radius:16px 16px 0 0;z-index:1}', '#ml-slots-pop.open{display:flex;flex-direction:column}', '#ml-slots-pop-head{padding:14px 14px 10px;display:flex;align-items:center;justify-content:space-between}', '#ml-slots-pop-title{font-size:14px;font-weight:800;color:rgba(255,250,255,.97);letter-spacing:.02em}', '#ml-slots-pop-close{cursor:pointer;background:rgba(255,255,255,.08);border:none;color:rgba(220,200,245,.6);font-size:16px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:8px;font-family:inherit;line-height:1;transition:all .15s}', '#ml-slots-pop-close:hover{color:#ff6b6b;background:rgba(255,80,80,.15)}', '#ml-slots-pop-body{overflow-y:auto;flex:1;padding:4px 8px 8px;scrollbar-width:auto;scrollbar-color:rgba(160,120,240,.5) rgba(255,255,255,.06);-webkit-overflow-scrolling:touch;touch-action:pan-y}', '#ml-slots-pop-body::-webkit-scrollbar{width:8px}', '#ml-slots-pop-body::-webkit-scrollbar-track{background:rgba(255,255,255,.06);border-radius:4px}', '#ml-slots-pop-body::-webkit-scrollbar-thumb{background:rgba(160,120,240,.5);border-radius:4px;border:1px solid rgba(255,255,255,.08)}', '#ml-slots-pop-body::-webkit-scrollbar-thumb:hover{background:rgba(160,120,240,.7)}', '.ml-slot{display:flex;align-items:center;gap:6px;padding:5px 8px;margin:2px 0;border-radius:8px;transition:all .12s;border:1px solid transparent}', '.ml-slot:hover{background:rgba(140,100,220,.1);border-color:rgba(140,100,220,.15)}', '.ml-slot-num{font-size:10px;color:rgba(168,130,230,.6);font-weight:700;min-width:14px;text-align:right}', '.ml-slot-info{flex:1;font-size:10px;color:rgba(200,180,240,.65);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}', '.ml-slot-info.filled{color:rgba(200,180,240,.9)}', '.ml-slot-go{background:rgba(140,100,220,.15);border:1px solid rgba(140,100,220,.25);color:rgba(200,170,255,.8);font-size:10px;padding:2px 8px;border-radius:6px;cursor:pointer;transition:all .12s}', '.ml-slot-go:hover{background:rgba(140,100,220,.3);color:#fff}', '.ml-slot-go.empty{opacity:.35;pointer-events:none}', '.ml-slot-set{background:rgba(60,180,60,.12);border:1px solid rgba(60,180,60,.25);color:rgba(140,230,140,.8);font-size:10px;padding:2px 8px;border-radius:6px;cursor:pointer;transition:all .12s}', '.ml-slot-set:hover{background:rgba(60,180,60,.25);color:#fff}', '.ml-slot-clr{background:rgba(220,60,60,.12);border:1px solid rgba(220,60,60,.25);color:rgba(255,140,140,.8);font-size:10px;padding:2px 6px;border-radius:6px;cursor:pointer;transition:all .12s}', '.ml-slot-clr:hover{background:rgba(220,60,60,.25);color:#fff}', '.ml-slot-clr.empty{opacity:.35;pointer-events:none}', '#ml-snipe{position:fixed;top:60px;right:10px;width:360px;max-height:calc(100vh - 20px);display:none;z-index:100005;pointer-events:auto;overflow:hidden auto;border-radius:16px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;user-select:none;background:linear-gradient(170deg,rgba(55,45,80,.92) 0%,rgba(45,38,72,.94) 40%,rgba(40,32,65,.95) 100%);border:1.5px solid rgba(240,120,120,.3);box-shadow:0 8px 32px rgba(0,0,0,.4),0 0 0 1px rgba(140,50,50,.2),0 0 60px rgba(200,80,80,.1)}', '#ml-snipe::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#ed3a3a,#f75555,#fc8484,#f75555,#ed3a3a);border-radius:16px 16px 0 0;z-index:1}', '#ml-snipe.open{display:flex;flex-direction:column}', '#ml-snipe-head{padding:14px 14px 10px;display:flex;align-items:center;justify-content:space-between}', '#ml-snipe-title{font-size:14px;font-weight:800;color:rgba(255,250,255,.97);letter-spacing:.02em}', '#ml-snipe-close{cursor:pointer;background:rgba(255,255,255,.08);border:none;color:rgba(220,200,245,.6);font-size:16px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:8px;font-family:inherit;line-height:1;transition:all .15s}', '#ml-snipe-close:hover{color:#ff6b6b;background:rgba(255,80,80,.15)}', '#ml-snipe-body{padding:8px 14px 14px}', '#ml-snipe-search{width:100%;background:rgba(255,255,255,.07);border:1.5px solid rgba(240,120,120,.25);color:rgba(240,230,255,.9);font-size:11px;padding:7px 12px;border-radius:10px;font-family:inherit;outline:none;box-sizing:border-box;transition:all .15s}', '#ml-snipe-search:focus{border-color:rgba(240,120,120,.45);box-shadow:0 0 8px rgba(200,70,70,.12)}', '#ml-snipe-search::placeholder{color:rgba(255,170,170,.5)}', '#ml-snipe-toggle{width:100%;margin-top:10px;padding:8px 0;border-radius:10px;border:1.5px solid rgba(240,120,120,.3);background:rgba(240,120,120,.12);color:rgba(255,200,200,.95);font-size:12px;font-weight:700;cursor:pointer;transition:all .15s;font-family:inherit}', '#ml-snipe-toggle:hover{background:rgba(240,120,120,.25)}', '#ml-snipe-toggle.active{background:rgba(60,200,60,.15);border-color:rgba(60,200,60,.3);color:rgba(140,255,140,.95)}', '#ml-snipe-status{margin-top:8px;font-size:11px;color:rgba(255,220,220,.85);min-height:14px}', '#ml-snipe-types{margin-top:4px;font-size:10px;color:rgba(255,220,210,.9);line-height:1.5;max-height:80px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(240,120,120,.3) transparent;-webkit-overflow-scrolling:touch;touch-action:pan-y}', '.ml-snipe-type-row{padding:1px 0;border-bottom:1px solid rgba(240,120,120,.06)}', '#ml-snipe-log{margin-top:6px;max-height:120px;overflow-y:auto;font-size:9.5px;color:rgba(220,200,240,.7);scrollbar-width:thin;scrollbar-color:rgba(160,120,240,.4) transparent;-webkit-overflow-scrolling:touch;touch-action:pan-y}', '.ml-snipe-entry{padding:1px 0;border-bottom:1px solid rgba(160,120,240,.08);font-family:monospace;letter-spacing:-.02em}', '#ml-carry-timer{position:fixed;bottom:18px;left:18px;display:none;padding:6px 14px;border-radius:10px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;font-weight:800;color:rgba(255,220,140,.95);background:rgba(40,32,60,.85);border:1.5px solid rgba(255,180,80,.35);box-shadow:0 4px 16px rgba(0,0,0,.3);z-index:100010;pointer-events:none;letter-spacing:.03em}', ].join(''); document.head.appendChild(s); const h = document.createElement('div'); const carryTimer = document.createElement('div'); carryTimer.id = 'ml-carry-timer'; document.body.appendChild(carryTimer); h.id = 'ml-hud'; h.innerHTML = ''; document.body.appendChild(h); const d = document.createElement('div'); d.id = 'ml-dialog'; d.innerHTML = `
${DESCRIPTION}
`; document.body.appendChild(d); const plist = document.createElement('div'); plist.id = 'ml-plist'; plist.innerHTML = '
Players10s
No other players found
'; document.body.appendChild(plist); const settings = document.createElement('div'); settings.id = 'ml-settings'; settings.innerHTML = `
Settings
Move
Features
Auto
Keys
Acceleration
Speed Cap${SPEED_CAP}
Accel Rate${ACCEL}
Base Speed${SPEED_DEFAULT}
Fly Hack
Speed Hack
Waypoints
Anti-Knockback
Noclip
Free Daily Money
Invincibility
Ghost Mode
Username
Cuddle Panel
Continuous Cuddle
Pet Browser
Auto-Lock Base
Auto-Collect Earnings
Collect Interval${autoCollectInterval}s
Auto-Free Stars
Auto-Attack Pet Thieves
Auto-Fountain (1.5× Profit)
Invisible Mode
Pro Tips
`; document.body.appendChild(settings); const KB_LABELS = { fly: 'Fly (toggle/up)', flyDown: 'Fly Down', setHome: 'Set Home', home: 'Teleport Home', back: 'Back Teleport', cuddle: 'Cuddle Panel', settings: 'Settings', pets: 'Pet Browser', slots: 'Waypoint Slots', snipe: 'Pet Sniper', attack: 'Attack', help: 'Help / Description', }; function keyCodeLabel(code) { if (code === 'Space') return 'Space'; if (code === 'Backquote') return '`'; if (code.startsWith('Key')) return code.slice(3); if (code.startsWith('Digit')) return code.slice(5); return code; } function buildKeybindsHTML() { let rows = ''; for (const [action, code] of Object.entries(KEYBINDS)) { rows += '
' + (KB_LABELS[action] || action) + '' + keyCodeLabel(code) + '
'; } $('ml-keybinds-body').innerHTML = rows; } buildKeybindsHTML(); const petsPanel = document.createElement('div'); petsPanel.id = 'ml-pets'; petsPanel.innerHTML = '
Pets
' + petRefreshInterval + 's
Words are AND\u2019d together. Use OR for alternatives, brackets to group. * or % as wildcard.
'; document.body.appendChild(petsPanel); const slotsPop = document.createElement('div'); slotsPop.id = 'ml-slots-pop'; slotsPop.innerHTML = '
Waypoint Slots
'; document.body.appendChild(slotsPop); function buildSlotsHTML() { const body = $('ml-slots-pop-body'); if (!body) return; let html = ''; for (let i = 0; i < 10; i++) { const s = slots[i]; const info = s ? `${s.x.toFixed(1)}, ${s.y.toFixed(1)}, ${s.z.toFixed(1)}` : 'empty'; html += `
${i}${info}
`; } body.innerHTML = html; } buildSlotsHTML(); $('ml-slots-pop-close').addEventListener('click', () => toggleSlots(false)); slotsPop.addEventListener('click', e => { const goBtn = e.target.closest('.ml-slot-go'); const setBtn = e.target.closest('.ml-slot-set'); const clrBtn = e.target.closest('.ml-slot-clr'); if (!goBtn && !setBtn && !clrBtn) return; const idx = parseInt((goBtn || setBtn || clrBtn).dataset.slot); if (isNaN(idx)) return; const p = getPlayer(); if (!p) return; if (clrBtn) { slots[idx] = null; saveWaypoints(); flash('ml-slots'); buildSlotsHTML(); console.log(`[slot ${idx}] cleared`); } else if (setBtn) { slots[idx] = capturePos(p); saveWaypoints(); flash('ml-slots'); buildSlotsHTML(); console.log(`[slot ${idx}] saved via popout`); } else if (goBtn && slots[idx]) { backPos = capturePos(p); teleport(p, slots[idx]); saveWaypoints(); flash('ml-slots'); toggleSlots(false); console.log(`[slot ${idx}] teleported via popout`); } }); slotsPop.addEventListener('ml-rebuild', () => buildSlotsHTML()); const snipePanel = document.createElement('div'); snipePanel.id = 'ml-snipe'; snipePanel.innerHTML = '
Pet Sniper
Words are AND\u2019d. Use OR for alternatives, brackets to group. * or % as wildcard.
Idle
'; document.body.appendChild(snipePanel); [plist, settings, d, petsPanel, slotsPop, snipePanel].forEach(el => { ['mousedown','mouseup','click','pointerdown','pointerup','mousemove','mouseover','mouseenter','mouseleave','wheel','contextmenu','pointermove','pointerover','pointerenter'].forEach(evt => { el.addEventListener(evt, e => e.stopPropagation()); }); ['keydown','keyup','keypress'].forEach(evt => { el.addEventListener(evt, e => e.stopPropagation()); }); }); function makeDraggable(panel, handle) { let dragging = false, ox = 0, oy = 0; handle.style.cursor = 'grab'; panel.style.resize = 'both'; panel.style.overflow = 'auto'; function startDrag(cx, cy, tag) { if (tag === 'BUTTON' || tag === 'INPUT' || tag === 'LABEL') return false; dragging = true; handle.style.cursor = 'grabbing'; const rect = panel.getBoundingClientRect(); panel.style.left = rect.left + 'px'; panel.style.top = rect.top + 'px'; panel.style.right = 'auto'; panel.style.bottom = 'auto'; panel.style.transform = 'none'; ox = cx - rect.left; oy = cy - rect.top; return true; } function moveDrag(cx, cy) { if (!dragging) return; const ph = panel.offsetHeight || 40; const pw = panel.offsetWidth || 40; panel.style.left = Math.max(0, Math.min(cx - ox, window.innerWidth - Math.min(pw, 40))) + 'px'; panel.style.top = Math.max(0, Math.min(cy - oy, window.innerHeight - Math.min(ph, 40))) + 'px'; } function endDrag() { if (dragging) { dragging = false; handle.style.cursor = 'grab'; } } handle.addEventListener('mousedown', e => { if (startDrag(e.clientX, e.clientY, e.target.tagName)) e.preventDefault(); }); window.addEventListener('mousemove', e => moveDrag(e.clientX, e.clientY), true); window.addEventListener('mouseup', endDrag, true); handle.addEventListener('touchstart', e => { const t = e.touches[0]; if (startDrag(t.clientX, t.clientY, e.target.tagName)) { e.preventDefault(); e.stopPropagation(); } }, { passive: false }); window.addEventListener('touchmove', e => { if (!dragging) return; moveDrag(e.touches[0].clientX, e.touches[0].clientY); e.preventDefault(); }, { passive: false, capture: true }); window.addEventListener('touchend', endDrag, true); panel._resetPos = () => { panel.style.left = ''; panel.style.top = ''; panel.style.right = ''; panel.style.bottom = ''; panel.style.transform = ''; panel.style.width = ''; panel.style.height = ''; }; } makeDraggable(plist, $('ml-plist-head')); makeDraggable(settings, $('ml-settings-head')); makeDraggable(petsPanel, $('ml-pets-head')); makeDraggable(slotsPop, $('ml-slots-pop-head')); makeDraggable(snipePanel, $('ml-snipe-head')); makeDraggable(d.querySelector('#ml-inner'), d.querySelector('#ml-inner h1')); function syncSettingsUI() { syncSlider('ml-s-cap', 'ml-sv-cap', SPEED_CAP); syncSlider('ml-s-accel', 'ml-sv-accel', ACCEL); syncSlider('ml-s-base', 'ml-sv-base', SPEED_DEFAULT); syncSlider('ml-s-acinterval', 'ml-sv-acinterval', autoCollectInterval, 's'); const ae = $('ml-s-accel-en'); if (ae) ae.classList.toggle('on', accelEnabled); const featVals = [featFly, featSprint, featWaypoints, featCuddle, featCuddleFollow, featPets, featAutoLock, featAntiKnockback, featNoclip, featFreeMoney, featAutoCollect, featInvincible, featGhostMode, featFreeStars, featAutoAttack, featAutoFountain, featInvisible, featProTips]; FEAT_IDS.forEach((id, i) => { const el = $(id); if (el) el.classList.toggle('on', featVals[i]); }); } syncSettingsUI(); function getPlayers() { const holder = W.pc?.app?.root?.findByName('EnemyHolder'); if (!holder) return []; const player = getPlayer(); const playerPos = player?.getPosition(); const results = []; for (const enemy of holder.children) { const pos = enemy.getPosition(); let username = null; try { username = enemy.script?.enemy?.usernameEntity?.element?.text; } catch (_) {} if (!username) { const ue = enemy.findByName?.('Username'); if (ue?.element?.text) username = ue.element.text; } if (!username || username === 'Enemy') username = enemy.name !== 'Enemy' ? enemy.name : null; if (!username) username = 'Player'; const dist = playerPos ? Math.floor(playerPos.distance(pos)) : '?'; results.push({ name: username, dist, pos: vec3(pos), entity: enemy }); } results.sort((a, b) => (typeof a.dist === 'number' && typeof b.dist === 'number') ? a.dist - b.dist : 0); return results; } function refreshPlayerList() { const body = $('ml-plist-body'); if (!body) return; const players = getPlayers(); if (players.length === 0) { body.innerHTML = '
No other players found
'; return; } body.innerHTML = ''; players.forEach((p, i) => { const row = document.createElement('div'); row.className = 'ml-prow'; row.innerHTML = `${i + 1}
${p.dist}m
`; row.querySelector('.ml-pname').textContent = p.name; row.addEventListener('click', () => { const player = getPlayer(); if (!player) return; const freshPos = p.entity?.getPosition(); const target = freshPos || p.pos; backPos = capturePos(player); teleport(player, vec3(target)); saveWaypoints(); if (featCuddleFollow) { cuddleTarget = p.entity; cuddling = true; console.log(`[cuddle] locked → ${p.name}`); } flash('ml-back'); const app = W.pc?.app; if (app) app.fire('GameManager:GameResumed'); }); body.appendChild(row); }); } function getPetOwnerId(pet) { if (!pet) return null; const d = pet.owner; if (d === false) return false; if (d != null) return d; return pet?.data?.owner ?? pet?.ownerId ?? pet?.data?.ownerId ?? null; } let _ownerMapCache = null; let _ownerMapTime = 0; function buildOwnerMap() { const now = Date.now(); if (_ownerMapCache && now - _ownerMapTime < 2000) return _ownerMapCache; const map = {}; const myId = W.pc?.sessionId; if (myId) map[myId] = 'Yours'; const nm = W.pc?.app?.root?.findByName('NetworkManager')?.script?.networkManager; if (nm?.sessionId && !map[nm.sessionId]) map[nm.sessionId] = 'Yours'; const holder = W.pc?.app?.root?.findByName('EnemyHolder'); if (holder) { for (const child of holder.children) { let id = child.id || child.sessionId || child.playerId; if (!id && child.script) { for (const sk of Object.keys(child.script._scriptsIndex || {})) { const inst = child.script[sk]; id = inst?.id || inst?.sessionId || inst?.playerId; if (id) break; } } if (!id) continue; let name = null; try { name = child.script?.enemy?.usernameEntity?.element?.text; } catch (_) {} if (!name) { const ue = child.findByName?.('Username'); if (ue?.element?.text) name = ue.element.text; } if (name && name !== 'Enemy') map[id] = name; } } _ownerMapCache = map; _ownerMapTime = now; return map; } function getPetOwnerName(pet, ownerMap) { const ownerId = getPetOwnerId(pet); if (ownerId === false || ownerId == null) return 'Wild'; if (ownerMap?.[ownerId]) return ownerMap[ownerId]; return ownerId.length > 10 ? ownerId.substring(0, 8) + '…' : ownerId; } let _pmCache = null; let _pmCacheTime = 0; function getPetsManager() { const now = Date.now(); if (_pmCacheTime && now - _pmCacheTime < 5000) return _pmCache; const pmEntity = W.pc?.app?.root?.findByName('PetsManager'); let pm = pmEntity?.script?.petsManager; if (!pm && pmEntity?.script) { for (const k of Object.keys(pmEntity.script)) { const s = pmEntity.script[k]; if (s?.activePets || s?.basePets) { pm = s; break; } } } if (!pm) { const root = W.pc?.app?.root; if (!root) return null; root.find(e => { if (!e.script) return false; for (const k of Object.keys(e.script)) { const s = e.script[k]; if (s?.activePets || s?.basePets) { pm = s; return true; } } return false; }); } _pmCache = pm || null; _pmCacheTime = now; return _pmCache; } function getAllPets() { const pm = getPetsManager(); if (!pm) return []; hookPetSpawn(); const ownerMap = buildOwnerMap(); const pets = []; const scan = (map, type) => { if (!map) return; map.forEach((pet, token) => { const name = pet.name || String(token).substring(0, 8); const sd = petSpawnData.get(token); let mutation = sd?.mutation ?? ''; let rarity = sd?.rarity ?? ''; let profit = sd?.profit ?? null; if (mutation === 'Default') mutation = ''; if (!mutation) { try { if (pet._mlMut) { mutation = pet._mlMut; } else { const mutNames = ['Golden', 'Diamond', 'Emerald', 'Rainbow', 'Galaxy']; for (const mn of mutNames) { if (pet.findByName?.(`Mutation ${mn} Effect`)) { mutation = mn; break; } } if (mutation) pet._mlMut = mutation; } } catch (_) {} } if (!rarity) { try { if (pet._mlRar) { rarity = pet._mlRar; } else { const RARITIES = ['BASIC', 'RARE', 'EPIC', 'LEGENDARY', 'MYTHICAL', 'EXOTIC', 'SECRET', 'EXCLUSIVE']; for (const r of RARITIES) { const node = pet.findByName?.(r); if (node && node.enabled) { rarity = r; break; } } if (rarity) pet._mlRar = rarity; } } catch (_) {} } if (!profit) { try { const statsEl = pet.findByName?.('PetStats'); if (statsEl) { const profitEl = statsEl.findByName?.('Profit') || statsEl.findByName?.('PetProfit'); if (profitEl?.element?.text) { const m = profitEl.element.text.match(/\$\s*([\d,.]+)\s*([kmbtqsxi]*)/); if (m) { let v = parseFloat(m[1].replace(/,/g, '')); const suf = m[2]?.toLowerCase(); if (suf === 'k') v *= 1e3; else if (suf === 'm') v *= 1e6; else if (suf === 'b') v *= 1e9; else if (suf === 't') v *= 1e12; else if (suf === 'q') v *= 1e15; profit = v; } } } } catch (_) {} } const pos = pet.getPosition ? pet.getPosition() : pet.position; const price = pet.price ?? 0; pets.push({ token, name, price, income: profit ?? 0, owner: getPetOwnerName(pet, ownerMap), ownerId: getPetOwnerId(pet), type, mutation, rarity, x: pos?.x ?? 0, y: pos?.y ?? 0, z: pos?.z ?? 0, }); }); }; scan(pm.activePets, 'active'); scan(pm.basePets, 'base'); return pets; } let lastRenderedPets = []; const grabbedTokens = new Map(); function renderPetTable() { const body = $('ml-pets-body'); const countEl = $('ml-pets-count'); if (!body) return; let pets = getAllPets(); if (countEl) countEl.textContent = `(${pets.length})`; if (pets.length === 0) { lastRenderedPets = []; body.innerHTML = '
No pets found in this room
'; return; } if (petFilter) pets = pets.filter(p => petMatchesFilter(p, petFilter)); const playerPos = getPlayer()?.getPosition(); if (playerPos) pets.forEach(p => { p._dist = Math.hypot(p.x - playerPos.x, p.y - playerPos.y, p.z - playerPos.z); }); pets.sort((a, b) => { const key = petSortCol === 'dist' ? '_dist' : petSortCol; let av = a[key], bv = b[key]; if (av == null) av = Infinity; if (bv == null) bv = Infinity; if (typeof av === 'string') av = av.toLowerCase(); if (typeof bv === 'string') bv = bv.toLowerCase(); if (av < bv) return -petSortDir; if (av > bv) return petSortDir; return 0; }); lastRenderedPets = pets; const cols = ['name','mutation','rarity','owner','price','income','dist','go']; const labels = { name:'Name', mutation:'Mutation', rarity:'Rarity', owner:'Owner', price:'Worth', income:'Income/s', dist:'Dist', go:'' }; let html = ''; cols.forEach(c => { const cls = petSortCol === c ? (petSortDir === 1 ? 'sort-asc' : 'sort-desc') : ''; html += c === 'go' ? '' : ``; }); html += ''; const now = Date.now(); pets.forEach(p => { const ownerCls = p.owner === 'Yours' ? 'own-you' : p.owner === 'Wild' ? 'own-wild' : ''; const mutCls = p.mutation ? `pet-mut-${p.mutation}` : 'pet-var'; const tokenStr = String(p.token); const grabbed = grabbedTokens.has(tokenStr) && grabbedTokens.get(tokenStr) > now; const grabBtn = p.owner !== 'Yours' ? `` : ''; html += ``; }); html += '
${labels[c]}
${esc(p.name)}${esc(p.mutation) || '\u2014'}${esc(p.rarity) || '\u2014'}${esc(p.owner)}${numFmt(p.price)}${numFmt(p.income)}/s${p._dist != null ? numFmt(Math.round(p._dist)) : '\u2014'}${grabBtn}
'; body.innerHTML = html; } function findPetByToken(token) { return lastRenderedPets.find(p => String(p.token) === token) || null; } $('ml-pets-body').addEventListener('click', e => { const th = e.target.closest('th[data-col]'); if (th) { const col = th.dataset.col; if (petSortCol === col) petSortDir *= -1; else { petSortCol = col; petSortDir = col === 'price' || col === 'income' || col === 'dist' ? -1 : 1; } saveSettings(); renderPetTable(); return; } const tpBtn = e.target.closest('.pet-tp'); if (tpBtn) { const p = findPetByToken(tpBtn.dataset.token); if (!p) return; const player = getPlayer(); if (!player) return; player.setPosition(p.x, p.y + 1, p.z); togglePetsPanel(false); return; } const grabBtn = e.target.closest('.pet-grab'); if (grabBtn) { const p = findPetByToken(grabBtn.dataset.token); if (!p) return; const app = W.pc?.app; if (!app) return; const player = getPlayer(); if (!player) return; const tokenStr = String(p.token); const orig = player.getPosition().clone(); player.setPosition(p.x, p.y + 0.5, p.z); grabBtn.disabled = true; grabBtn.textContent = '…'; setTimeout(() => { app.fire('ModeOverlay:BuyPet', p.token); console.log(`[ml] grab pet: ${p.name} (${p.token})`); setTimeout(() => { player.setPosition(orig.x, orig.y, orig.z); setTimeout(() => { app.fire('NetworkManager:Send', 'dropPet'); console.log(`[ml] drop pet at origin`); grabbedTokens.set(tokenStr, Date.now() + 5000); renderPetTable(); }, 150); }, 150); }, 100); } }); function esc(s) { return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } function numFmt(n) { if (n >= 1e15) return (n / 1e15).toFixed(1) + 'q'; if (n >= 1e12) return (n / 1e12).toFixed(1) + 't'; if (n >= 1e9) return (n / 1e9).toFixed(1) + 'b'; if (n >= 1e6) return (n / 1e6).toFixed(1) + 'm'; if (n >= 1e3) return (n / 1e3).toFixed(1) + 'k'; return n % 1 === 0 ? String(n) : n.toFixed(1); } function petMatchesFilter(p, raw) { if (!raw) return true; const text = [p.name, p.owner, p.mutation, p.rarity].join(' ').toLowerCase(); const tokens = raw.match(/\(|\)|AND|OR|[^\s()]+/gi) || []; function parseOr(i) { let [result, j] = parseAnd(i); while (j < tokens.length && tokens[j]?.toUpperCase() === 'OR') { const [r2, j2] = parseAnd(j + 1); result = result || r2; j = j2; } return [result, j]; } function parseAnd(i) { let [result, j] = parseAtom(i); while (j < tokens.length) { const up = tokens[j]?.toUpperCase(); if (up === 'AND') { j++; } else if (up === 'OR' || tokens[j] === ')') break; const [r2, j2] = parseAtom(j); result = result && r2; j = j2; } return [result, j]; } function parseAtom(i) { if (i >= tokens.length) return [false, i]; if (tokens[i] === '(') { const [result, j] = parseOr(i + 1); return [result, j < tokens.length && tokens[j] === ')' ? j + 1 : j]; } const t = tokens[i].toLowerCase(); if (t.includes('*') || t.includes('%')) { const re = new RegExp(t.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/[*%]/g, '.*')); return [re.test(text), i + 1]; } return [text.includes(t), i + 1]; } try { return parseOr(0)[0]; } catch (_) { return text.includes(raw.toLowerCase()); } } let petRefreshTimer = null; function startPetRefresh() { stopPetRefresh(); petRefreshTimer = setInterval(() => renderPetTable(), petRefreshInterval * 1000); } function stopPetRefresh() { if (petRefreshTimer) { clearInterval(petRefreshTimer); petRefreshTimer = null; } } function togglePetsPanel(forceOpen) { const open = forceOpen !== undefined ? forceOpen : !petsPanel.classList.contains('open'); petsPanel.classList.toggle('open', open); if (open) { $('ml-pets-search').value = petFilter; $('ml-pets-auto').checked = petAutoRefresh; syncSlider('ml-pets-interval', 'ml-pets-iv', petRefreshInterval); renderPetTable(); if (petAutoRefresh) startPetRefresh(); panelPause(); } else { stopPetRefresh(); petsPanel._resetPos?.(); panelResume(); } } $('ml-pets-btn').addEventListener('click', () => { togglePetsPanel(); }); $('ml-pets-close').addEventListener('click', () => togglePetsPanel(false)); $('ml-pets-search').addEventListener('input', e => { petFilter = e.target.value; saveSettings(); renderPetTable(); }); $('ml-pets-auto').addEventListener('change', e => { petAutoRefresh = e.target.checked; saveSettings(); if (petAutoRefresh && petsPanel.classList.contains('open')) startPetRefresh(); else stopPetRefresh(); }); $('ml-pets-interval').addEventListener('input', e => { petRefreshInterval = parseInt(e.target.value); const iv = $('ml-pets-iv'); if (iv) iv.textContent = petRefreshInterval; saveSettings(); if (petAutoRefresh && petsPanel.classList.contains('open')) startPetRefresh(); }); let _snipeTimer = null; let _snipeDropInProgress = false; function isOwnerBaseLocked(ownerId) { if (!ownerId) return false; if (_serverLockedSessions.has(ownerId)) return true; const bm = _getBasesManager(); if (bm?.activeBases) { for (const bd of bm.activeBases) { if (bd.data?.sessionId !== ownerId) continue; return !!(bd.data.lockdownActive || bd.data.lockdownTimeLeft > 0); } } return false; } const _snipedPets = []; const SNIPE_HISTORY_CAP = 200; function recordSnipe(token) { _snipedPets.push({ token: String(token), time: Date.now() }); while (_snipedPets.length > SNIPE_HISTORY_CAP) _snipedPets.shift(); } function getSnipeTime(token) { const t = String(token); for (let i = _snipedPets.length - 1; i >= 0; i--) { if (_snipedPets[i].token === t) return _snipedPets[i].time; } return 0; } function snipeLog(msg) { const log = $('ml-snipe-log'); if (!log) return; const entry = document.createElement('div'); entry.className = 'ml-snipe-entry'; entry.textContent = new Date().toLocaleTimeString() + ' ' + msg; log.prepend(entry); while (log.children.length > 30) log.lastChild.remove(); } function snipeScan() { if (!snipeFilter) { $('ml-snipe-status').textContent = 'No filter set'; $('ml-snipe-types').textContent = ''; return null; } const app = W.pc?.app; const player = getPlayer(); if (!app || !player) { $('ml-snipe-status').textContent = 'Waiting for game...'; return null; } const nm = _getNetworkManager(); const myId = nm?.room?.sessionId || W.pc?.sessionId; const bm = _getBasesManager(); const isStealMode = !!(bm?.activeBases); const pets = getAllPets(); const nameMatches = pets.filter(p => { if (p.ownerId === myId || p.owner === 'Yours') return false; return petMatchesFilter(p, snipeFilter); }); let blocked = 0; const matches = nameMatches.filter(p => { if (isStealMode) { if (p.owner === 'Wild' || !p.ownerId) { blocked++; return false; } if (p.type === 'active') { blocked++; return false; } if (isOwnerBaseLocked(p.ownerId)) { blocked++; return false; } return true; } else { if (p.owner !== 'Wild' && p.ownerId) { blocked++; return false; } return true; } }); const blockedStr = blocked ? ' (' + blocked + ' locked)' : ''; $('ml-snipe-status').textContent = (isStealMode ? '[Steal] ' : '[Waves] ') + matches.length + ' target(s) / ' + nameMatches.length + ' matched' + blockedStr; const typeCounts = {}; for (const m of nameMatches) { const variant = [m.rarity, m.mutation, m.name].filter(Boolean).join(' '); const isLocked = isStealMode && m.ownerId && isOwnerBaseLocked(m.ownerId); if (!typeCounts[variant]) typeCounts[variant] = { total: 0, locked: 0 }; typeCounts[variant].total++; if (isLocked) typeCounts[variant].locked++; } const typesEl = $('ml-snipe-types'); if (typesEl) { const entries = Object.entries(typeCounts).sort((a, b) => b[1].total - a[1].total); typesEl.innerHTML = ''; for (const [k, v] of entries) { const row = document.createElement('div'); row.className = 'ml-snipe-type-row'; let label = k + (v.total > 1 ? ' \u00d7' + v.total : ''); if (v.locked > 0) label += ' \ud83d\udd12' + v.locked; row.textContent = label; typesEl.appendChild(row); } } return { matches, isStealMode, totalPets: pets.length, blocked }; } let _snipeScanTimer = null; function snipeTick() { if (!snipeActive) return; if (_hopInProgress) return; const now = Date.now(); if (now < _snipeCooldown) { $('ml-snipe-status').textContent = 'Cooldown ' + (((_snipeCooldown - now) / 1000) | 0) + 's...'; return; } const app = W.pc?.app; const pt = _getPetTycoon(); const et = _getEscapeTsunami(); const holding = !!(pt?.isHoldingPet || et?.isHoldingPet); if (_snipeWasHolding && !holding) { _snipeCooldown = Date.now() + 10000; console.log('[ml] pet deposited — 10s snipe cooldown'); } _snipeWasHolding = holding; if (holding) { $('ml-snipe-status').textContent = 'Holding a pet \u2014 paused'; return; } const scan = snipeScan(); if (!scan || scan.matches.length === 0) { if (snipeAutoHop && scan && scan.isStealMode && snipeFilter && scan.totalPets > 0 && !scan.blocked) { if (!_snipeHopNoMatchStart) _snipeHopNoMatchStart = Date.now(); const elapsed = ((Date.now() - _snipeHopNoMatchStart) / 1000) | 0; if (elapsed >= 5) { snipeLog('No matches (' + scan.totalPets + ' pets) — hopping...'); $('ml-snipe-status').textContent = 'Hopping server...'; _snipeHopNoMatchStart = 0; performServerHop(); return; } $('ml-snipe-status').textContent = 'No matches (' + scan.totalPets + ' pets loaded)'; } return; } _snipeHopNoMatchStart = 0; const { matches, isStealMode } = scan; const player = getPlayer(); if (!player) return; const pPos = player.getPosition(); for (const m of matches) { m._dist = Math.hypot(m.x - pPos.x, m.y - pPos.y, m.z - pPos.z); m._snipeTime = getSnipeTime(m.token); m._value = Math.max(m.price || 0, m.income || 0); } matches.sort((a, b) => { if (!isStealMode) { if (!a._snipeTime && b._snipeTime) return -1; if (a._snipeTime && !b._snipeTime) return 1; if (a._snipeTime && b._snipeTime) return a._snipeTime - b._snipeTime; } if (isStealMode) { if (b.income !== a.income) return b.income - a.income; } if (b._value !== a._value) return b._value - a._value; return a._dist - b._dist; }); const target = matches[0]; $('ml-snipe-status').textContent = 'Sniping: ' + target.name + '...'; snipeLog('Sniping ' + target.name + ' (' + (target.owner || 'wild') + ') dist=' + Math.round(target._dist)); if (isStealMode) { if (!_lockDataReceived) { $('ml-snipe-status').textContent = 'Waiting for lock data...'; return; } if (target.ownerId && isOwnerBaseLocked(target.ownerId)) { snipeLog(target.name + ': base locked at last second, skipping'); $('ml-snipe-status').textContent = 'Base locked — skipping...'; _snipeCooldown = Date.now() + 500; return; } const nm = _getNetworkManager(); const room = nm?.room; const sid = room?.sessionId; if (!room || !sid) return; const rawSend = room.__mlOrigSend || room.send.bind(room); _ghostSuppressed = true; player.setPosition(target.x, target.y + 0.5, target.z); const posMsg = { x: target.x, y: target.y + 0.5, z: target.z, w: 0 }; rawSend('p', posMsg); recordSnipe(target.token); snipeLog('TP\u2019d to ' + target.name + ' — stealing...'); $('ml-snipe-status').textContent = 'Stealing ' + target.name + '...'; _snipeCooldown = Date.now() + 8000; for (let i = 1; i <= 4; i++) setTimeout(() => rawSend('p', posMsg), i * 80); setTimeout(() => { _ghostSuppressed = false; room.send('stealPet', target.token); console.log('[ml] snipe steal sent:', target.name, target.token); }, 400); } else { const orig = player.getPosition().clone(); const nm = _getNetworkManager(); const room = nm?.room; const sid = room?.sessionId; if (!room || !sid) return; const rawSend = room.__mlOrigSend || room.send.bind(room); _snipeCooldown = Date.now() + 5000; if (featGhostMode) { _wavesGhostPos = { x: target.x, y: target.y + 0.5, z: target.z }; } else { player.setPosition(target.x, target.y + 0.5, target.z); } (async () => { await new Promise(r => setTimeout(r, 150)); app.fire('ModeOverlay:BuyPet', target.token); recordSnipe(target.token); console.log('[ml] snipe grab:', target.name, target.token); const grabbed = await new Promise(resolve => { const timer = setTimeout(() => { unsub(); resolve(false); }, 600); const unsub = room.onMessage('petHeld', msg => { if (msg.holderSessionId !== sid) return; clearTimeout(timer); unsub(); resolve(true); }); }); if (!grabbed) { _wavesGhostPos = null; if (!featGhostMode) player.setPosition(orig.x, orig.y, orig.z); snipeLog(target.name + ': grab timeout'); $('ml-snipe-status').textContent = 'Grab failed. Retrying...'; _snipeCooldown = Date.now() + 500; return; } _wavesGhostPos = null; if (!featGhostMode) player.setPosition(orig.x, orig.y, orig.z); if (snipeAutoDrop) { _snipeDropInProgress = true; const realPos = player.getPosition(); rawSend('p', { x: realPos.x, y: realPos.y, z: realPos.z, w: 0 }); let dropped = false; for (let att = 0; att < 4 && !dropped; att++) { await new Promise(r => setTimeout(r, att === 0 ? 200 : 500)); const et = _getEscapeTsunami(); if (!et?.isHoldingPet) { dropped = true; break; } const dp = new Promise(resolve => { const t = setTimeout(() => { u(); resolve(false); }, 800); const u = room.onMessage('escapeTsunamiPetDropped', msg => { if (msg.holderSessionId !== sid) return; clearTimeout(t); u(); resolve(true); }); }); rawSend('dropPet'); if (att > 0) rawSend('p', { x: realPos.x, y: realPos.y, z: realPos.z, w: 0 }); dropped = await dp; if (!dropped) console.log('[ml] drop attempt', att + 1, 'failed'); } _snipeDropInProgress = false; if (!dropped) console.log('[ml] drop failed after retries — isHolding:', _getEscapeTsunami()?.isHoldingPet); snipeLog('Sniped ' + target.name + (dropped ? ' ✓ dropped' : ' (drop failed!)')); $('ml-snipe-status').textContent = dropped ? 'Dropped ' + target.name : 'Drop failed!'; _snipeCooldown = Date.now() + 300; } else { snipeLog('Sniped ' + target.name + ' ✓ — place on base!'); $('ml-snipe-status').textContent = 'Holding ' + target.name + '! Place on base.'; _snipeCooldown = Date.now() + 1000; } })(); } } let _heldPetCleanup = null; function heldPetCleanupTick() { if (!snipeActive || !snipeAutoDrop || _snipeDropInProgress) return; const et = _getEscapeTsunami(); if (!et?.isHoldingPet) return; const nm = _getNetworkManager(); const room = nm?.room; if (!room) return; const rawSend = room.__mlOrigSend || room.send.bind(room); const pos = getPlayer()?.getPosition(); if (pos) rawSend('p', { x: pos.x, y: pos.y, z: pos.z, w: 0 }); rawSend('dropPet'); console.log('[ml] held-pet cleanup: forced drop'); } function startSnipe() { if (_snipeTimer) return; _snipeTimer = setInterval(snipeTick, 200); if (!_heldPetCleanup) _heldPetCleanup = setInterval(heldPetCleanupTick, 3000); snipeLog('Sniping started: ' + snipeFilter); } function stopSnipe() { if (_snipeTimer) { clearInterval(_snipeTimer); _snipeTimer = null; } if (_heldPetCleanup) { clearInterval(_heldPetCleanup); _heldPetCleanup = null; } } function toggleSnipePanel(forceOpen) { const wasOpen = snipePanel.classList.contains('open'); if (wasOpen && forceOpen === undefined && document.pointerLockElement) { panelPause(); return; } const open = forceOpen !== undefined ? forceOpen : !wasOpen; snipePanel.classList.toggle('open', open); if (open) { if (document.pointerLockElement) panelPause(); $('ml-snipe-search').value = snipeFilter; $('ml-snipe-drop').checked = snipeAutoDrop; $('ml-snipe-hop').checked = snipeAutoHop; $('ml-snipe-toggle').textContent = snipeActive ? 'Stop Sniping' : 'Start Sniping'; $('ml-snipe-toggle').classList.toggle('active', snipeActive); snipeScan(); if (!_snipeScanTimer && !_snipeTimer) _snipeScanTimer = setInterval(snipeScan, 2000); } else if (wasOpen) { if (_snipeScanTimer) { clearInterval(_snipeScanTimer); _snipeScanTimer = null; } snipePanel._resetPos?.(); panelResume(); } } document.addEventListener('mousedown', e => { if (!snipePanel.classList.contains('open')) return; if (document.pointerLockElement) return; if (snipePanel.contains(e.target)) return; const app = W.pc?.app; const canvas = app?.graphicsDevice?.canvas; if (canvas) origRequestPointerLock.call(canvas, {unadjustedMovement: true}); }); $('ml-snipe-btn').addEventListener('click', () => { toggleSnipePanel(); }); $('ml-snipe-close').addEventListener('click', () => toggleSnipePanel(false)); $('ml-snipe-search').addEventListener('input', e => { snipeFilter = e.target.value; saveSettings(); }); $('ml-snipe-drop').addEventListener('change', e => { snipeAutoDrop = e.target.checked; saveSettings(); }); $('ml-snipe-hop').addEventListener('change', e => { snipeAutoHop = e.target.checked; if (snipeAutoHop) sessionStorage.setItem('ml_snipeAutoHop', '1'); else sessionStorage.removeItem('ml_snipeAutoHop'); _snipeHopNoMatchStart = 0; }); $('ml-snipe-toggle').addEventListener('click', () => { snipeActive = !snipeActive; saveSettings(); $('ml-snipe-toggle').textContent = snipeActive ? 'Stop Sniping' : 'Start Sniping'; $('ml-snipe-toggle').classList.toggle('active', snipeActive); if (snipeActive) startSnipe(); else { stopSnipe(); $('ml-snipe-status').textContent = 'Idle'; } }); if (snipeActive) { $('ml-snipe-toggle').textContent = 'Stop Sniping'; $('ml-snipe-toggle').classList.add('active'); startSnipe(); } function toggleCuddlePanel(forceOpen) { const wasOpen = plist.classList.contains('open'); const open = forceOpen !== undefined ? forceOpen : !wasOpen; plist.classList.toggle('open', open); if (open) { refreshPlayerList(); panelPause(); if (!wasOpen && autoRefresh) startRefreshTimer(); } else if (wasOpen) { stopRefreshTimer(); plist._resetPos?.(); panelResume(); } } const origRequestPointerLock = Element.prototype.requestPointerLock; Element.prototype.requestPointerLock = function() { if (anyPanelOpen()) { if (W.pc?.isGamePaused) { for (const id of ['ml-plist', 'ml-settings', 'ml-pets', 'ml-dialog', 'ml-slots-pop', 'ml-snipe']) { $(id)?.classList.remove('open'); } _savedPointerLock = false; } else { return; } } return origRequestPointerLock.apply(this, arguments); }; const origRequestFullscreen = Element.prototype.requestFullscreen; Element.prototype.requestFullscreen = function(opts) { return origRequestFullscreen.call(document.body, opts); }; document.addEventListener('pointerlockchange', e => { const wasIntentional = _intentionalPointerExit; _intentionalPointerExit = false; if (wasIntentional && !document.pointerLockElement) { e.stopImmediatePropagation(); return; } if (document.pointerLockElement) { const app = W.pc?.app; if (app) app.fire('GameManager:GameResumed'); } }, true); document.addEventListener('visibilitychange', () => { if (document.hidden) _intentionalPointerExit = false; }); let refreshCountdown = refreshInterval; let refreshTimer = null; function startRefreshTimer() { stopRefreshTimer(); refreshCountdown = refreshInterval; const timerEl = $('ml-plist-timer'); if (timerEl) timerEl.textContent = refreshCountdown + 's'; refreshTimer = setInterval(() => { refreshCountdown--; if (timerEl) timerEl.textContent = refreshCountdown + 's'; if (refreshCountdown <= 0) { refreshPlayerList(); refreshCountdown = refreshInterval; if (timerEl) timerEl.textContent = refreshCountdown + 's'; } }, 1000); } function stopRefreshTimer() { if (refreshTimer) { clearInterval(refreshTimer); refreshTimer = null; } } $('ml-invis').addEventListener('click', () => { featInvisible = !featInvisible; _toggleInvisible(featInvisible); _updateInvisEffect(featInvisible); const el = $('ml-f-invisible'); if (el) el.classList.toggle('on', featInvisible); saveSettings(); }); $('ml-tp').addEventListener('click', () => { toggleCuddlePanel(); }); $('ml-plist-refresh').addEventListener('click', () => { refreshPlayerList(); if (autoRefresh && plist.classList.contains('open')) startRefreshTimer(); }); $('ml-plist-close').addEventListener('click', () => toggleCuddlePanel(false)); function toggleSettings(forceOpen) { const open = forceOpen !== undefined ? forceOpen : !settings.classList.contains('open'); settings.classList.toggle('open', open); if (open) { panelPause(); refreshUsernameUI(); } else if (!open) { kbListeningRow = null; settings._resetPos?.(); panelResume(); } } $('ml-cfg').addEventListener('click', () => { toggleSettings(); }); $('ml-settings-close').addEventListener('click', () => toggleSettings(false)); document.querySelectorAll('#ml-tabs .ml-tab').forEach(tab => { tab.addEventListener('click', () => { const t = tab.dataset.tab; document.querySelectorAll('#ml-tabs .ml-tab').forEach(x => x.classList.toggle('active', x.dataset.tab === t)); document.querySelectorAll('#ml-settings-body .ml-tab-content').forEach(x => x.classList.toggle('active', x.dataset.tab === t)); if (t === 'keys') buildKeybindsHTML(); else { kbListeningRow = null; $('ml-keybinds-body').querySelectorAll('.ml-krow.listening').forEach(r => r.classList.remove('listening')); } }); }); const DEFAULTS = { ACCEL: 6, SPEED_CAP: 100, SPEED_DEFAULT: 7, petRefreshInterval: 1, petFilter: 'wild', petSortCol: 'price', petSortDir: -1 }; $('ml-settings-reset').addEventListener('click', () => { ACCEL = DEFAULTS.ACCEL; SPEED_CAP = DEFAULTS.SPEED_CAP; SPEED_DEFAULT = DEFAULTS.SPEED_DEFAULT; petRefreshInterval = DEFAULTS.petRefreshInterval; petFilter = DEFAULTS.petFilter; petSortCol = DEFAULTS.petSortCol; petSortDir = DEFAULTS.petSortDir; accelEnabled = true; featFly = true; featSprint = true; featWaypoints = true; featCuddle = true; featCuddleFollow = true; featPets = true; featAutoLock = true; featAntiKnockback = true; featNoclip = false; featFreeMoney = true; featAutoCollect = true; featInvincible = true; featGhostMode = true; featFreeStars = true; autoCollectInterval = 30; Object.assign(KEYBINDS, DEFAULT_KEYBINDS); syncSettingsUI(); buildKeybindsHTML(); updateHUDBadgeLabels(); console.log('[settings] reset'); saveSettings(); }); const sliderMap = [ { id: 'ml-s-cap', valId: 'ml-sv-cap', apply: v => { SPEED_CAP = v; } }, { id: 'ml-s-accel', valId: 'ml-sv-accel', apply: v => { ACCEL = v; } }, { id: 'ml-s-base', valId: 'ml-sv-base', apply: v => { SPEED_DEFAULT = v; } }, { id: 'ml-s-acinterval', valId: 'ml-sv-acinterval', uom: 's', apply: v => { autoCollectInterval = v; } }, ]; sliderMap.forEach(s => { const el = $(s.id); const valEl = $(s.valId); if (!el) return; el.addEventListener('input', () => { const v = parseInt(el.value); if (valEl) valEl.textContent = s.uom ? v + s.uom : v; s.apply(v); saveSettings(); }); }); const accelToggle = $('ml-s-accel-en'); if (accelToggle) { accelToggle.addEventListener('click', () => { accelEnabled = !accelEnabled; accelToggle.classList.toggle('on', accelEnabled); saveSettings(); }); } const featToggles = [ { id: 'ml-f-fly', get: () => featFly, set: v => { featFly = v; if (!v) { const p = getPlayer(); const k = getKcc(p); if (k && flyActive) flyOff(k); } } }, { id: 'ml-f-sprint', get: () => featSprint, set: v => { featSprint = v; if (!v) sprinting = false; } }, { id: 'ml-f-waypoints', get: () => featWaypoints, set: v => { featWaypoints = v; } }, { id: 'ml-f-cuddle', get: () => featCuddle, set: v => { featCuddle = v; if (!v) toggleCuddlePanel(false); } }, { id: 'ml-f-cuddle-follow', get: () => featCuddleFollow, set: v => { featCuddleFollow = v; if (!v) { cuddling = false; cuddleTarget = null; } } }, { id: 'ml-f-pets', get: () => featPets, set: v => { featPets = v; if (!v) togglePetsPanel(false); } }, { id: 'ml-f-autolock', get: () => featAutoLock, set: v => { featAutoLock = v; } }, { id: 'ml-f-antiknockback', get: () => featAntiKnockback, set: v => { featAntiKnockback = v; if (!v) antiKnockbackReady = false; } }, { id: 'ml-f-noclip', get: () => featNoclip, set: v => { featNoclip = v; } }, { id: 'ml-f-freemoney', get: () => featFreeMoney, set: v => { featFreeMoney = v; if (v && !freeMoneyDone) autoFarmFreeMoney(); } }, { id: 'ml-f-autocollect', get: () => featAutoCollect, set: v => { featAutoCollect = v; } }, { id: 'ml-f-invincible', get: () => featInvincible, set: v => { featInvincible = v; } }, { id: 'ml-f-ghostmode', get: () => featGhostMode, set: v => { featGhostMode = v; if (!v) { _ghostActive = true; updateGhostEffect(); } } }, { id: 'ml-f-freestars', get: () => featFreeStars, set: v => { featFreeStars = v; if (v) _freeStarsStart(); else _freeStarsStop(); } }, { id: 'ml-f-autoattack', get: () => featAutoAttack, set: v => { featAutoAttack = v; } }, { id: 'ml-f-autofountain', get: () => featAutoFountain, set: v => { featAutoFountain = v; if (v) _fountainStart(); else _fountainStop(); } }, { id: 'ml-f-invisible', get: () => featInvisible, set: v => { featInvisible = v; _toggleInvisible(v); _updateInvisEffect(v); } }, { id: 'ml-f-protips', get: () => featProTips, set: v => { featProTips = v; } }, ]; featToggles.forEach(ft => { const el = $(ft.id); if (!el) return; el.addEventListener('click', () => { const nv = !ft.get(); ft.set(nv); el.classList.toggle('on', nv); saveSettings(); console.log(`[feat] ${ft.id.replace('ml-f-','')} = ${nv}`); }); }); function refreshUsernameUI() { const statusEl = $('ml-uname-status'); const btnEl = $('ml-uname-btn'); const inputEl = $('ml-uname-input'); if (!statusEl) return; const nm = _getNetworkManager(); const me = nm?.room?.state?.players?.get?.(nm?.room?.sessionId); const apiMgr = W.pc?.app?.root?.findByName('APIManager')?.script?.apimanager; const canChange = !!apiMgr?.accountData?.canChangeName; statusEl.textContent = me?.username ? (canChange ? me.username + ' (1 free change)' : me.username + ' (used)') : '…'; statusEl.style.color = canChange ? 'rgba(140,230,140,.7)' : 'rgba(255,150,150,.6)'; if (btnEl) btnEl.disabled = !canChange; if (btnEl) btnEl.style.opacity = canChange ? '1' : '.4'; if (inputEl) inputEl.disabled = !canChange; } $('ml-uname-btn')?.addEventListener('click', () => { const input = $('ml-uname-input'); const name = input?.value?.trim(); if (!name) return; if (name.length < 3 || name.length > 12) { $('ml-uname-status').textContent = 'Must be 3-12 characters'; $('ml-uname-status').style.color = 'rgba(255,150,150,.8)'; return; } const token = localStorage.getItem('access_token_v0.01'); if (!token) { $('ml-uname-status').textContent = 'Not logged in'; return; } const btn = $('ml-uname-btn'); btn.disabled = true; btn.textContent = '…'; fetch('https://api.meeland.io/v1/users/changeName', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ name }) }).then(r => { if (!r.ok) throw new Error(r.status === 400 || r.status === 403 ? 'Change unavailable' : 'Error ' + r.status); return r.text().then(() => null); }).then(() => { console.log('[ml] username changed to: ' + name); const app = W.pc?.app; if (app) app.fire('NetworkManager:Send', 'refreshUsername'); input.value = ''; $('ml-uname-status').textContent = name + ' ✓'; $('ml-uname-status').style.color = 'rgba(140,230,140,.8)'; btn.textContent = 'Change'; btn.disabled = true; btn.style.opacity = '.4'; }).catch(e => { console.error('[ml] username change failed:', e.message); $('ml-uname-status').textContent = e.message; $('ml-uname-status').style.color = 'rgba(255,150,150,.8)'; btn.textContent = 'Change'; btn.disabled = false; }); }); $('ml-keybinds-body').addEventListener('click', e => { const row = e.target.closest('.ml-krow'); if (!row) return; $('ml-keybinds-body').querySelectorAll('.ml-krow.listening').forEach(r => r.classList.remove('listening')); if (kbListeningRow === row) { kbListeningRow = null; return; } row.classList.add('listening'); row.querySelector('.ml-krow-key').textContent = '...'; kbListeningRow = row; }); window.addEventListener('keydown', e => { if (!kbListeningRow) return; e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); const action = kbListeningRow.dataset.action; if (!action || !(action in KEYBINDS)) return; if (e.code === 'Escape') { kbListeningRow.classList.remove('listening'); kbListeningRow.querySelector('.ml-krow-key').textContent = keyCodeLabel(KEYBINDS[action]); kbListeningRow = null; return; } KEYBINDS[action] = e.code; kbListeningRow.querySelector('.ml-krow-key').textContent = keyCodeLabel(e.code); kbListeningRow.classList.remove('listening'); kbListeningRow = null; saveSettings(); updateHUDBadgeLabels(); console.log('[keybind] ' + action + ' → ' + e.code); }, true); function updateHUDBadgeLabels() { const map = { 'ml-fly': ['FLY', 'fly'], 'ml-spr': ['SPR', null], 'ml-home': ['SETHOME', 'setHome'], 'ml-go': ['HOME', 'home'], 'ml-back': ['BACK', 'back'], 'ml-tp': ['CUDDLE', 'cuddle'], 'ml-pets-btn': ['PETS', 'pets'], 'ml-snipe-btn': ['SNIPE', 'snipe'], 'ml-invis': ['INVIS', 'invisible'], 'ml-cfg': ['CFG', 'settings'], }; const nativeKeyMap = { 'ml-fly': 'fly', 'ml-spr': 'spr', 'ml-home': 'home', 'ml-go': 'go', 'ml-back': 'back', 'ml-invis': 'invis', 'ml-tp': 'tp', 'ml-pets-btn': 'petsBtn', 'ml-snipe-btn': 'snipeBtn', 'ml-cfg': 'cfg' }; for (const [id, [label, action]] of Object.entries(map)) { if (_nativeHud) { const k = nativeKeyMap[id]; const kl = k && _nativeHud[k]?._native?.keyLbl; if (kl?.element) { kl.element.text = !action ? 'SH' : keyCodeLabel(KEYBINDS[action]); } } } } updateHUDBadgeLabels(); function toggleHelp(forceOpen) { const open = forceOpen !== undefined ? forceOpen : !d.classList.contains('open'); d.classList.toggle('open', open); if (open) { panelPause(); } else { d.querySelector('#ml-inner')._resetPos?.(); panelResume(); } } $('ml-help').addEventListener('click', () => { toggleHelp(); }); $('ml-close').addEventListener('click', () => toggleHelp(false)); d.addEventListener('click', e => { if (e.target === d) toggleHelp(false); }); d.addEventListener('wheel', e => { e.stopPropagation(); e.preventDefault(); d.scrollTop += e.deltaY; }, { passive: false }); /* ── mobile touch-scroll fix ────────────────────────────── */ function enableTouchScroll(el) { el.addEventListener('touchstart', e => e.stopPropagation(), { passive: true }); el.addEventListener('touchmove', e => e.stopPropagation(), { passive: true }); el.addEventListener('touchend', e => e.stopPropagation(), { passive: true }); } [d, $('ml-plist-body'), $('ml-settings-body'), $('ml-pets-body'), $('ml-slots-pop-body'), $('ml-snipe-types'), $('ml-snipe-log')].forEach(el => { if (el) enableTouchScroll(el); }); document.addEventListener('click', e => { if (plist.classList.contains('open') && !plist.contains(e.target) && e.target.id !== 'ml-tp') { toggleCuddlePanel(false); } if (settings.classList.contains('open') && !settings.contains(e.target) && e.target.id !== 'ml-cfg') { toggleSettings(false); } if (petsPanel.classList.contains('open') && !petsPanel.contains(e.target) && e.target.id !== 'ml-pets-btn') { togglePetsPanel(false); } if (slotsPop.classList.contains('open') && !slotsPop.contains(e.target) && e.target.id !== 'ml-slots') { toggleSlots(false); } }); } let _nativeHud = null; function createNativeHUD() { const app = W.pc?.app; const pc = W.pc; if (!app || !pc) return null; const roundedTex = app.assets.get(236692532); const fontAsset = app.assets.get(236690804); const gpm = app.root.findByName('GamePlayMenu'); if (!gpm || !roundedTex || !fontAsset) return null; const old = app.root.findByName('ML-HUD'); if (old) old.destroy(); const btnSize = 50, spacing = 56, rowGap = 68; const COL_NORM = [0.071, 0.071, 0.071]; const COL_ON = [0, 0.5, 1]; const COL_FRESH = [0, 0.66, 1]; const COL_DISABLED = [0.071, 0.071, 0.071]; const topDefs = [ ['fly', 'FLY', 'SPC', 'ml-fly'], ['spr', 'SPR', 'SH', 'ml-spr'], ['home', 'SET', 'Q', 'ml-home'], ['go', 'GO', '~', 'ml-go'], ['back', 'BCK', 'Z', 'ml-back'], ['slots','0/10', 'I', 'ml-slots'], ['lock', 'LCK', '', 'ml-lock'], ]; const botDefs = [ ['invis', 'INV', 'V', 'ml-invis'], ['tp', 'CUD', 'J', 'ml-tp'], ['petsBtn', 'PET', 'K', 'ml-pets-btn'], ['snipeBtn','SNP', 'U', 'ml-snipe-btn'], ['cfg', 'CFG', 'M', 'ml-cfg'], ['help', '?', '/', 'ml-help'], ]; const mlGroup = new pc.Entity('ML-HUD'); mlGroup.addComponent('element', { type: 'group', anchor: [0,1,0,1], pivot: [0,1], width: 440, height: 200 }); mlGroup.setLocalPosition(10, -70, 0); mlGroup.enabled = false; function makeBtn(id, label, keyText, idx, yBase) { const btn = new pc.Entity('ML-' + id); btn.addComponent('element', { type: 'group', anchor: [0,1,0,1], pivot: [0,1], width: btnSize + 6, height: btnSize + 30 }); btn.setLocalPosition(idx * spacing, -yBase, 0); const bg = new pc.Entity('BG'); bg.addComponent('element', { type: 'image', anchor: [.5,.5,.5,.5], pivot: [.5,.5], width: btnSize, height: btnSize, color: new pc.Color(COL_NORM[0], COL_NORM[1], COL_NORM[2]), opacity: 1, textureAsset: roundedTex.id, useInput: true }); btn.addChild(bg); const fs = label.length > 3 ? 15 : (label.length > 2 ? 20 : label.length > 1 ? 24 : 30); const lbl = new pc.Entity('Label'); lbl.addComponent('element', { type: 'text', anchor: [.5,.5,.5,.5], pivot: [.5,.5], text: label, fontSize: fs, fontAsset: fontAsset.id, color: new pc.Color(1, 1, 1), outlineThickness: .3, outlineColor: new pc.Color(0, 0, 0), autoWidth: true, autoHeight: true }); bg.addChild(lbl); if (keyText) { const isLong = keyText.length > 2, isMed = keyText.length === 2; if (isLong || isMed) { const hg = isLong ? 6 : 3, rw = hg * 2 + 0.5; const dk = new pc.Entity('DesktopKey'); dk.addComponent('element', { type:'group', anchor:[.5,.5,.5,.5], pivot:[.5,.5], width:25, height:25 }); dk.setLocalPosition(17.5, -17.5, 0); bg.addChild(dk); [[-hg,25,25],[hg,25,25],[0,rw,25]].forEach(([x,w,h],j)=>{ const e = new pc.Entity('Image'); const c = { type:'image', anchor:[.5,.5,.5,.5], pivot:[.5,.5], width:w, height:h, color:new pc.Color(.388,.388,.388), opacity:1 }; if (j < 2) c.textureAsset = roundedTex.id; e.addComponent('element', c); if (x) e.setLocalPosition(x,0,0); dk.addChild(e); }); [[-hg,20,20],[hg,20,20],[0,rw,20]].forEach(([x,w,h],j)=>{ const e = new pc.Entity('Group'); const c = { type:'image', anchor:[.5,.5,.5,.5], pivot:[.5,.5], width:w, height:h, color:new pc.Color(1,1,1), opacity:1 }; if (j < 2) c.textureAsset = roundedTex.id; e.addComponent('element', c); if (x) e.setLocalPosition(x,0,0); dk.addChild(e); }); const kl = new pc.Entity('Text'); kl.addComponent('element', { type:'text', anchor:[.5,.5,.5,.5], pivot:[.5,.5], text:keyText, fontSize:15, fontAsset:fontAsset.id, color:new pc.Color(0,0,0), autoWidth:true, autoHeight:true }); kl.setLocalPosition(0, -0.3, 0); dk.addChild(kl); } else { const dk = new pc.Entity('DesktopKey'); dk.addComponent('element', { type:'image', anchor:[.5,.5,.5,.5], pivot:[.5,.5], width:25, height:25, color:new pc.Color(.388,.388,.388), opacity:1, textureAsset:roundedTex.id }); dk.setLocalPosition(17.5, -17.5, 0); bg.addChild(dk); const inner = new pc.Entity('Group'); inner.addComponent('element', { type:'image', anchor:[.5,.5,.5,.5], pivot:[.5,.5], width:20, height:20, color:new pc.Color(1,1,1), opacity:1, textureAsset:roundedTex.id }); dk.addChild(inner); const kl = new pc.Entity('Text'); kl.addComponent('element', { type:'text', anchor:[.5,.5,.5,.5], pivot:[.5,.5], text:keyText, fontSize:15, fontAsset:fontAsset.id, color:new pc.Color(0,0,0), autoWidth:true, autoHeight:true }); kl.setLocalPosition(0.6, 0, 0); dk.addChild(kl); } } mlGroup.addChild(btn); return { bg, lbl, btn, keyLbl: keyText ? btn.findByName('Text') : null }; } function makeProxy(parts, htmlId) { const st = {}; const setCol = (r, g, b) => { if (parts.bg.element) { parts.bg.element.color = new pc.Color(r, g, b); } }; const update = () => { if (st.disabled) { setCol(COL_DISABLED[0], COL_DISABLED[1], COL_DISABLED[2]); parts.bg.element.opacity = .45; parts.lbl.element.color = new pc.Color(1, .24, .24); } else if (st.fresh) { setCol(COL_FRESH[0], COL_FRESH[1], COL_FRESH[2]); parts.bg.element.opacity = 1; parts.lbl.element.color = new pc.Color(1, 1, 1); } else if (st.on) { setCol(COL_ON[0], COL_ON[1], COL_ON[2]); parts.bg.element.opacity = 1; parts.lbl.element.color = new pc.Color(1, 1, 1); } else { setCol(COL_NORM[0], COL_NORM[1], COL_NORM[2]); parts.bg.element.opacity = 1; parts.lbl.element.color = new pc.Color(1, 1, 1); } }; return { _native: parts, classList: { toggle(cls, force) { st[cls] = force; update(); }, add(cls) { st[cls] = true; update(); }, remove(cls) { delete st[cls]; update(); }, contains(cls) { return !!st[cls]; } }, set textContent(t) { const short = t.replace(/^SLOTS\s*/, '').replace(/^\u{1F512}\s*/u, '').replace(/^\u{1F513}\s*/u, ''); parts.lbl.element.text = short.length > 5 ? short.substring(0, 5) : short; }, get textContent() { return parts.lbl.element.text; }, addEventListener() {}, click() { const el = document.getElementById(htmlId); if (el) el.click(); } }; } const result = {}; topDefs.forEach(([key, label, keyText, htmlId], i) => { result[key] = makeProxy(makeBtn(key, label, keyText, i, 0), htmlId); }); botDefs.forEach(([key, label, keyText, htmlId], i) => { result[key] = makeProxy(makeBtn(key, label, keyText, i, rowGap), htmlId); }); const prevOverlay = $('ml-click-overlay'); if (prevOverlay) prevOverlay.remove(); const clickOverlay = document.createElement('div'); clickOverlay.id = 'ml-click-overlay'; clickOverlay.style.cssText = 'position:fixed;inset:0;z-index:10;pointer-events:none'; document.body.appendChild(clickOverlay); const clickDivs = {}; for (const key of Object.keys(result)) { const div = document.createElement('div'); div.style.cssText = 'position:absolute;pointer-events:auto;cursor:pointer'; div.dataset.key = key; clickOverlay.appendChild(div); clickDivs[key] = div; } ['mousedown','mouseup','pointerdown','pointerup'].forEach(evt => { clickOverlay.addEventListener(evt, e => { if (e.target.dataset?.key) e.stopPropagation(); }); }); clickOverlay.addEventListener('touchstart', e => { if (e.target.dataset?.key) { e.stopPropagation(); e.preventDefault(); } }); clickOverlay.addEventListener('touchend', e => { const key = e.target.dataset?.key; if (key && result[key]) { e.stopPropagation(); e.preventDefault(); console.log('[ml] btn-touch ' + key); result[key].click(); } }); clickOverlay.addEventListener('click', e => { const key = e.target.dataset?.key; if (!key || !result[key]) return; console.log('[ml] btn-click ' + key); e.stopPropagation(); e.preventDefault(); result[key].click(); }); const btnLayout = {}; topDefs.forEach(([key], i) => { btnLayout[key] = { idx: i, yBase: 0 }; }); botDefs.forEach(([key], i) => { btnLayout[key] = { idx: i, yBase: rowGap }; }); let _syncDiag = false; let _syncLast = 0; function syncOverlay() { requestAnimationFrame(syncOverlay); const now = performance.now(); if (now - _syncLast < 500) return; _syncLast = now; const canvas = app.graphicsDevice.canvas; const rect = canvas.getBoundingClientRect(); const cw = rect.width, ch = rect.height; const scr = mlGroup.parent?.screen; const refW = scr?.referenceResolution?.x || 1280; const refH = scr?.referenceResolution?.y || 720; const sx = cw / refW, sy = ch / refH; const blend = scr?.scaleBlend ?? 0.5; const scale = Math.pow(sx, 1 - blend) * Math.pow(sy, blend); const groupY = Math.abs(mlGroup.localPosition.y); const groupX = mlGroup.localPosition.x; const visible = mlGroup.enabled; for (const key of Object.keys(result)) { const lay = btnLayout[key]; if (!lay) continue; const bgLeft = groupX + lay.idx * spacing + 3; const bgTop = groupY + lay.yBase + 15; const div = clickDivs[key]; div.style.left = (rect.left + bgLeft * scale) + 'px'; div.style.top = (rect.top + bgTop * scale) + 'px'; div.style.width = (btnSize * scale) + 'px'; div.style.height = (btnSize * scale) + 'px'; div.style.display = visible ? 'block' : 'none'; } if (!_syncDiag && visible) { _syncDiag = true; console.log('[ml] overlay-sync scale=' + scale.toFixed(3) + ' groupXY=' + groupX + ',' + groupY + ' canvas=' + cw.toFixed(0) + 'x' + ch.toFixed(0) + ' buttons=' + Object.keys(btnLayout).join(',')); } } const overlay = gpm.parent; overlay.addChild(mlGroup); syncOverlay(); const chatEntity = gpm.findByName('Chat'); if (chatEntity) { const chatY = -(Math.abs(mlGroup.localPosition.y) + rowGap + btnSize + 12); chatEntity.setLocalPosition(chatEntity.localPosition.x, chatY, 0); console.log('[ml] chat repositioned to y=' + chatY); } function setPauseLayout() { mlGroup.setLocalPosition(10, -115, 0); } function setGameplayLayout() { mlGroup.setLocalPosition(10, -70, 0); } const pauseEntity = overlay.findByName('Pause'); if (pauseEntity) { const origDesc = Object.getOwnPropertyDescriptor(pc.GraphNode.prototype, 'enabled'); if (origDesc?.set) { Object.defineProperty(pauseEntity, 'enabled', { get() { return origDesc.get.call(this); }, set(v) { origDesc.set.call(this, v); if (v) setPauseLayout(); else setGameplayLayout(); }, configurable: true }); } } const loadingEntity = overlay.findByName('LoadingScreen'); if (loadingEntity) { const origDesc = Object.getOwnPropertyDescriptor(pc.GraphNode.prototype, 'enabled'); if (origDesc?.set) { Object.defineProperty(loadingEntity, 'enabled', { get() { return origDesc.get.call(this); }, set(v) { origDesc.set.call(this, v); mlGroup.enabled = !v; const mf = $('ml-mobile-fly'); if (mf) mf.style.display = v ? 'none' : 'flex'; }, configurable: true }); mlGroup.enabled = !loadingEntity.enabled; const mfInit = $('ml-mobile-fly'); if (mfInit) mfInit.style.display = loadingEntity.enabled ? 'none' : 'flex'; } else { mlGroup.enabled = true; const mfOrig = $('ml-mobile-fly'); if (mfOrig) mfOrig.style.display = 'flex'; } } else { mlGroup.enabled = true; const mfFallback = $('ml-mobile-fly'); if (mfFallback) mfFallback.style.display = 'flex'; } console.log('[ml] native PlayCanvas HUD created'); return result; } function getApiManager() { const root = W.pc?.app?.root; const scripts = root?.findComponents('script') || []; for (const s of scripts) { for (const name of Object.keys(s)) { const inst = s[name]; if (inst?.freeCurrency && inst?.balance !== undefined) return inst; } } return null; } let freeMoneyDone = false; async function autoFarmFreeMoney() { if (freeMoneyDone || !featFreeMoney) return; const api = getApiManager(); if (!api) return; const nm = W.pc?.app?.root?.findByName('NetworkManager')?.script?.networkManager; if (!nm?.room?.sessionId) return; freeMoneyDone = true; const remaining = (api.freeCurrencyAdLimit || 10) - (api.freeCurrencyAdCounter || 0); if (remaining <= 0) { console.log('[ml] free money: daily limit already reached'); return; } let total = 0, calls = 0; for (let i = 0; i < remaining; i++) { const before = api.balance; api.freeCurrency(); await new Promise(r => setTimeout(r, 1500)); const gained = api.balance - before; if (gained <= 0) break; total += gained; calls++; } console.log('[ml] free money: +' + total + ' coins (' + calls + ' calls, balance: ' + api.balance + ')'); } function _freeStarsStart() { _freeStarsStop(); if (!featFreeStars) return; _freeStarsTick(); } function _freeStarsStop() { clearTimeout(_freeStarsTimer); _freeStarsTimer = null; } function _freeStarsTick() { _freeStarsStop(); if (!featFreeStars) return; const nm = _getNetworkManager(); if (!nm?.room || nm.room.name !== 'escapeTsunami') { _freeStarsTimer = setTimeout(_freeStarsTick, 5000); return; } const app = W.pc?.app; if (!app) { _freeStarsTimer = setTimeout(_freeStarsTick, 5000); return; } app.fire('NetworkManager:Send', 'getFreeStars'); _freeStarsTimer = setTimeout(_freeStarsTick, 60000); } let _lastFountainSend = 0; function _fountainStart() { if (!featAutoFountain) return; _fountainSend(); } function _fountainStop() { clearTimeout(_fountainTimer); _fountainTimer = null; } function _fountainSend() { const nm = _getNetworkManager(); const room = nm?.room; if (!room?.connection?.isOpen) return; if (room.name !== 'PetTycoon' && room.name !== 'EscapeTsunami') return; _lastFountainSend = Date.now(); room.send('unlockDecoration', 'MagicFountain'); console.log('[ml] fountain: 1.5× profit boost sent'); } function _fountainHookExpiry(room) { if (room.__mlFountainHooked) return; room.__mlFountainHooked = true; room.onMessage('decorationDisabled', msg => { if (!featAutoFountain) return; if (msg?.sessionId !== room.sessionId) return; if (msg?.decorationName !== 'MagicFountain') return; _fountainTimer = setTimeout(() => { _fountainTimer = null; _fountainSend(); }, 1000); console.log('[ml] fountain expired — re-sending in 1s'); }); } let lastAutoCollect = 0; let _mlBatchCollecting = false; let _mlBatchTotal = 0; let _mlBatchCount = 0; let _mlBatchTimer = null; let _mlCachedBalance = null; function findPetOverlay() { const app = W.pc?.app; if (!app) return null; let overlay = null; app.root.find(e => { if (!e.script) return false; for (const k of Object.keys(e.script)) { const s = e.script[k]; if (s?.coinContainer && s?.onCoinAnimation) { overlay = s; return true; } } return false; }); return overlay; } function flushBatch() { if (!_mlBatchCollecting) return; _mlBatchCollecting = false; clearTimeout(_mlBatchTimer); if (_mlBatchTotal !== 0) { console.log('[ml] auto-collect: batched ' + _mlBatchCount + ' notifications → +$' + _mlBatchTotal); const overlay = findPetOverlay(); const app = W.pc?.app; if (overlay) { for (let i = 0; i < 3; i++) { setTimeout(() => overlay.onCoinAnimation(5), i * 200); } } if (_mlCachedBalance !== null && app?._mlOrigFire) { const bal = _mlCachedBalance; _mlCachedBalance = null; setTimeout(() => { app._mlOrigFire.call(app, 'ModeOverlay:Balance', bal); }, 1500); } } else if (_mlCachedBalance !== null) { const app = W.pc?.app; if (app?._mlOrigFire) { app._mlOrigFire.call(app, 'ModeOverlay:Balance', _mlCachedBalance); } _mlCachedBalance = null; } _mlBatchTotal = 0; _mlBatchCount = 0; } function autoCollectPetEarnings() { if (!featAutoCollect) return; const now = Date.now(); if (now - lastAutoCollect < autoCollectInterval * 1000) return; lastAutoCollect = now; const app = W.pc?.app; if (!app) return; const root = app.root; if (!app._mlNotifBatched) { app._mlNotifBatched = true; app._mlOrigFire = app.fire; } let pm = null; const pmEntity = root.findByName('PetsManager'); if (pmEntity?.script) { for (const k of Object.keys(pmEntity.script)) { const s = pmEntity.script[k]; if (s?.basePets) { pm = s; break; } } } if (!pm) { root.find(e => { if (!e.script) return false; for (const k of Object.keys(e.script)) { const s = e.script[k]; if (s?.basePets) { pm = s; return true; } } return false; }); } if (!pm?.basePets || pm.basePets.size === 0) return; const nm = root.findByName('NetworkManager')?.script?.networkManager; if (!nm?.room?.sessionId) return; const myId = nm.room.sessionId; _mlBatchCollecting = true; _mlBatchTotal = 0; _mlBatchCount = 0; clearTimeout(_mlBatchTimer); let claimed = 0; pm.basePets.forEach((pet, token) => { if (String(pet.owner) === String(myId)) { app.fire('NetworkManager:Send', 'claimPetBalance', token); claimed++; } }); if (claimed > 0) { console.log('[ml] auto-collect: claimed ' + claimed + ' pets'); _mlBatchTimer = setTimeout(flushBatch, 5000); } else { _mlBatchCollecting = false; } } const petSpawnData = new Map(); const PET_SPAWN_CAP = 2000; function hookPetSpawn() { const app = W.pc?.app; if (!app) return; if (app._mlPetSpawnHooked) return; app._mlPetSpawnHooked = true; const onPetsSpawn = data => { const items = Array.isArray(data) ? data : (data && typeof data === 'object' ? Object.values(data) : []); if (!items.length) return; if (petSpawnData.size > PET_SPAWN_CAP) { const excess = petSpawnData.size - PET_SPAWN_CAP + items.length; const it = petSpawnData.keys(); for (let i = 0; i < excess; i++) petSpawnData.delete(it.next().value); } for (const p of items) { if (!p.token) continue; petSpawnData.set(p.token, { profit: p.profit ?? null, rarity: p.rarity ?? null, mutation: p.mutation ?? null, isEgg: !!p.isEgg, }); } }; app.on('PetsManager:PetsSpawn', onPetsSpawn); app.on('BasesManager:PetsSpawn', onPetsSpawn); console.log('[ml] pet spawn hook installed'); } function getMyBase() { const basesScript = _getBasesManager(); if (!basesScript?.activeBases) return null; const nm = _getNetworkManager(); const sessionId = nm?.room?.sessionId || W.pc?.sessionId; if (!sessionId) return null; for (const bd of basesScript.activeBases) { if (bd?.data?.sessionId === sessionId) return basesScript.baseEntities?.[bd.data.id] ?? null; } return null; } function getLockBtn() { const base = getMyBase(); if (!base) return null; const btn = base.findByName('LockdownButton'); return btn?.script?.lockdownButton ?? null; } let _lastLockTriggerLog = 0; function triggerLock() { const btn = getLockBtn(); if (!btn || typeof btn.onTriggerEnter !== 'function') return false; const player = getPlayer(); if (!player) return false; btn.onTriggerEnter(player); const now = Date.now(); if (_roomJoinTime) { console.log('[ml] auto-lock: first lock ' + (now - _roomJoinTime) + 'ms after join'); _roomJoinTime = 0; } else if (now - _lastLockTriggerLog > 10000) { _lastLockTriggerLog = now; console.log('[ml] auto-lock: triggered'); } return true; } let lastLockCheck = 0; function hookAntiDisconnect() { const nm = _getNetworkManager(); const room = nm?.room; if (!room) return; if (room.__mlSendHooked) return; room.__mlSendHooked = true; const origSend = room.send.bind(room); room.__mlOrigSend = origSend; const HEIGHT_OFFSET = 200; let _currentOffset = 0; let _wasHolding = false; let _earlyGhost = false; let _earlyGhostTimer = null; room.send = function (type, message) { if (type === 'stealPet' && featGhostMode) { _earlyGhost = true; _currentOffset = HEIGHT_OFFSET; _wasHolding = true; if (_earlyGhostTimer) clearTimeout(_earlyGhostTimer); _earlyGhostTimer = setTimeout(() => { _earlyGhost = false; _earlyGhostTimer = null; }, 5000); console.log('[ml] ghost: early activate on stealPet send'); } if (type === 'p' && message && featGhostMode && !_ghostSuppressed) { if (_wavesGhostPos) { return origSend(type, { x: _wavesGhostPos.x, y: _wavesGhostPos.y, z: _wavesGhostPos.z, w: message.w }); } const pt = _getPetTycoon(); const holding = !!pt?.isHoldingPet; if (holding) { _earlyGhost = false; _currentOffset = HEIGHT_OFFSET; _wasHolding = true; } else if (_earlyGhost) { // keep offset active until server confirms or 5s timeout } else if (_wasHolding && _currentOffset > 0) { _currentOffset = Math.max(0, _currentOffset - 10); if (_currentOffset === 0) _wasHolding = false; } if (_currentOffset > 0) { return origSend(type, { x: message.x, y: message.y + _currentOffset, z: message.z, w: message.w }); } } if (type === 'dropPet') { _earlyGhost = false; } return origSend(type, message); }; console.log('[ml] ghost position hook installed'); _playerCache = null; _playerCacheTime = 0; _ptCache = null; _ptCacheTime = 0; _etCache = null; _etCacheTime = 0; _nmCache = null; _nmCacheTime = 0; _bmCache = null; _bmCacheTime = 0; _serverLockedSessions.clear(); _lockDataReceived = false; _pendingBaseCapture = true; _roomJoinTime = Date.now(); _myPetTokens = new Set(); _myPetTokensTime = 0; if (featAntiKnockback) { room.onMessage('gotAttacked', () => {}); } setTimeout(() => { if (featInvisible) { _toggleInvisible(true); _updateInvisEffect(true); } if (featAutoFountain) _fountainStart(); _fountainHookExpiry(room); _hookProTips(room); }, 2000); let _stealReturnTimer = null; function _stealReturnHome() { if (!featGhostMode) return; const rawSend = room.__mlOrigSend || room.send.bind(room); if (_stealReturnTimer) { clearTimeout(_stealReturnTimer); } console.log('[ml] steal return: 10s then TP base'); _stealReturnTimer = setTimeout(() => { _stealReturnTimer = null; const player = getPlayer(); if (!player) return; const pt = _getPetTycoon(); const et = _getEscapeTsunami(); if (!pt?.isHoldingPet && !et?.isHoldingPet) { console.log('[ml] steal return: not holding pet, skip TP'); return; } _wavesGhostPos = null; backPos = capturePos(player); const app = W.pc?.app; if (app) app.fire('Player:TeleportToPersonalSpawn'); setTimeout(() => { const pos = player.getPosition(); rawSend('p', { x: pos.x, y: pos.y, z: pos.z, w: 0 }); }, 100); console.log('[ml] steal return: teleported to base'); }, 10000); } room.onMessage('petClaimed', msg => { if (msg?.stealerSessionId && msg.stealerSessionId !== room.sessionId) return; if (msg?.sessionId && msg.sessionId !== room.sessionId) return; _snipeCooldown = Date.now() + 10000; console.log('[ml] pet claimed — 10s snipe cooldown'); _stealReturnHome(); }); room.onMessage('petStolen', msg => { if (msg?.stealerSessionId && msg.stealerSessionId !== room.sessionId) return; if (msg?.sessionId && msg.sessionId !== room.sessionId) return; console.log('[ml] pet stolen'); _stealReturnHome(); }); room.onMessage('modeNotification', msg => { if (msg === 'PetClaimedSuccessfully' || (typeof msg === 'object' && msg.text === 'PetClaimedSuccessfully')) { console.log('[ml] mode notification: claimed'); _stealReturnHome(); } }); room.onMessage('baseLockdownTimers', msg => { _serverLockedSessions.clear(); if (Array.isArray(msg)) { for (const entry of msg) { if (entry.sessionId) _serverLockedSessions.add(entry.sessionId); } } _lockDataReceived = true; }); room.onMessage('triggerFunction', msg => { if (!msg?.client || msg.client === room.sessionId) return; if (msg.name !== 'Disable' && msg.name !== 'Enable') return; const nm2 = _getNetworkManager(); const enemy = nm2?.getPlayerById(msg.client); if (!enemy) return; const es = enemy.script?.enemy; if (!es?.originEntity) return; if (msg.name === 'Disable') { es.originEntity.enabled = true; _ghostifyEnemy(es.originEntity); console.log('[ml] anti-invis: ghosted', enemy.username || msg.client); } else { _unghostifyEnemy(es.originEntity); console.log('[ml] anti-invis: restored', enemy.username || msg.client); } }); if (typeof room.onLeave === 'function') { room.onLeave((code) => { console.log('[ml] room closed code=' + code); }); } } let _ghostActive = false; let _wavesGhostPos = null; let _ghostSuppressed = false; const GHOST_OPACITY = 0.25; function _ghostifyEnemy(origin) { origin.forEach(child => { const mis = child.render?.meshInstances || child.model?.meshInstances || []; for (const mi of mis) { if (!mi.material) continue; if (!mi.__mlAntiInvisOrig) { mi.__mlAntiInvisOrig = mi.material; mi.material = mi.material.clone(); } mi.material.blendType = W.pc.BLEND_NORMAL; mi.material.opacity = 0.3; mi.material.depthWrite = false; mi.material.update(); } }); } function _unghostifyEnemy(origin) { origin.forEach(child => { const mis = child.render?.meshInstances || child.model?.meshInstances || []; for (const mi of mis) { if (mi.__mlAntiInvisOrig) { mi.material = mi.__mlAntiInvisOrig; delete mi.__mlAntiInvisOrig; mi.material.update(); } } }); } function _getCharMeshInstances() { const player = getPlayer(); const ch = player?.findByName('CharacterHolder'); if (!ch) return []; const petHolder = player.findByName('PetHolder'); const skipSet = new Set(); if (petHolder) { skipSet.add(petHolder); petHolder.forEach(c => skipSet.add(c)); } const result = []; ch.forEach(child => { if (skipSet.has(child)) return; const mis = child.render?.meshInstances || child.model?.meshInstances || []; for (const mi of mis) if (mi.material) result.push(mi); }); return result; } function _updateCharTransparency() { const shouldFade = _ghostActive || featInvisible; const opacity = !shouldFade ? 1.0 : (featInvisible ? INVIS_OPACITY : GHOST_OPACITY); const mis = _getCharMeshInstances(); if (!mis.length) return; for (const mi of mis) { if (opacity < 1.0) { if (!mi.__mlOrigMat) { mi.__mlOrigMat = mi.material; mi.material = mi.material.clone(); } mi.material.blendType = W.pc.BLEND_NORMAL; mi.material.opacity = opacity; mi.material.depthWrite = false; } else { if (mi.__mlOrigMat) { mi.material = mi.__mlOrigMat; delete mi.__mlOrigMat; } } mi.material.update(); } } function updateGhostEffect() { const pt = _getPetTycoon(); const shouldGhost = featGhostMode && (!!pt?.isHoldingPet || !!_wavesGhostPos); if (shouldGhost === _ghostActive) return; _ghostActive = shouldGhost; console.log('[ml] ghost:', shouldGhost ? 'active' : 'inactive'); _updateCharTransparency(); } let antiDeathReady = false; function hookAntiDeath() { if (antiDeathReady) return; const app = W.pc?.app; if (!app) return; app.root.find(entity => { if (!entity.script?._scripts) return false; for (const inst of entity.script._scripts) { if (inst && typeof inst.deathYThreshold === 'number' && inst.deathYThreshold > -9999) { inst.deathYThreshold = -99999; console.log('[ml] anti-death: Y threshold → -99999 on %s', entity.name); } } return false; }); const origFire = app.fire; app._mlOrigFire = origFire; app.fire = function (ev, a1, a2, a3, a4, a5, a6, a7, a8) { switch (ev) { case 'DeathScreen:Trigger': if (featInvincible) return this; break; case 'PlayerController:GotHit': if (featAntiKnockback) return this; break; case 'ModeOverlay:BalanceChange': if (_mlBatchCollecting) { _mlBatchTotal += (typeof a1 === 'number' ? a1 : 0); _mlBatchCount++; clearTimeout(_mlBatchTimer); _mlBatchTimer = setTimeout(flushBatch, 2000); return this; } break; case 'ModeOverlay:Balance': if (_mlBatchCollecting) { _mlCachedBalance = a1; return this; } break; } return origFire.call(this, ev, a1, a2, a3, a4, a5, a6, a7, a8); }; app._mlNotifBatched = true; antiDeathReady = true; console.log('[ml] anti-death: ready'); } let antiKnockbackReady = false; function hookAntiKnockback() { if (antiKnockbackReady || !featAntiKnockback) return; const player = getPlayer(); const pc = getPC(player); if (!pc) return; pc.shockedTime = 0; pc.knockbackDecay = 1.0; antiKnockbackReady = true; } let noclipHooked = false; function hookNoclip() { if (noclipHooked) return; const player = getPlayer(); const kcc = getKcc(player); if (!kcc || !kcc.update) return; const origUpdate = kcc.update.bind(kcc); kcc.update = function (dt) { if (!featNoclip) return origUpdate(dt); const pos = this.entity.getPosition(); const preX = pos.x, preZ = pos.z; origUpdate(dt); const speed = this.speed || 7; const h = this._horizontal || 0, v = this._vertical || 0; const newPos = this.entity.getPosition(); this.entity.setPosition(preX + h * speed * dt, newPos.y, preZ + v * speed * dt); }; noclipHooked = true; console.log('[ml] noclip: KCC update hooked'); } let netSpyHooked = false; function hookNetSpy() { if (netSpyHooked) return; const nm = _getNetworkManager(); if (!nm?.room) return; netSpyHooked = true; const NOISY = new Set(['positions', 'animSetBooleans', 'animSetTrigger']); const origOnMessage = nm.room.onMessage.bind(nm.room); nm.room.onMessage = function (type, cb) { if (NOISY.has(type)) return origOnMessage(type, cb); return origOnMessage(type, function () { console.log('[ml] NET ←', type, arguments.length === 1 ? arguments[0] : Array.from(arguments)); return cb.apply(this, arguments); }); }; const prevSend = nm.room.send; nm.room.send = function (type, message) { if (type !== 'p' && !NOISY.has(type)) { console.log('[ml] NET →', type, message); } return prevSend.call(this, type, message); }; console.log('[ml] net-spy: active'); } W.mlSetUsername = function (name) { if (!name || typeof name !== 'string') { console.log('[ml] usage: mlSetUsername("NewName")'); return; } const token = localStorage.getItem('access_token_v0.01'); if (!token) { console.log('[ml] no access token — not logged in'); return; } console.log('[ml] changing username to: ' + name); fetch('https://api.meeland.io/v1/users/changeName', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ name }) }).then(r => { if (!r.ok) throw new Error(r.status === 400 || r.status === 403 ? 'already used free name change' : 'HTTP ' + r.status); return r.text().then(() => null); }).then(() => { console.log('[ml] username changed to: ' + name + ' — syncing to room'); const app = W.pc?.app; if (app) app.fire('NetworkManager:Send', 'refreshUsername'); }).catch(e => { console.error('[ml] username change failed:', e.message); }); }; W.mlProbeUsername = function () { const nm = _getNetworkManager(); if (!nm) { console.log('[ml] no network manager'); return; } const room = nm.room; const ps = room?.state?.players; const me = ps?.get?.(room.sessionId); console.log('[ml] username:', me?.username); console.log('[ml] sessionId:', room?.sessionId); console.log('[ml] accountId:', me?.accountId); console.log('[ml] room:', room?.name, room?.id); }; createHUD(); loadWaypoints(); if (isMobile) { const mfc = document.createElement('div'); mfc.id = 'ml-mobile-fly'; mfc.innerHTML = ''; const mfcStyle = document.createElement('style'); mfcStyle.textContent = [ '#ml-mobile-fly{position:fixed;right:2.5vmin;bottom:3vmin;z-index:15;display:none;flex-direction:column;align-items:flex-end;gap:clamp(6px,1.5vmin,12px);pointer-events:none}', '.ml-mfly{pointer-events:auto;width:clamp(52px,12vmin,80px);height:clamp(52px,12vmin,80px);border-radius:50%;border:2px solid rgba(200,170,255,.35);background:rgba(55,45,80,.55);color:rgba(255,250,255,.85);font-size:clamp(14px,3.5vmin,22px);font-weight:700;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;cursor:pointer;user-select:none;-webkit-user-select:none;touch-action:none;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);transition:background .12s,border-color .12s,transform .08s}', '.ml-mfly:active{transform:scale(.92);background:rgba(140,100,220,.4);border-color:rgba(200,170,255,.6)}', '.ml-mfly.on{background:rgba(100,180,100,.4);border-color:rgba(140,230,140,.5)}', '.ml-mcollapse{width:clamp(36px,8vmin,52px);height:clamp(36px,8vmin,52px);font-size:clamp(16px,4vmin,24px);border-color:rgba(180,180,200,.3);background:rgba(40,40,55,.55)}', '.ml-mcollapse:active{background:rgba(100,100,140,.4)}', '#ml-mobile-fly.collapsed .ml-mfly:not(.ml-mcollapse){display:none}', '.ml-msprint-btn{border-color:rgba(255,180,60,.35);background:rgba(80,55,30,.55);font-size:clamp(11px,2.8vmin,16px)}', '.ml-msprint-btn:active{background:rgba(220,160,40,.4);border-color:rgba(255,200,80,.6)}', '.ml-msprint-btn.on{background:rgba(220,160,40,.4);border-color:rgba(255,200,80,.5)}', ].join(''); document.head.appendChild(mfcStyle); document.body.appendChild(mfc); const mflyToggle = $('ml-mfly-toggle'); const mflyUp = $('ml-mfly-up'); const mflyDown = $('ml-mfly-down'); const msprint = $('ml-msprint'); const mCollapse = $('ml-mfly-collapse'); let _collapseLock = false; const toggleCollapse = () => { if (_collapseLock) return; _collapseLock = true; setTimeout(() => _collapseLock = false, 200); const collapsed = mfc.classList.toggle('collapsed'); mCollapse.textContent = collapsed ? '⊞' : '⊟'; }; mCollapse.addEventListener('touchstart', e => { e.preventDefault(); toggleCollapse(); }); mCollapse.addEventListener('click', toggleCollapse); mflyToggle.addEventListener('touchstart', e => { e.preventDefault(); if (!featFly) return; const p = getPlayer(), k = getKcc(p); if (!k) return; if (flyActive) { flyOff(k); mflyToggle.classList.remove('on'); } else { flyOn(k, true); mflyToggle.classList.add('on'); } }); msprint.addEventListener('touchstart', e => { e.preventDefault(); if (!featSprint) return; sprinting = !sprinting; msprint.classList.toggle('on', sprinting); }); mflyUp.addEventListener('touchstart', e => { e.preventDefault(); if (!featFly || !flyActive) return; flyUp = true; }); mflyUp.addEventListener('touchend', e => { e.preventDefault(); flyUp = false; }); mflyUp.addEventListener('touchcancel', () => { flyUp = false; }); mflyDown.addEventListener('touchstart', e => { e.preventDefault(); if (!featFly || !flyActive) return; flyDown = true; }); mflyDown.addEventListener('touchend', e => { e.preventDefault(); flyDown = false; }); mflyDown.addEventListener('touchcancel', () => { flyDown = false; }); } let _flyClickTime = 0; $('ml-fly').addEventListener('click', () => { if (!featFly || isMobile) return; const now = Date.now(); if (now - _flyClickTime < 300) return; _flyClickTime = now; const p = getPlayer(), k = getKcc(p); if (!k) return; if (flyActive) flyOff(k); else flyOn(k, true); }); $('ml-spr').addEventListener('click', () => { if (!featSprint) return; sprinting = !sprinting; }); $('ml-home').addEventListener('click', () => { if (!featWaypoints) return; const p = getPlayer(); if (!p) return; homePos = capturePos(p); saveWaypoints(); flash('ml-home'); console.log('[ml] home set via click'); }); $('ml-go').addEventListener('click', () => { if (!featWaypoints || !homePos) return; const p = getPlayer(); if (!p) return; backPos = capturePos(p); teleport(p, homePos); saveWaypoints(); flash('ml-go'); }); $('ml-back').addEventListener('click', () => { if (!featWaypoints || !backPos) return; const p = getPlayer(); if (!p) return; const cur = capturePos(p); teleport(p, backPos); backPos = cur; saveWaypoints(); flash('ml-back'); }); $('ml-lock').addEventListener('click', () => { if (!featAutoLock) return; triggerLock(); flash('ml-lock'); }); function toggleSlots(forceOpen) { if (!featWaypoints) return; const pop = $('ml-slots-pop'); if (!pop) return; const open = forceOpen !== undefined ? forceOpen : !pop.classList.contains('open'); pop.classList.toggle('open', open); if (open) { pop.dispatchEvent(new CustomEvent('ml-rebuild')); panelPause(); } else { pop._resetPos?.(); panelResume(); } } $('ml-slots').addEventListener('click', () => { toggleSlots(); }); let _invisTimer = null; function _toggleInvisible(on) { clearInterval(_invisTimer); _invisTimer = null; const nm = _getNetworkManager(); const room = nm?.room; if (!room?.connection?.isOpen) return; const rawSend = room.__mlOrigSend || room.send.bind(room); rawSend('triggerFunction', { name: on ? 'Disable' : 'Enable', value: true }); if (on) { _invisTimer = setInterval(() => { const nm2 = _getNetworkManager(); const r = nm2?.room; if (!r?.connection?.isOpen || !featInvisible) { clearInterval(_invisTimer); _invisTimer = null; return; } const rs = r.__mlOrigSend || r.send.bind(r); rs('triggerFunction', { name: 'Disable', value: true }); }, 3000); } console.log('[ml] invisible: ' + (on ? 'ON (repeating)' : 'OFF')); } let _invisActive = false; const INVIS_OPACITY = 0.3; function _updateInvisEffect(on) { if (on === _invisActive) return; _invisActive = on; console.log('[ml] invis effect:', on ? 'on' : 'off'); _updateCharTransparency(); } let _proTipsCooldown = 0; const _PT_COOLDOWN = 600000; const _ptOpeners = ['yo','ngl','bro','pro tip','just found','anyone try','seriously','trust me','ok but','hey']; const _ptNames = ["'Meeland Enhancement Suite'","the 'Meeland Enhancement Suite'","'MES'","the enhancement suite"]; const _ptQuality = ['is insane','so broken lol','is actually op','changes everything','is crazy good','is goated','best mod ive seen','makes the game ez','is nuts']; const _ptLocation = ['on greasy fork','search greasy fork','check greasy fork','find it on greasy fork','its on greasy fork']; const _ptClosers = ['fr fr','no cap','thank me later','trust','try it','you need this','100%','seriously']; const _ptTemplates = [ (o,n,q,l,c) => `${o} ${n} ${q} ${l} ${c}`, (o,n,q,l,c) => `${o} ${l} for ${n} ${q} ${c}`, (o,n,q,l,c) => `${o} get ${n} ${l} ${c}`, (o,n,q,l,c) => `${n} ${q} ${l} ${c}`, (o,n,q,l,c) => `${o} ${n} ${l} ${q} ${c}`, ]; function _pick(arr) { return arr[Math.random() * arr.length | 0]; } function _genProTip() { const t = _pick(_ptTemplates); return t(_pick(_ptOpeners), _pick(_ptNames), _pick(_ptQuality), _pick(_ptLocation), _pick(_ptClosers)).replace(/\s+/g, ' ').trim(); } const _proTipSentMsgs = new Set(); function _trySendProTip(isJoin) { if (!featProTips) return; const now = Date.now(); if (now - _proTipsCooldown < _PT_COOLDOWN) return; const nm = _getNetworkManager(); const room = nm?.room; if (!room?.connection?.isOpen) return; _proTipsCooldown = now; const rawSend = room.__mlOrigSend || room.send.bind(room); const delay = 2000 + Math.random() * 3000; setTimeout(() => { if (!featProTips || !room?.connection?.isOpen) return; const msg = _genProTip(); _proTipSentMsgs.add(msg); setTimeout(() => _proTipSentMsgs.delete(msg), 5000); _hookProTipSuppression(); rawSend(1, msg); _proTipsCooldown = isJoin ? Date.now() - _PT_COOLDOWN + 5000 : Date.now(); console.log('[ml] pro tip sent' + (isJoin ? ' (join)' : '') + ':', msg); }, delay); } function _hookProTipSuppression() { const app = W.pc?.app; if (!app || app.__mlPTSuppress) return; app.__mlPTSuppress = true; const origFire = app.fire; app.fire = function(event) { if (event === 'OverlayManager:ChatMessage') { const m = arguments[1]; if (m?.type === 0 && _proTipSentMsgs.size > 0 && _proTipSentMsgs.has(m.msg)) { _proTipSentMsgs.delete(m.msg); return this; } } return origFire.apply(this, arguments); }; } function _hookProTips(room) { if (room.__mlProTipsHooked) return; room.__mlProTipsHooked = true; _proTipsCooldown = 0; _trySendProTip(true); room.onMessage('sendChatMessage', msg => { if (!msg || msg.type !== 0) return; _trySendProTip(); }); } let _lastAttackTime = 0; function attackClosestEnemy() { const nm = _getNetworkManager(); const room = nm?.room; if (!room?.connection?.isOpen) return; if (room.name !== 'PetTycoon') return; const now = Date.now(); if (now - _lastAttackTime < 100) return; _lastAttackTime = now; const player = getPlayer(); if (!player) return; const holder = W.pc?.app?.root?.findByName('EnemyHolder'); if (!holder?.children?.length) { console.log('[ml] attack: no enemies found'); return; } const pPos = player.getPosition(); let closest = null, closestDist = Infinity, closestName = 'Player', closestEntity = null; for (const enemy of holder.children) { let name = null; try { name = enemy.script?.enemy?.usernameEntity?.element?.text; } catch (_) {} if (!name) { const ue = enemy.findByName?.('Username'); if (ue?.element?.text) name = ue.element.text; } if (name === 'Stishka') continue; const ePos = enemy.getPosition(); const d = pPos.distance(ePos); if (d < closestDist) { closestDist = d; closest = ePos; closestEntity = enemy; closestName = name || 'Player'; } } if (!closest || !closestEntity) return; backPos = capturePos(player); const rawSend = room.__mlOrigSend || room.send.bind(room); _ghostSuppressed = true; const myPos = player.getPosition(); const dx = closest.x - myPos.x; const dz = closest.z - myPos.z; const dir = Math.atan2(dx, dz) * (180 / Math.PI); const startTime = performance.now(); let attacked = false; const trackAndAttack = () => { const ep = closestEntity.getPosition(); teleport(player, vec3(ep)); rawSend('p', { x: ep.x, y: ep.y, z: ep.z, w: dir }); if (performance.now() - startTime >= 50 && !attacked) { rawSend('attack', 'Baton'); attacked = true; } if (performance.now() - startTime < 150) { requestAnimationFrame(trackAndAttack); } else { if (!attacked) rawSend('attack', 'Baton'); console.log('[ml] attack: ' + Math.round(performance.now() - startTime) + 'ms'); setTimeout(() => { _ghostSuppressed = false; }, 200); } }; trackAndAttack(); console.log('[ml] attack: TP→' + closestName + ' (' + Math.floor(closestDist) + 'm)'); } let _autoAttackCooldown = 0; let _autoAttackTarget = null; let _autoAttackRRIdx = 0; let _myPetTokens = new Set(); let _myPetTokensTime = 0; function _refreshMyPetTokens() { const now = Date.now(); if (now - _myPetTokensTime < 10000 && _myPetTokens.size > 0) return; const nm = _getNetworkManager(); const myId = nm?.room?.sessionId; if (!myId) return; const root = W.pc?.app?.root; if (!root) return; root.find(e => { if (!e.script) return false; for (const k of Object.keys(e.script)) { const s = e.script[k]; if (s?.basePets && s.basePets.size > 0) { s.basePets.forEach((pet, token) => { if (pet?.owner === myId) _myPetTokens.add(token); }); _myPetTokensTime = now; return true; } } return false; }); } function autoAttackPetThieves() { if (!featAutoAttack) return; if (!_getBasesManager()?.activeBases) return; const now = Date.now(); if (now < _autoAttackCooldown) return; _refreshMyPetTokens(); if (_myPetTokens.size === 0) return; const nm = _getNetworkManager(); const room = nm?.room; if (!room?.state?.players || !room?.connection?.isOpen) return; const myId = room.sessionId; const thieves = []; room.state.players.forEach((p, sid) => { if (sid === myId) return; if (p.isHoldingPet && p.holdingPetToken && _myPetTokens.has(p.holdingPetToken)) { thieves.push({ sid, name: p.username || 'Player' }); } }); if (thieves.length === 0) { if (_autoAttackTarget) { console.log('[ml] auto-attack: no thieves — chase ended'); _autoAttackTarget = null; _autoAttackRRIdx = 0; } return; } if (_autoAttackRRIdx >= thieves.length) _autoAttackRRIdx = 0; const thief = thieves[_autoAttackRRIdx]; _autoAttackRRIdx++; const holder = W.pc?.app?.root?.findByName('EnemyHolder'); if (!holder?.children?.length) return; let targetEntity = null; for (const enemy of holder.children) { let name = null; try { name = enemy.script?.enemy?.usernameEntity?.element?.text; } catch (_) {} if (!name) { const ue = enemy.findByName?.('Username'); if (ue?.element?.text) name = ue.element.text; } if (name === thief.name) { targetEntity = enemy; break; } } if (!targetEntity) return; const player = getPlayer(); if (!player) return; if (_autoAttackTarget !== thief.name) { backPos = capturePos(player); console.log('[ml] auto-attack: → ' + thief.name + ' (' + thieves.length + ' thieves)'); } _autoAttackTarget = thief.name; _autoAttackCooldown = now + 1600; const rawSend = room.__mlOrigSend || room.send.bind(room); _ghostSuppressed = true; const myPos = player.getPosition(); const tPos = targetEntity.getPosition(); const dx = tPos.x - myPos.x; const dz = tPos.z - myPos.z; const dir = Math.atan2(dx, dz) * (180 / Math.PI); const startTime = performance.now(); let attacked = false; const trackAndAttack = () => { const ep = targetEntity.getPosition(); teleport(player, vec3(ep)); rawSend('p', { x: ep.x, y: ep.y, z: ep.z, w: dir }); if (performance.now() - startTime >= 50 && !attacked) { rawSend('attack', 'Baton'); attacked = true; } if (performance.now() - startTime < 150) { requestAnimationFrame(trackAndAttack); } else { if (!attacked) rawSend('attack', 'Baton'); setTimeout(() => { _ghostSuppressed = false; }, 200); } }; trackAndAttack(); } window.addEventListener('keydown', e => { const openPanel = $('ml-pets')?.classList.contains('open') ? 'pets' : $('ml-settings')?.classList.contains('open') ? 'settings' : $('ml-plist')?.classList.contains('open') ? 'plist' : $('ml-dialog')?.classList.contains('open') ? 'dialog' : $('ml-slots-pop')?.classList.contains('open') ? 'slots' : $('ml-snipe')?.classList.contains('open') ? 'snipe' : null; if (openPanel) { if (openPanel === 'snipe') { if (e.code === 'Escape') { e.stopPropagation(); e.preventDefault(); $('ml-snipe-close')?.click(); return; } const active = document.activeElement; if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA') && $('ml-snipe')?.contains(active)) { e.stopPropagation(); return; } } else { if (e.code === 'Escape') { e.stopPropagation(); e.preventDefault(); if (openPanel === 'pets') $('ml-pets-close')?.click(); else if (openPanel === 'settings') $('ml-settings-close')?.click(); else if (openPanel === 'plist') $('ml-plist-close')?.click(); else if (openPanel === 'dialog') $('ml-close')?.click(); else if (openPanel === 'slots') $('ml-slots-pop-close')?.click(); return; } const active = document.activeElement; if (active?.tagName === 'INPUT' || active?.tagName === 'TEXTAREA') { e.stopPropagation(); return; } e.stopPropagation(); e.preventDefault(); return; } } const active = document.activeElement; if (active?.tagName === 'INPUT' || active?.tagName === 'TEXTAREA') return; if (kbListeningRow) return; if (e.code === KEYBINDS.cuddle) { e.preventDefault(); e.stopPropagation(); if (featCuddle) $('ml-tp')?.click(); return; } if (e.code === KEYBINDS.settings) { e.preventDefault(); e.stopPropagation(); $('ml-cfg')?.click(); return; } if (e.code === KEYBINDS.pets) { e.preventDefault(); e.stopPropagation(); if (featPets) $('ml-pets-btn')?.click(); return; } if (e.code === KEYBINDS.snipe) { e.preventDefault(); e.stopPropagation(); $('ml-snipe-btn')?.click(); return; } if (e.code === KEYBINDS.attack) { e.preventDefault(); e.stopPropagation(); attackClosestEnemy(); return; } if (e.code === KEYBINDS.invisible) { e.preventDefault(); e.stopPropagation(); $('ml-invis')?.click(); return; } if (e.code === KEYBINDS.slots) { e.preventDefault(); e.stopPropagation(); $('ml-slots')?.click(); return; } if (e.code === KEYBINDS.help) { e.preventDefault(); e.stopPropagation(); $('ml-help')?.click(); return; } const player = getPlayer(); const kcc = getKcc(player); if (!kcc) return; if (cuddling && MOVE_KEYS.has(e.code)) { cuddling = false; cuddleTarget = null; console.log('[cuddle] cancelled'); } const numpadMatch = e.code.match(/^Numpad(\d)$/); let slotIdx = numpadMatch ? parseInt(numpadMatch[1]) : -1; if (slotIdx < 0 && e.location === 3) { const alt = { Insert: 0, End: 1, ArrowDown: 2, PageDown: 3, ArrowLeft: 4, Clear: 5, ArrowRight: 6, Home: 7, ArrowUp: 8, PageUp: 9 }; slotIdx = alt[e.key] ?? -1; } if (slotIdx >= 0 && featWaypoints) { const idx = slotIdx; if (e.ctrlKey) { e.preventDefault(); e.stopPropagation(); slots[idx] = capturePos(player); saveWaypoints(); flash('ml-slots'); console.log(`[slot ${idx}] saved`, slots[idx]); return; } else if (slots[idx]) { e.preventDefault(); e.stopPropagation(); backPos = capturePos(player); teleport(player, slots[idx]); saveWaypoints(); flash('ml-slots'); console.log(`[slot ${idx}] teleported to`, slots[idx]); return; } } if (e.code === KEYBINDS.fly) { if (!featFly) return; e.stopPropagation(); if (flyActive) { flyUp = true; } else { flyOn(kcc); } return; } if (e.code === KEYBINDS.flyDown && flyActive) { flyDown = true; return; } if (e.key === 'Shift' && !sprinting && featSprint) { sprinting = true; return; } if (e.code === KEYBINDS.setHome) { e.preventDefault(); if (!featWaypoints) return; homePos = capturePos(player); saveWaypoints(); flash('ml-home'); return; } if (e.code === KEYBINDS.home) { e.preventDefault(); if (!featWaypoints) return; if (homePos) { backPos = capturePos(player); teleport(player, homePos); saveWaypoints(); flash('ml-go'); } return; } if (e.code === KEYBINDS.back) { e.preventDefault(); if (!featWaypoints) return; if (backPos) { const cur = capturePos(player); teleport(player, backPos); backPos = cur; saveWaypoints(); flash('ml-back'); } } }, true); window.addEventListener('keyup', e => { if (anyPanelOpen()) { e.stopPropagation(); return; } if (e.code === KEYBINDS.fly) flyUp = false; if (e.code === KEYBINDS.flyDown) flyDown = false; if (e.key === 'Shift' && sprinting) { sprinting = false; } }, true); const _htmlHud = { fly: $('ml-fly'), spr: $('ml-spr'), home: $('ml-home'), go: $('ml-go'), back: $('ml-back'), slots: $('ml-slots'), lock: $('ml-lock'), invis: $('ml-invis'), tp: $('ml-tp'), petsBtn: $('ml-pets-btn'), snipeBtn: $('ml-snipe-btn'), cfg: $('ml-cfg'), help: $('ml-help') }; _nativeHud = createNativeHUD(); if (!_nativeHud) { const retryId = setInterval(() => { _nativeHud = createNativeHUD(); if (_nativeHud) { clearInterval(retryId); Object.assign(hud, _nativeHud); console.log('[ml] native HUD loaded (deferred)'); } }, 500); } const hud = _nativeHud || _htmlHud; const panels = { plist: $('ml-plist'), settings: $('ml-settings'), dialog: $('ml-dialog'), pets: $('ml-pets'), snipe: $('ml-snipe') }; let _hopResumed = false; let _hopInProgress = false; function performServerHop() { if (_hopInProgress) return; _hopInProgress = true; const app = W.pc?.app; if (!app) { _hopInProgress = false; return; } app.fire('NetworkManager:LeaveCurrentRoom'); console.log('[ml] hop: left room'); $('ml-snipe-status').textContent = 'Hopping...'; _nmCache = null; _nmCacheTime = 0; _bmCache = null; _bmCacheTime = 0; _serverLockedSessions.clear(); _lockDataReceived = false; _myPetTokens = new Set(); _myPetTokensTime = 0; _snipeHopNoMatchStart = 0; _hopResumed = false; setTimeout(() => { app.fire('OverlayManager:ClickGameMode', 0); console.log('[ml] hop: rejoining Steal a Pet'); const dismissPlay = () => { const fml = app.root.findByName('FirstMouseLock'); if (fml && fml.enabled) { fml.enabled = false; app.fire('GameManager:GameResumed'); console.log('[ml] hop: dismissed PLAY screen'); } const canvas = app.graphicsDevice?.canvas; if (canvas && !document.pointerLockElement) { try { canvas.requestPointerLock(); } catch (_) {} } _hopInProgress = false; }; let attempts = 0; const checkReady = setInterval(() => { attempts++; const nm = _getNetworkManager(); const fml = app.root.findByName('FirstMouseLock'); if ((nm?.room?.state?.players && fml?.enabled) || attempts > 30) { clearInterval(checkReady); dismissPlay(); } }, 500); }, 3000); } function tryHopResume() { if (_hopResumed || _hopInProgress || !snipeAutoHop || !snipeActive) return; const nm = _getNetworkManager(); if (!nm?.room?.state?.players) return; const bm = _getBasesManager(); if (!bm?.activeBases) return; const root = W.pc?.app?.root; let petCount = 0; if (root) { root.find(e => { if (!e.script) return false; for (const k of Object.keys(e.script)) { const s = e.script[k]; if (s?.basePets && s.basePets.size > 0) { petCount = s.basePets.size; return true; } } return false; }); } if (petCount === 0) return; _hopResumed = true; _snipeHopNoMatchStart = 0; console.log('[ml] hop: new room ready (' + petCount + ' pets)'); const logEl = $('ml-snipe-log'); if (logEl) { const entry = document.createElement('div'); entry.className = 'ml-snipe-entry'; entry.textContent = new Date().toLocaleTimeString() + ' Hopped — ' + petCount + ' pets in new room'; logEl.prepend(entry); } } let _tickN = 0; function _tick() { requestAnimationFrame(_tick); _tickN++; const slow = (_tickN % 12 === 0); if (slow) { try { hookPetSpawn(); } catch (_) {} try { hookAntiDisconnect(); } catch (_) {} try { tryHopResume(); } catch (_) {} try { hookAntiDeath(); } catch (_) {} try { hookAntiKnockback(); } catch (_) {} try { hookNoclip(); } catch (_) {} try { updateGhostEffect(); } catch (_) {} try { hookNetSpy(); } catch (_) {} if (!freeMoneyDone && featFreeMoney) autoFarmFreeMoney(); if (featFreeStars && !_freeStarsTimer) _freeStarsStart(); if (featAutoFountain && Date.now() - _lastFountainSend > 30000) _fountainSend(); autoCollectPetEarnings(); autoAttackPetThieves(); const ct = $('ml-carry-timer'); if (ct) { const pt = _getPetTycoon(); const holding = !!(pt?.isHoldingPet); const isSteal = !!_getBasesManager()?.activeBases; if (holding && isSteal) { if (!ct._start) ct._start = Date.now(); ct.style.display = ''; ct.textContent = '\u23F1 ' + ((Date.now() - ct._start) / 1000).toFixed(1) + 's'; } else { if (ct._start) ct._start = 0; ct.style.display = 'none'; } } } const player = getPlayer(); if (!player) return; if (slow && _pendingBaseCapture) { const myBase = getMyBase(); if (myBase) { const bp = myBase.getPosition(); backPos = { x: bp.x, y: bp.y, z: bp.z }; _pendingBaseCapture = false; console.log('[ml] backPos set to home base (' + (_roomJoinTime ? (Date.now() - _roomJoinTime) + 'ms' : '?') + '):', bp.x.toFixed(1), bp.y.toFixed(1), bp.z.toFixed(1)); } } const kcc = getKcc(player); if (!kcc) return; const now = Date.now(); const dt = Math.min((now - prevTick) / 1000, 0.1); prevTick = now; const pc = getPC(player); if (pc?.isDied) { pc.isDied = false; } if (sprinting && !isMobile) { const kb = W.pc?.app?.keyboard; if (kb && !kb.isPressed(W.pc.KEY_SHIFT)) { sprinting = false; } } if (sprinting) { const sprintMin = SPEED_DEFAULT * 3; if (sprintSpeed < sprintMin) sprintSpeed = sprintMin; if (accelEnabled) sprintSpeed = Math.min(sprintSpeed + ACCEL * dt, SPEED_CAP); setSpeed(pc, kcc, sprintSpeed); if (pc?.isSlowedSpeed) pc.isSlowedSpeed = false; } else if (sprintSpeed !== SPEED_DEFAULT) { sprintSpeed = SPEED_DEFAULT; setSpeed(pc, kcc, SPEED_DEFAULT); } if (slow) { if (hud.fly) { hud.fly.classList.toggle('on', flyActive); hud.fly.classList.toggle('disabled', !featFly); } const mft = $('ml-mfly-toggle'); if (mft) mft.classList.toggle('on', flyActive); if (hud.spr) { hud.spr.classList.toggle('on', sprinting); hud.spr.classList.toggle('disabled', !featSprint); } const msp = $('ml-msprint'); if (msp) msp.classList.toggle('on', sprinting); if (hud.home) hud.home.classList.toggle('disabled', !featWaypoints); if (hud.go) hud.go.classList.toggle('disabled', !featWaypoints); if (hud.back) hud.back.classList.toggle('disabled', !featWaypoints); if (hud.slots) { const n = slots.filter(Boolean).length; hud.slots.textContent = `SLOTS ${n}/10`; hud.slots.classList.toggle('disabled', !featWaypoints); } if (hud.tp) { hud.tp.classList.toggle('disabled', !featCuddle); hud.tp.classList.toggle('on', !!panels.plist?.classList.contains('open')); } if (hud.petsBtn) { hud.petsBtn.classList.toggle('disabled', !featPets); hud.petsBtn.classList.toggle('on', !!panels.pets?.classList.contains('open')); } if (hud.snipeBtn) { hud.snipeBtn.classList.toggle('on', snipeActive || !!panels.snipe?.classList.contains('open')); } if (hud.invis) hud.invis.classList.toggle('on', featInvisible); if (hud.cfg) hud.cfg.classList.toggle('on', !!panels.settings?.classList.contains('open')); if (hud.help) hud.help.classList.toggle('on', !!panels.dialog?.classList.contains('open')); if (featAutoLock && now - lastLockCheck > 100) { lastLockCheck = now; const lockBtn = getLockBtn(); if (lockBtn) { const timeLeft = lockBtn.lockdownTimeLeft || 0; const isActive = lockBtn.isLockdownActive || false; if (hud.lock) { hud.lock.classList.toggle('on', isActive && timeLeft > 0); hud.lock.textContent = (isActive && timeLeft > 0) ? `\ud83d\udd12 ${Math.ceil(timeLeft)}s` : '\ud83d\udd13 UNLOCKED'; } if (!isActive || timeLeft <= 0) triggerLock(); } else if (hud.lock) { hud.lock.textContent = '\ud83d\udd12 LOCK'; hud.lock.classList.remove('on'); } } if (hud.lock) hud.lock.classList.toggle('disabled', !featAutoLock); } if (cuddling && cuddleTarget && featCuddleFollow) { if (kcc._horizontal || kcc._vertical) { cuddling = false; cuddleTarget = null; console.log('[cuddle] cancelled (movement input)'); } else { const tPos = cuddleTarget.getPosition?.(); if (tPos) { kcc.gravity = 0; kcc._velY = 0; teleport(player, vec3(tPos)); } else { cuddling = false; cuddleTarget = null; console.log('[cuddle] target lost'); } } } if (!flyActive) return; if (kcc._grounded && Date.now() - _flyStartTime > 500) { flyOff(kcc, false); return; } if (kcc.gravity !== 0) kcc.gravity = 0; flyVelY = kcc._velY; const flySpeedCap = sprinting ? sprintSpeed : SPEED_CAP; if (flyUp) { if (flyVelY < 0) { flyVelY = 0; } else if (accelEnabled) { if (flyVelY < FLY_MIN_SPEED) flyVelY = FLY_MIN_SPEED; flyVelY = Math.min(flyVelY + ACCEL * dt, flySpeedCap); } else { flyVelY = flySpeedCap; } } else if (flyDown) { if (flyVelY > 0) { flyVelY = 0; } else if (accelEnabled) { if (flyVelY > -FLY_MIN_SPEED) flyVelY = -FLY_MIN_SPEED; flyVelY = Math.max(flyVelY - ACCEL * dt, -flySpeedCap); } else { flyVelY = -flySpeedCap; } } else { flyVelY = 0; } kcc._velY = flyVelY; } requestAnimationFrame(_tick); })();