Veck.io Mod Menu - Ultimate Hack Client

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

Size

42.5 KB

Version

1.1.1

Created

Feb 26, 2026

Updated

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