Veck.io Mod Menu - Ultimate Hack Client

Advanced mod menu with infinite ammo, rapid fire, speed hacks, jump boost, and ESP wallhack

Size

43.5 KB

Version

1.2.2

Created

Mar 7, 2026

Updated

about 1 month ago

1// ==UserScript==
2// @name		Veck.io Mod Menu - Ultimate Hack Client
3// @description		Advanced mod menu with infinite ammo, rapid fire, speed hacks, jump boost, and ESP wallhack
4// @version		1.2.2
5// @match		https://*.veck.io/*
6// @icon		https://veck.io/favicon/favicon.ico
7// @grant		GM.getValue
8// @grant		GM.setValue
9// ==/UserScript==
10(function() {
11    'use strict';
12
13    console.log('[VECK.IO ADVANCED MOD] Initializing...');
14
15    // ============================================
16    // CONFIGURATION
17    // ============================================
18    const CONFIG = {
19        infiniteAmmo: false,
20        rapidFire: false,
21        speedHack: false,
22        jumpBoost: false,
23        esp: false,
24        noRecoil: false,
25        aimbot: false,
26        speedMultiplier: 2.5,
27        jumpMultiplier: 2.0,
28        fireRateMultiplier: 5.0
29    };
30
31    // ============================================
32    // STATE MANAGEMENT
33    // ============================================
34    let gameInstance = null;
35    let unityInstance = null;
36    let webglContext = null;
37    let originalWebSocket = null;
38    let players = new Map();
39    let localPlayer = null;
40    let espCanvas = null;
41    let espContext = null;
42    let viewMatrix = null;
43    let projectionMatrix = null;
44
45    // ============================================
46    // UTILITY FUNCTIONS
47    // ============================================
48    function debounce(func, wait) {
49        let timeout;
50        return function executedFunction(...args) {
51            const later = () => {
52                clearTimeout(timeout);
53                func(...args);
54            };
55            clearTimeout(timeout);
56            timeout = setTimeout(later, wait);
57        };
58    }
59
60    // ============================================
61    // LOAD/SAVE SETTINGS
62    // ============================================
63    async function loadSettings() {
64        try {
65            const saved = await GM.getValue('veckio_advanced_settings', null);
66            if (saved) {
67                Object.assign(CONFIG, JSON.parse(saved));
68                console.log('[MOD] Settings loaded:', CONFIG);
69            }
70        } catch (e) {
71            console.error('[MOD] Error loading settings:', e);
72        }
73    }
74
75    async function saveSettings() {
76        try {
77            await GM.setValue('veckio_advanced_settings', JSON.stringify(CONFIG));
78        } catch (e) {
79            console.error('[MOD] Error saving settings:', e);
80        }
81    }
82
83    // ============================================
84    // WEBGL CONTEXT INTERCEPTION
85    // ============================================
86    function interceptWebGL() {
87        console.log('[WEBGL] Intercepting WebGL context...');
88        
89        const canvas = document.querySelector('canvas#unity-canvas');
90        if (!canvas) {
91            console.error('[WEBGL] Canvas not found!');
92            return;
93        }
94
95        // Store original getContext
96        const originalGetContext = HTMLCanvasElement.prototype.getContext;
97        
98        HTMLCanvasElement.prototype.getContext = function(type, attributes) {
99            const context = originalGetContext.call(this, type, attributes);
100            
101            if ((type === 'webgl' || type === 'webgl2' || type === 'experimental-webgl') && this.id === 'unity-canvas') {
102                console.log('[WEBGL] Game WebGL context captured!');
103                webglContext = context;
104                hookWebGLFunctions(context);
105            }
106            
107            return context;
108        };
109
110        // Try to get existing context
111        webglContext = canvas.getContext('webgl') || canvas.getContext('webgl2') || canvas.getContext('experimental-webgl');
112        if (webglContext) {
113            console.log('[WEBGL] Existing context found and hooked');
114            hookWebGLFunctions(webglContext);
115        }
116    }
117
118    // ============================================
119    // HOOK WEBGL FUNCTIONS FOR ESP
120    // ============================================
121    function hookWebGLFunctions(gl) {
122        console.log('[WEBGL] Hooking WebGL functions for ESP...');
123
124        // Hook drawArrays and drawElements to intercept rendering
125        const originalDrawArrays = gl.drawArrays;
126        const originalDrawElements = gl.drawElements;
127
128        gl.drawArrays = function(mode, first, count) {
129            if (CONFIG.esp) {
130                extractRenderData(gl, mode, first, count);
131            }
132            return originalDrawArrays.call(this, mode, first, count);
133        };
134
135        gl.drawElements = function(mode, count, type, offset) {
136            if (CONFIG.esp) {
137                extractRenderData(gl, mode, count, type, offset);
138            }
139            return originalDrawElements.call(this, mode, count, type, offset);
140        };
141
142        // Hook uniform setters to capture matrices
143        const originalUniformMatrix4fv = gl.uniformMatrix4fv;
144        gl.uniformMatrix4fv = function(location, transpose, value) {
145            if (value && value.length === 16) {
146                // Try to identify view and projection matrices
147                const matrixArray = Array.from(value);
148                
149                // Store potential camera matrices
150                if (!viewMatrix || Math.abs(matrixArray[12]) > 0.01) {
151                    viewMatrix = matrixArray;
152                }
153                if (!projectionMatrix || Math.abs(matrixArray[0]) < 10) {
154                    projectionMatrix = matrixArray;
155                }
156            }
157            return originalUniformMatrix4fv.call(this, location, transpose, value);
158        };
159
160        console.log('[WEBGL] WebGL functions hooked successfully');
161    }
162
163    // ============================================
164    // EXTRACT RENDER DATA FOR ESP
165    // ============================================
166    function extractRenderData() {
167        // This would extract vertex data from buffers
168        // For now, we'll use a different approach with WebSocket data
169    }
170
171    // ============================================
172    // WEBSOCKET INTERCEPTION (ADVANCED)
173    // ============================================
174    function interceptWebSocket() {
175        console.log('[WEBSOCKET] Setting up advanced interception...');
176        
177        originalWebSocket = window.WebSocket;
178        
179        window.WebSocket = function(url, protocols) {
180            console.log('[WEBSOCKET] New connection intercepted:', url);
181            
182            const ws = new originalWebSocket(url, protocols);
183            
184            // Hook send method
185            const originalSend = ws.send.bind(ws);
186            ws.send = function(data) {
187                const modified = processOutgoingPacket(data);
188                return originalSend(modified);
189            };
190            
191            // Hook message event with proper interception
192            const originalAddEventListener = ws.addEventListener.bind(ws);
193            ws.addEventListener = function(type, listener, ...args) {
194                if (type === 'message') {
195                    const wrappedListener = function(event) {
196                        processIncomingPacket(event);
197                        return listener.call(this, event);
198                    };
199                    return originalAddEventListener(type, wrappedListener, ...args);
200                }
201                return originalAddEventListener(type, listener, ...args);
202            };
203            
204            // Also hook onmessage property
205            Object.defineProperty(ws, 'onmessage', {
206                set: function(handler) {
207                    this._onmessage = function(event) {
208                        processIncomingPacket(event);
209                        if (handler) handler.call(this, event);
210                    };
211                },
212                get: function() {
213                    return this._onmessage;
214                }
215            });
216            
217            return ws;
218        };
219        
220        console.log('[WEBSOCKET] Interception active');
221    }
222
223    // ============================================
224    // PROCESS OUTGOING PACKETS
225    // ============================================
226    function processOutgoingPacket(data) {
227        try {
228            // Handle binary data (most modern games use binary protocols)
229            if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
230                return modifyBinaryPacket(data);
231            }
232            
233            // Handle string/JSON data
234            if (typeof data === 'string') {
235                return modifyTextPacket(data);
236            }
237            
238            return data;
239        } catch (e) {
240            console.error('[PACKET] Error processing outgoing:', e);
241            return data;
242        }
243    }
244
245    // ============================================
246    // MODIFY BINARY PACKETS (ADVANCED)
247    // ============================================
248    function modifyBinaryPacket(data) {
249        const buffer = data instanceof ArrayBuffer ? data : data.buffer;
250        const view = new DataView(buffer);
251        const uint8View = new Uint8Array(buffer);
252        
253        // Log packet for analysis
254        if (Math.random() < 0.01) { // Log 1% of packets
255            console.log('[PACKET] Binary packet:', {
256                length: buffer.byteLength,
257                first16Bytes: Array.from(uint8View.slice(0, 16))
258            });
259        }
260        
261        // Apply hacks to binary data
262        if (CONFIG.speedHack || CONFIG.jumpBoost) {
263            // Scan for float values that might be movement data
264            for (let i = 0; i < view.byteLength - 4; i++) {
265                // Try little-endian
266                let value = view.getFloat32(i, true);
267                
268                // Movement values are typically in range [-10, 10]
269                if (Math.abs(value) > 0.1 && Math.abs(value) < 10) {
270                    if (CONFIG.speedHack && Math.abs(value) > 0.5) {
271                        view.setFloat32(i, value * CONFIG.speedMultiplier, true);
272                    }
273                    if (CONFIG.jumpBoost && value > 1 && value < 8) {
274                        view.setFloat32(i, value * CONFIG.jumpMultiplier, true);
275                    }
276                }
277            }
278        }
279        
280        return data;
281    }
282
283    // ============================================
284    // MODIFY TEXT PACKETS
285    // ============================================
286    function modifyTextPacket(data) {
287        try {
288            const packet = JSON.parse(data);
289            
290            // Movement modifications
291            if (packet.type === 'move' || packet.type === 'input' || packet.type === 'player_input') {
292                if (CONFIG.speedHack && packet.velocity) {
293                    if (packet.velocity.x) packet.velocity.x *= CONFIG.speedMultiplier;
294                    if (packet.velocity.z) packet.velocity.z *= CONFIG.speedMultiplier;
295                }
296                if (CONFIG.jumpBoost && packet.velocity && packet.velocity.y > 0) {
297                    packet.velocity.y *= CONFIG.jumpMultiplier;
298                }
299            }
300            
301            // Weapon modifications
302            if (packet.type === 'fire' || packet.type === 'shoot' || packet.type === 'weapon_fire') {
303                if (CONFIG.infiniteAmmo) {
304                    packet.ammo = 999;
305                    packet.magazine = 999;
306                }
307                if (CONFIG.rapidFire) {
308                    packet.fireRate = (packet.fireRate || 100) * CONFIG.fireRateMultiplier;
309                    packet.delay = (packet.delay || 100) / CONFIG.fireRateMultiplier;
310                }
311                if (CONFIG.noRecoil) {
312                    packet.recoil = 0;
313                    packet.spread = 0;
314                }
315            }
316            
317            return JSON.stringify(packet);
318        } catch {
319            // Not JSON, return as-is
320            return data;
321        }
322    }
323
324    // ============================================
325    // PROCESS INCOMING PACKETS
326    // ============================================
327    function processIncomingPacket(event) {
328        try {
329            const data = event.data;
330            
331            // Handle binary data
332            if (data instanceof ArrayBuffer || data instanceof Blob) {
333                parseBinaryGameState(data);
334                return;
335            }
336            
337            // Handle text data
338            if (typeof data === 'string') {
339                parseTextGameState(data);
340            }
341        } catch (e) {
342            console.error('[PACKET] Error processing incoming:', e);
343        }
344    }
345
346    // ============================================
347    // PARSE BINARY GAME STATE
348    // ============================================
349    async function parseBinaryGameState(data) {
350        try {
351            let buffer = data;
352            if (data instanceof Blob) {
353                buffer = await data.arrayBuffer();
354            }
355            
356            const view = new DataView(buffer);
357            
358            // Try to extract player positions
359            // This is game-specific and requires reverse engineering
360            // Look for patterns: player data often comes in groups
361            
362            // Example: scan for coordinate triplets (x, y, z)
363            for (let i = 0; i < view.byteLength - 12; i += 4) {
364                const x = view.getFloat32(i, true);
365                const y = view.getFloat32(i + 4, true);
366                const z = view.getFloat32(i + 8, true);
367                
368                // Valid game coordinates are usually in reasonable ranges
369                if (Math.abs(x) < 1000 && Math.abs(y) < 1000 && Math.abs(z) < 1000) {
370                    // Potential player position found
371                    updatePlayerPosition(i, x, y, z);
372                }
373            }
374        } catch (e) {
375            console.error('[BINARY] Error parsing:', e);
376        }
377    }
378
379    // ============================================
380    // PARSE TEXT GAME STATE
381    // ============================================
382    function parseTextGameState(data) {
383        try {
384            const packet = JSON.parse(data);
385            
386            // Extract player data
387            if (packet.type === 'players' || packet.type === 'game_state' || packet.type === 'update') {
388                if (packet.players && Array.isArray(packet.players)) {
389                    packet.players.forEach(player => {
390                        updatePlayer(player);
391                    });
392                }
393            }
394            
395            // Track local player
396            if (packet.type === 'init' || packet.type === 'spawn' || packet.type === 'player_init') {
397                localPlayer = {
398                    id: packet.id || packet.playerId || packet.player_id,
399                    position: packet.position || { x: packet.x, y: packet.y, z: packet.z }
400                };
401                console.log('[PLAYER] Local player initialized:', localPlayer);
402            }
403            
404            // Update player positions
405            if (packet.type === 'position' || packet.type === 'player_position') {
406                updatePlayer({
407                    id: packet.id || packet.playerId,
408                    x: packet.x,
409                    y: packet.y,
410                    z: packet.z,
411                    name: packet.name,
412                    health: packet.health
413                });
414            }
415            
416        } catch {
417            // Not JSON or parsing error
418        }
419    }
420
421    // ============================================
422    // UPDATE PLAYER DATA
423    // ============================================
424    function updatePlayer(playerData) {
425        if (!playerData || !playerData.id) return;
426        
427        const player = {
428            id: playerData.id,
429            x: playerData.x || playerData.position?.x || 0,
430            y: playerData.y || playerData.position?.y || 0,
431            z: playerData.z || playerData.position?.z || 0,
432            name: playerData.name || `Player ${playerData.id}`,
433            health: playerData.health || 100,
434            isEnemy: playerData.id !== localPlayer?.id,
435            lastUpdate: Date.now()
436        };
437        
438        players.set(playerData.id, player);
439        
440        // Clean up old players (not updated in 5 seconds)
441        const now = Date.now();
442        for (let [id, p] of players.entries()) {
443            if (now - p.lastUpdate > 5000) {
444                players.delete(id);
445            }
446        }
447    }
448
449    function updatePlayerPosition(offset, x, y, z) {
450        // Create a pseudo-ID based on position offset
451        const id = `player_${offset}`;
452        
453        const player = players.get(id) || {};
454        player.id = id;
455        player.x = x;
456        player.y = y;
457        player.z = z;
458        player.lastUpdate = Date.now();
459        
460        players.set(id, player);
461    }
462
463    // ============================================
464    // 3D TO 2D PROJECTION
465    // ============================================
466    function worldToScreen(worldPos, canvas) {
467        if (!viewMatrix || !projectionMatrix) {
468            return null;
469        }
470        
471        try {
472            // Apply view matrix
473            const viewPos = multiplyMatrixVector(viewMatrix, [worldPos.x, worldPos.y, worldPos.z, 1]);
474            
475            // Apply projection matrix
476            const clipPos = multiplyMatrixVector(projectionMatrix, viewPos);
477            
478            // Perspective divide
479            if (clipPos[3] === 0) return null;
480            
481            const ndcX = clipPos[0] / clipPos[3];
482            const ndcY = clipPos[1] / clipPos[3];
483            const ndcZ = clipPos[2] / clipPos[3];
484            
485            // Check if behind camera
486            if (ndcZ < -1 || ndcZ > 1) return null;
487            
488            // Convert to screen coordinates
489            const screenX = (ndcX + 1) * 0.5 * canvas.width;
490            const screenY = (1 - ndcY) * 0.5 * canvas.height;
491            
492            return { x: screenX, y: screenY, visible: true };
493        } catch {
494            return null;
495        }
496    }
497
498    function multiplyMatrixVector(matrix, vector) {
499        const result = [0, 0, 0, 0];
500        for (let i = 0; i < 4; i++) {
501            for (let j = 0; j < 4; j++) {
502                result[i] += matrix[i * 4 + j] * vector[j];
503            }
504        }
505        return result;
506    }
507
508    // ============================================
509    // ESP CANVAS
510    // ============================================
511    function createESPCanvas() {
512        if (espCanvas) return;
513        
514        espCanvas = document.createElement('canvas');
515        espCanvas.id = 'esp-overlay';
516        espCanvas.style.cssText = `
517            position: fixed;
518            top: 0;
519            left: 0;
520            width: 100%;
521            height: 100%;
522            pointer-events: none;
523            z-index: 999998;
524        `;
525        espCanvas.width = window.innerWidth;
526        espCanvas.height = window.innerHeight;
527        document.body.appendChild(espCanvas);
528        
529        espContext = espCanvas.getContext('2d');
530        
531        window.addEventListener('resize', () => {
532            if (espCanvas) {
533                espCanvas.width = window.innerWidth;
534                espCanvas.height = window.innerHeight;
535            }
536        });
537        
538        renderESP();
539        console.log('[ESP] Canvas created and rendering started');
540    }
541
542    function removeESPCanvas() {
543        if (espCanvas) {
544            espCanvas.remove();
545            espCanvas = null;
546            espContext = null;
547        }
548    }
549
550    // ============================================
551    // RENDER ESP
552    // ============================================
553    function renderESP() {
554        if (!CONFIG.esp || !espCanvas || !espContext) return;
555        
556        espContext.clearRect(0, 0, espCanvas.width, espCanvas.height);
557        
558        const gameCanvas = document.querySelector('canvas#unity-canvas');
559        if (!gameCanvas) {
560            requestAnimationFrame(renderESP);
561            return;
562        }
563        
564        // Draw ESP for each player
565        players.forEach((player) => {
566            if (player.id === localPlayer?.id) return; // Don't draw local player
567            
568            // Try 3D to 2D projection if we have matrices
569            let screenPos = worldToScreen(player, gameCanvas);
570            
571            // Fallback: use simple position mapping
572            if (!screenPos) {
573                screenPos = {
574                    x: (player.x + 100) * 4,
575                    y: (player.z + 100) * 4,
576                    visible: true
577                };
578            }
579            
580            if (screenPos && screenPos.visible) {
581                drawESPBox(screenPos.x, screenPos.y, player);
582            }
583        });
584        
585        // Draw player count
586        espContext.fillStyle = '#00ff88';
587        espContext.font = 'bold 14px Arial';
588        espContext.fillText(`Players: ${players.size}`, 10, 30);
589        
590        requestAnimationFrame(renderESP);
591    }
592
593    function drawESPBox(x, y, player) {
594        const width = 40;
595        const height = 60;
596        
597        // Draw box
598        espContext.strokeStyle = player.isEnemy ? '#ff0000' : '#00ff00';
599        espContext.lineWidth = 2;
600        espContext.strokeRect(x - width/2, y - height/2, width, height);
601        
602        // Draw health bar
603        if (player.health !== undefined) {
604            const healthPercent = player.health / 100;
605            const barWidth = width;
606            const barHeight = 4;
607            
608            espContext.fillStyle = '#000000';
609            espContext.fillRect(x - barWidth/2, y - height/2 - 10, barWidth, barHeight);
610            
611            espContext.fillStyle = healthPercent > 0.5 ? '#00ff00' : (healthPercent > 0.25 ? '#ffff00' : '#ff0000');
612            espContext.fillRect(x - barWidth/2, y - height/2 - 10, barWidth * healthPercent, barHeight);
613        }
614        
615        // Draw name
616        if (player.name) {
617            espContext.fillStyle = '#ffffff';
618            espContext.font = '12px Arial';
619            espContext.textAlign = 'center';
620            espContext.fillText(player.name, x, y - height/2 - 15);
621        }
622        
623        // Draw distance if we have local player position
624        if (localPlayer && localPlayer.position) {
625            const dx = player.x - localPlayer.position.x;
626            const dz = player.z - localPlayer.position.z;
627            const distance = Math.sqrt(dx * dx + dz * dz);
628            
629            espContext.fillStyle = '#ffff00';
630            espContext.font = '10px Arial';
631            espContext.fillText(Math.round(distance) + 'm', x, y + height/2 + 15);
632        }
633    }
634
635    // ============================================
636    // MEMORY PATCHING
637    // ============================================
638    function patchGameMemory() {
639        console.log('[MEMORY] Patching game functions...');
640        
641        // Patch timers for rapid fire
642        const originalSetInterval = window.setInterval;
643        const originalSetTimeout = window.setTimeout;
644        
645        window.setInterval = function(callback, delay, ...args) {
646            if (CONFIG.rapidFire && delay > 10 && delay < 2000) {
647                delay = Math.max(10, delay / CONFIG.fireRateMultiplier);
648            }
649            return originalSetInterval.call(this, callback, delay, ...args);
650        };
651        
652        window.setTimeout = function(callback, delay, ...args) {
653            if (CONFIG.rapidFire && delay > 10 && delay < 2000) {
654                delay = Math.max(10, delay / CONFIG.fireRateMultiplier);
655            }
656            return originalSetTimeout.call(this, callback, delay, ...args);
657        };
658        
659        // Patch requestAnimationFrame for speed hacks
660        const originalRAF = window.requestAnimationFrame;
661        window.requestAnimationFrame = function(callback) {
662            return originalRAF.call(this, function(timestamp) {
663                if (CONFIG.speedHack) {
664                    // Speed up game time
665                    timestamp *= CONFIG.speedMultiplier;
666                }
667                return callback(timestamp);
668            });
669        };
670        
671        console.log('[MEMORY] Game functions patched');
672    }
673
674    // ============================================
675    // SCAN FOR GAME OBJECTS
676    // ============================================
677    function scanForGameObjects() {
678        console.log('[SCAN] Scanning for game objects...');
679        
680        const checkInterval = setInterval(() => {
681            // Look for Unity instance
682            if (typeof unityInstance !== 'undefined' && !gameInstance) {
683                gameInstance = unityInstance;
684                console.log('[SCAN] Unity instance found!');
685                hookUnityInstance(gameInstance);
686            }
687            
688            // Look for game objects in window
689            const keys = Object.keys(window);
690            for (let key of keys) {
691                const obj = window[key];
692                if (obj && typeof obj === 'object') {
693                    // Look for player objects
694                    if (obj.player || obj.players || obj.localPlayer) {
695                        console.log('[SCAN] Found game object:', key);
696                        hookGameObject(obj);
697                    }
698                    
699                    // Look for weapon objects
700                    if (obj.weapon || obj.weapons || obj.currentWeapon) {
701                        console.log('[SCAN] Found weapon object:', key);
702                        hookWeaponObject(obj);
703                    }
704                }
705            }
706        }, 2000);
707        
708        // Stop after 30 seconds
709        setTimeout(() => clearInterval(checkInterval), 30000);
710    }
711
712    function hookUnityInstance(instance) {
713        console.log('[UNITY] Hooking Unity instance...');
714        
715        try {
716            // Try to access Unity's SendMessage function
717            if (instance.SendMessage) {
718                const originalSendMessage = instance.SendMessage;
719                instance.SendMessage = function(gameObject, method, value) {
720                    console.log('[UNITY] SendMessage:', gameObject, method, value);
721                    
722                    // Modify messages for hacks
723                    if (CONFIG.infiniteAmmo && method.toLowerCase().includes('ammo')) {
724                        value = 999;
725                    }
726                    
727                    return originalSendMessage.call(this, gameObject, method, value);
728                };
729            }
730        } catch (e) {
731            console.error('[UNITY] Error hooking:', e);
732        }
733    }
734
735    function hookGameObject(obj) {
736        try {
737            if (obj.player) {
738                const player = obj.player;
739                
740                // Hook speed
741                if (player.speed !== undefined) {
742                    Object.defineProperty(player, 'speed', {
743                        get: function() { 
744                            return this._speed * (CONFIG.speedHack ? CONFIG.speedMultiplier : 1); 
745                        },
746                        set: function(value) { 
747                            this._speed = value; 
748                        }
749                    });
750                }
751                
752                // Hook jump force
753                if (player.jumpForce !== undefined) {
754                    Object.defineProperty(player, 'jumpForce', {
755                        get: function() { 
756                            return this._jumpForce * (CONFIG.jumpBoost ? CONFIG.jumpMultiplier : 1); 
757                        },
758                        set: function(value) { 
759                            this._jumpForce = value; 
760                        }
761                    });
762                }
763            }
764        } catch (e) {
765            console.error('[HOOK] Error hooking game object:', e);
766        }
767    }
768
769    function hookWeaponObject(obj) {
770        try {
771            const weapon = obj.weapon || obj.currentWeapon;
772            if (!weapon) return;
773            
774            // Hook ammo
775            if (weapon.ammo !== undefined) {
776                Object.defineProperty(weapon, 'ammo', {
777                    get: function() { 
778                        return CONFIG.infiniteAmmo ? 999 : this._ammo; 
779                    },
780                    set: function(value) { 
781                        this._ammo = CONFIG.infiniteAmmo ? 999 : value; 
782                    }
783                });
784            }
785            
786            // Hook fire rate
787            if (weapon.fireRate !== undefined) {
788                Object.defineProperty(weapon, 'fireRate', {
789                    get: function() { 
790                        return this._fireRate * (CONFIG.rapidFire ? CONFIG.fireRateMultiplier : 1); 
791                    },
792                    set: function(value) { 
793                        this._fireRate = value; 
794                    }
795                });
796            }
797            
798            // Hook recoil
799            if (weapon.recoil !== undefined) {
800                Object.defineProperty(weapon, 'recoil', {
801                    get: function() { 
802                        return CONFIG.noRecoil ? 0 : this._recoil; 
803                    },
804                    set: function(value) { 
805                        this._recoil = value; 
806                    }
807                });
808            }
809        } catch (e) {
810            console.error('[HOOK] Error hooking weapon:', e);
811        }
812    }
813
814    // ============================================
815    // GUI CREATION
816    // ============================================
817    function createModMenu() {
818        const existing = document.getElementById('veckio-advanced-mod');
819        if (existing) existing.remove();
820        
821        const menu = document.createElement('div');
822        menu.id = 'veckio-advanced-mod';
823        menu.innerHTML = `
824            <div class="mod-header">
825                <span class="mod-title">⚡ VECK.IO ADVANCED MOD</span>
826                <div class="mod-controls">
827                    <button class="mod-minimize" id="mod-minimize">_</button>
828                    <button class="mod-close" id="mod-close">×</button>
829                </div>
830            </div>
831            <div class="mod-body" id="mod-body">
832                <div class="mod-section">
833                    <h3>⚔️ WEAPON HACKS</h3>
834                    <label><input type="checkbox" id="infinite-ammo" ${CONFIG.infiniteAmmo ? 'checked' : ''}> Infinite Ammo</label>
835                    <label><input type="checkbox" id="rapid-fire" ${CONFIG.rapidFire ? 'checked' : ''}> Rapid Fire</label>
836                    <label><input type="checkbox" id="no-recoil" ${CONFIG.noRecoil ? 'checked' : ''}> No Recoil</label>
837                </div>
838                
839                <div class="mod-section">
840                    <h3>🏃 MOVEMENT HACKS</h3>
841                    <label><input type="checkbox" id="speed-hack" ${CONFIG.speedHack ? 'checked' : ''}> Speed Hack</label>
842                    <label><input type="checkbox" id="jump-boost" ${CONFIG.jumpBoost ? 'checked' : ''}> Jump Boost</label>
843                </div>
844                
845                <div class="mod-section">
846                    <h3>👁️ VISUAL HACKS</h3>
847                    <label><input type="checkbox" id="esp-hack" ${CONFIG.esp ? 'checked' : ''}> ESP Wallhack</label>
848                </div>
849                
850                <div class="mod-section">
851                    <h3>⚙️ SETTINGS</h3>
852                    <div class="mod-slider-group">
853                        <label>Speed: <span id="speed-val">${CONFIG.speedMultiplier}x</span></label>
854                        <input type="range" id="speed-slider" min="1" max="10" step="0.5" value="${CONFIG.speedMultiplier}">
855                    </div>
856                    <div class="mod-slider-group">
857                        <label>Jump: <span id="jump-val">${CONFIG.jumpMultiplier}x</span></label>
858                        <input type="range" id="jump-slider" min="1" max="5" step="0.5" value="${CONFIG.jumpMultiplier}">
859                    </div>
860                    <div class="mod-slider-group">
861                        <label>Fire Rate: <span id="fire-val">${CONFIG.fireRateMultiplier}x</span></label>
862                        <input type="range" id="fire-slider" min="1" max="10" step="0.5" value="${CONFIG.fireRateMultiplier}">
863                    </div>
864                </div>
865                
866                <div class="mod-footer">
867                    <div class="mod-status">🟢 Active | Players: <span id="player-count">0</span></div>
868                    <div class="mod-hint">Press ~ or INSERT to toggle</div>
869                </div>
870            </div>
871        `;
872        
873        const style = document.createElement('style');
874        style.textContent = `
875            #veckio-advanced-mod {
876                position: fixed;
877                top: 20px;
878                right: 20px;
879                width: 300px;
880                background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
881                border: 2px solid #00ff88;
882                border-radius: 10px;
883                box-shadow: 0 10px 40px rgba(0, 255, 136, 0.4);
884                font-family: 'Consolas', 'Monaco', monospace;
885                color: #fff;
886                z-index: 999999;
887                user-select: none;
888            }
889            
890            .mod-header {
891                background: linear-gradient(90deg, #00ff88 0%, #00cc6a 100%);
892                padding: 10px 15px;
893                border-radius: 8px 8px 0 0;
894                display: flex;
895                justify-content: space-between;
896                align-items: center;
897                cursor: move;
898            }
899            
900            .mod-controls {
901                display: flex;
902                gap: 5px;
903            }
904            
905            .mod-title {
906                font-weight: bold;
907                font-size: 13px;
908                color: #000;
909                letter-spacing: 1px;
910            }
911            
912            .mod-minimize {
913                background: rgba(0,0,0,0.3);
914                border: none;
915                color: #000;
916                width: 22px;
917                height: 22px;
918                border-radius: 3px;
919                cursor: pointer;
920                font-weight: bold;
921            }
922            
923            .mod-minimize:hover {
924                background: rgba(0,0,0,0.5);
925            }
926            
927            .mod-close {
928                background: rgba(0,0,0,0.3);
929                border: none;
930                color: #000;
931                width: 22px;
932                height: 22px;
933                border-radius: 3px;
934                cursor: pointer;
935                font-weight: bold;
936                font-size: 18px;
937                line-height: 18px;
938            }
939            
940            .mod-close:hover {
941                background: rgba(255,0,0,0.5);
942            }
943            
944            .mod-body {
945                padding: 15px;
946                max-height: 500px;
947                overflow-y: auto;
948            }
949            
950            .mod-body.hidden {
951                display: none;
952            }
953            
954            .mod-section {
955                margin-bottom: 15px;
956                padding-bottom: 15px;
957                border-bottom: 1px solid rgba(0, 255, 136, 0.2);
958            }
959            
960            .mod-section:last-of-type {
961                border-bottom: none;
962            }
963            
964            .mod-section h3 {
965                margin: 0 0 10px 0;
966                font-size: 12px;
967                color: #00ff88;
968                text-transform: uppercase;
969            }
970            
971            .mod-section label {
972                display: block;
973                padding: 6px 8px;
974                margin: 4px 0;
975                background: rgba(0, 255, 136, 0.05);
976                border-radius: 4px;
977                cursor: pointer;
978                font-size: 12px;
979                transition: all 0.2s;
980            }
981            
982            .mod-section label:hover {
983                background: rgba(0, 255, 136, 0.15);
984            }
985            
986            .mod-section input[type="checkbox"] {
987                margin-right: 8px;
988                accent-color: #00ff88;
989            }
990            
991            .mod-slider-group {
992                margin: 10px 0;
993                padding: 8px;
994                background: rgba(0, 255, 136, 0.05);
995                border-radius: 4px;
996            }
997            
998            .mod-slider-group label {
999                display: block;
1000                font-size: 11px;
1001                color: #00ff88;
1002                margin-bottom: 6px;
1003                padding: 0;
1004                background: none;
1005            }
1006            
1007            .mod-slider-group input[type="range"] {
1008                width: 100%;
1009                height: 4px;
1010                background: rgba(255,255,255,0.1);
1011                border-radius: 2px;
1012                outline: none;
1013                cursor: pointer;
1014            }
1015            
1016            .mod-slider-group input[type="range"]::-webkit-slider-thumb {
1017                appearance: none;
1018                width: 14px;
1019                height: 14px;
1020                background: #00ff88;
1021                border-radius: 50%;
1022                cursor: pointer;
1023            }
1024            
1025            .mod-footer {
1026                margin-top: 15px;
1027                padding-top: 15px;
1028                border-top: 1px solid rgba(0, 255, 136, 0.2);
1029            }
1030            
1031            .mod-status {
1032                font-size: 11px;
1033                color: #00ff88;
1034                margin-bottom: 6px;
1035            }
1036            
1037            .mod-hint {
1038                font-size: 10px;
1039                color: #666;
1040                text-align: center;
1041            }
1042            
1043            .mod-body::-webkit-scrollbar {
1044                width: 5px;
1045            }
1046            
1047            .mod-body::-webkit-scrollbar-track {
1048                background: rgba(0,0,0,0.2);
1049            }
1050            
1051            .mod-body::-webkit-scrollbar-thumb {
1052                background: #00ff88;
1053                border-radius: 3px;
1054            }
1055        `;
1056        
1057        document.head.appendChild(style);
1058        document.body.appendChild(menu);
1059        
1060        makeDraggable(menu);
1061        setupEventListeners();
1062        
1063        console.log('[GUI] Mod menu created');
1064    }
1065
1066    function makeDraggable(element) {
1067        const header = element.querySelector('.mod-header');
1068        let isDragging = false;
1069        let offsetX, offsetY;
1070        
1071        header.addEventListener('mousedown', (e) => {
1072            if (e.target.classList.contains('mod-minimize') || e.target.classList.contains('mod-close')) return;
1073            isDragging = true;
1074            offsetX = e.clientX - element.offsetLeft;
1075            offsetY = e.clientY - element.offsetTop;
1076        });
1077        
1078        document.addEventListener('mousemove', (e) => {
1079            if (isDragging) {
1080                element.style.left = (e.clientX - offsetX) + 'px';
1081                element.style.top = (e.clientY - offsetY) + 'px';
1082                element.style.right = 'auto';
1083            }
1084        });
1085        
1086        document.addEventListener('mouseup', () => {
1087            isDragging = false;
1088        });
1089    }
1090
1091    function setupEventListeners() {
1092        // Minimize button
1093        document.getElementById('mod-minimize').addEventListener('click', () => {
1094            document.getElementById('mod-body').classList.toggle('hidden');
1095        });
1096        
1097        // Close button
1098        document.getElementById('mod-close').addEventListener('click', () => {
1099            const menu = document.getElementById('veckio-advanced-mod');
1100            if (menu) {
1101                menu.style.display = menu.style.display === 'none' ? 'block' : 'none';
1102            }
1103        });
1104        
1105        // Checkboxes
1106        document.getElementById('infinite-ammo').addEventListener('change', (e) => {
1107            CONFIG.infiniteAmmo = e.target.checked;
1108            saveSettings();
1109            console.log('[MOD] Infinite Ammo:', CONFIG.infiniteAmmo);
1110        });
1111        
1112        document.getElementById('rapid-fire').addEventListener('change', (e) => {
1113            CONFIG.rapidFire = e.target.checked;
1114            saveSettings();
1115            console.log('[MOD] Rapid Fire:', CONFIG.rapidFire);
1116        });
1117        
1118        document.getElementById('no-recoil').addEventListener('change', (e) => {
1119            CONFIG.noRecoil = e.target.checked;
1120            saveSettings();
1121            console.log('[MOD] No Recoil:', CONFIG.noRecoil);
1122        });
1123        
1124        document.getElementById('speed-hack').addEventListener('change', (e) => {
1125            CONFIG.speedHack = e.target.checked;
1126            saveSettings();
1127            console.log('[MOD] Speed Hack:', CONFIG.speedHack);
1128        });
1129        
1130        document.getElementById('jump-boost').addEventListener('change', (e) => {
1131            CONFIG.jumpBoost = e.target.checked;
1132            saveSettings();
1133            console.log('[MOD] Jump Boost:', CONFIG.jumpBoost);
1134        });
1135        
1136        document.getElementById('esp-hack').addEventListener('change', (e) => {
1137            CONFIG.esp = e.target.checked;
1138            saveSettings();
1139            if (CONFIG.esp) {
1140                createESPCanvas();
1141            } else {
1142                removeESPCanvas();
1143            }
1144            console.log('[MOD] ESP:', CONFIG.esp);
1145        });
1146        
1147        // Sliders
1148        document.getElementById('speed-slider').addEventListener('input', (e) => {
1149            CONFIG.speedMultiplier = parseFloat(e.target.value);
1150            document.getElementById('speed-val').textContent = CONFIG.speedMultiplier + 'x';
1151            saveSettings();
1152        });
1153        
1154        document.getElementById('jump-slider').addEventListener('input', (e) => {
1155            CONFIG.jumpMultiplier = parseFloat(e.target.value);
1156            document.getElementById('jump-val').textContent = CONFIG.jumpMultiplier + 'x';
1157            saveSettings();
1158        });
1159        
1160        document.getElementById('fire-slider').addEventListener('input', (e) => {
1161            CONFIG.fireRateMultiplier = parseFloat(e.target.value);
1162            document.getElementById('fire-val').textContent = CONFIG.fireRateMultiplier + 'x';
1163            saveSettings();
1164        });
1165        
1166        // Keyboard shortcut
1167        document.addEventListener('keydown', (e) => {
1168            if (e.key === 'Insert') {
1169                e.preventDefault();
1170                document.getElementById('mod-body').classList.toggle('hidden');
1171            }
1172            // Alternative: Use ~ key (tilde/backtick)
1173            if (e.key === '~' || e.key === '`') {
1174                e.preventDefault();
1175                const menu = document.getElementById('veckio-advanced-mod');
1176                if (menu) {
1177                    menu.style.display = menu.style.display === 'none' ? 'block' : 'none';
1178                }
1179            }
1180        });
1181        
1182        // Update player count
1183        setInterval(() => {
1184            const countEl = document.getElementById('player-count');
1185            if (countEl) {
1186                countEl.textContent = players.size;
1187            }
1188        }, 1000);
1189    }
1190
1191    // ============================================
1192    // INITIALIZATION
1193    // ============================================
1194    async function init() {
1195        console.log('[MOD] Initializing advanced mod menu...');
1196        
1197        await loadSettings();
1198        
1199        if (document.readyState === 'loading') {
1200            document.addEventListener('DOMContentLoaded', initAfterLoad);
1201        } else {
1202            initAfterLoad();
1203        }
1204    }
1205
1206    function initAfterLoad() {
1207        console.log('[MOD] Page loaded, starting initialization...');
1208        
1209        // Create GUI
1210        createModMenu();
1211        
1212        // Intercept WebGL
1213        interceptWebGL();
1214        
1215        // Intercept WebSocket
1216        interceptWebSocket();
1217        
1218        // Patch memory
1219        patchGameMemory();
1220        
1221        // Scan for game objects
1222        scanForGameObjects();
1223        
1224        // Create ESP if enabled
1225        if (CONFIG.esp) {
1226            setTimeout(createESPCanvas, 2000);
1227        }
1228        
1229        console.log('[MOD] ✅ Advanced mod menu fully initialized!');
1230        console.log('[MOD] Press INSERT to toggle menu');
1231    }
1232
1233    // Start initialization
1234    init();
1235
1236})();
Veck.io Mod Menu - Ultimate Hack Client | Robomonkey