您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Professional toggleable wallhack (chams) GUI for Kirka.io with advanced crosshairs and stats HUD
javascript:(function() { // ==UserScript== // @name Emu's Chams GUI (Stats HUD) // @namespace EmuChams // @version 1.9 // @description Professional toggleable wallhack (chams) GUI for Kirka.io with advanced crosshairs and stats HUD // @author Emulation // @match *://kirka.io/* // @run-at document-start // @license MIT // ==/UserScript== (function () { // Settings const settings = { enabled: localStorage.getItem('chamsEnabled') !== 'false', theme: localStorage.getItem('chamsTheme') || 'obsidian-black', menuPosition: JSON.parse(localStorage.getItem('menuPosition')) || { left: '120px', top: '120px' }, menuVisible: true, // Always visible on load menuMinimized: localStorage.getItem('menuMinimized') === 'true', hudPosition: JSON.parse(localStorage.getItem('hudPosition')) || { left: '400px', top: '120px' }, crosshairType: localStorage.getItem('crosshairType') || 'None', crosshairSize: parseInt(localStorage.getItem('crosshairSize')) || 20, crosshairThickness: parseInt(localStorage.getItem('crosshairThickness')) || 2, crosshairColor: localStorage.getItem('crosshairColor') || '#00f0ff', crosshairOutline: localStorage.getItem('crosshairOutline') === 'true', crosshairOutlineThickness: parseFloat(localStorage.getItem('crosshairOutlineThickness')) || 1, crosshairOpacity: parseFloat(localStorage.getItem('crosshairOpacity')) || 1, crosshairRotation: parseInt(localStorage.getItem('crosshairRotation')) || 0, showFPS: localStorage.getItem('showFPS') === 'true', showLatency: localStorage.getItem('showLatency') === 'true', showFPSGraph: localStorage.getItem('showFPSGraph') === 'true', showLatencyGraph: localStorage.getItem('showLatencyGraph') === 'true', menuOpacity: parseFloat(localStorage.getItem('menuOpacity')) || 1, menuScale: parseFloat(localStorage.getItem('menuScale')) || 1 }; const modifiedMaterials = new WeakSet(); let notificationTimeout = null; const clientVersion = '1.9.0'; let menuVisible = settings.menuVisible; const notifications = []; let crosshairCanvas, crosshairCtx, statsCanvas, statsCtx; let lastFrameTime = performance.now(); let fps = 0, latency = 0; const fpsHistory = [], latencyHistory = []; const maxHistory = 60; // ~30s at 60fps // Save settings function saveSettings() { localStorage.setItem('chamsEnabled', settings.enabled); localStorage.setItem('chamsTheme', settings.theme); localStorage.setItem('menuPosition', JSON.stringify(settings.menuPosition)); localStorage.setItem('menuVisible', menuVisible); localStorage.setItem('menuMinimized', settings.menuMinimized); localStorage.setItem('hudPosition', JSON.stringify(settings.hudPosition)); localStorage.setItem('crosshairType', settings.crosshairType); localStorage.setItem('crosshairSize', settings.crosshairSize); localStorage.setItem('crosshairThickness', settings.crosshairThickness); localStorage.setItem('crosshairColor', settings.crosshairColor); localStorage.setItem('crosshairOutline', settings.crosshairOutline); localStorage.setItem('crosshairOutlineThickness', settings.crosshairOutlineThickness); localStorage.setItem('crosshairOpacity', settings.crosshairOpacity); localStorage.setItem('crosshairRotation', settings.crosshairRotation); localStorage.setItem('showFPS', settings.showFPS); localStorage.setItem('showLatency', settings.showLatency); localStorage.setItem('showFPSGraph', settings.showFPSGraph); localStorage.setItem('showLatencyGraph', settings.showLatencyGraph); localStorage.setItem('menuOpacity', settings.menuOpacity); localStorage.setItem('menuScale', settings.menuScale); } // Reset settings function resetSettings() { localStorage.clear(); settings.enabled = true; settings.theme = 'obsidian-black'; settings.menuPosition = { left: '120px', top: '120px' }; settings.menuVisible = true; settings.menuMinimized = false; settings.hudPosition = { left: '400px', top: '120px' }; settings.crosshairType = 'None'; settings.crosshairSize = 20; settings.crosshairThickness = 2; settings.crosshairColor = '#00f0ff'; settings.crosshairOutline = false; settings.crosshairOutlineThickness = 1; settings.crosshairOpacity = 1; settings.crosshairRotation = 0; settings.showFPS = false; settings.showLatency = false; settings.showFPSGraph = false; settings.showLatencyGraph = false; settings.menuOpacity = 1; settings.menuScale = 1; saveSettings(); showNotification('Settings reset to default'); location.reload(); } // Show notification function showNotification(message) { const notification = document.createElement('div'); notification.className = 'notification tooltip'; notification.textContent = message; notification.style.position = 'fixed'; notification.style.bottom = `${20 + notifications.length * 40}px`; notification.style.right = '20px'; notification.style.background = 'var(--bg-gradient)'; notification.style.border = '1px solid var(--accent-color)'; notification.style.color = 'var(--text-color)'; notification.style.padding = '6px 12px'; notification.style.borderRadius = '5px'; notification.style.boxShadow = '0 4px 15px var(--accent-shadow)'; notification.style.opacity = '0'; notification.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; notification.style.transform = 'translateX(20px)'; notification.style.zIndex = '999997'; notification.style.fontFamily = '"Inter", sans-serif'; notification.style.fontSize = '11px'; notification.style.backdropFilter = 'blur(12px)'; document.body.appendChild(notification); notifications.push(notification); setTimeout(() => { notification.style.opacity = '1'; notification.style.transform = 'translateX(0)'; }, 10); setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateX(20px)'; setTimeout(() => { notification.remove(); notifications.splice(notifications.indexOf(notification), 1); notifications.forEach((n, i) => { n.style.bottom = `${20 + i * 40}px`; }); }, 300); }, 2500); if (notificationTimeout) clearTimeout(notificationTimeout); notificationTimeout = setTimeout(() => {}, 100); } // Patch material for chams const patchMaterial = (material) => { if (!material || !material.map || !material.map.image) return; const isTarget = material.map.image.width === 64 && material.map.image.height === 64; if (!isTarget) return; if (settings.enabled && !modifiedMaterials.has(material)) { for (let key in material) { if (material[key] === 3) { material[key] = 1; modifiedMaterials.add(material); } } } else if (!settings.enabled && modifiedMaterials.has(material)) { for (let key in material) { if (material[key] === 1) { material[key] = 3; } } modifiedMaterials.delete(material); } }; // Hook Array.isArray to intercept material use const proxyHandler = { apply(target, thisArg, args) { patchMaterial(args[0]); return Reflect.apply(target, thisArg, args); } }; const originalIsArray = Array.isArray; Array.isArray = new Proxy(originalIsArray, proxyHandler); // Force material patching on any new materials dynamically const observeMaterials = () => { const interval = setInterval(() => { if (window.THREE) { const walk = (obj) => { if (!obj || typeof obj !== "object") return; if (obj.material) { const mat = obj.material; if (Array.isArray(mat)) mat.forEach(patchMaterial); else patchMaterial(mat); } for (const key in obj) { if (obj.hasOwnProperty(key)) walk(obj[key]); } }; walk(window); clearInterval(interval); } }, 1000); }; // Crosshair rendering function initCrosshairCanvas() { crosshairCanvas = document.createElement('canvas'); crosshairCanvas.id = 'crosshair-canvas'; crosshairCanvas.style.position = 'fixed'; crosshairCanvas.style.top = '0'; crosshairCanvas.style.left = '0'; crosshairCanvas.style.width = '100%'; crosshairCanvas.style.height = '100%'; crosshairCanvas.style.zIndex = '999998'; crosshairCanvas.style.pointerEvents = 'none'; document.body.appendChild(crosshairCanvas); crosshairCtx = crosshairCanvas.getContext('2d'); resizeCrosshair(); } function resizeCrosshair() { if (!crosshairCanvas) return; crosshairCanvas.width = window.innerWidth; crosshairCanvas.height = window.innerHeight; drawCrosshair(); } function drawCrosshair() { if (!crosshairCtx || !crosshairCanvas) return; crosshairCtx.clearRect(0, 0, crosshairCanvas.width, crosshairCanvas.height); if (settings.crosshairType === 'None') return; const centerX = crosshairCanvas.width / 2; const centerY = crosshairCanvas.height / 2; const size = settings.crosshairSize; const thickness = settings.crosshairThickness; const color = settings.crosshairColor; let rotation = settings.crosshairRotation * Math.PI / 180; if (settings.crosshairType === 'Dynamic Star') rotation += Date.now() / 1000; if (settings.crosshairType === 'Dynamic Circle') rotation = 0; crosshairCtx.save(); crosshairCtx.translate(centerX, centerY); crosshairCtx.rotate(rotation); crosshairCtx.globalAlpha = settings.crosshairOpacity; if (settings.crosshairOutline) { crosshairCtx.strokeStyle = '#000000'; crosshairCtx.lineWidth = thickness + settings.crosshairOutlineThickness * 2; drawCrosshairShape(true); } crosshairCtx.strokeStyle = color; crosshairCtx.fillStyle = color; crosshairCtx.lineWidth = thickness; drawCrosshairShape(false); crosshairCtx.restore(); function drawCrosshairShape(isOutline) { const method = isOutline ? 'stroke' : settings.crosshairType.includes('Dot') || settings.crosshairType === 'Circle' || settings.crosshairType === 'Triangle' ? 'fill' : 'stroke'; crosshairCtx.beginPath(); switch (settings.crosshairType) { case 'Dot': crosshairCtx.arc(0, 0, size / 5, 0, Math.PI * 2); break; case 'Cross': crosshairCtx.moveTo(-size / 2, 0); crosshairCtx.lineTo(-size / 4, 0); crosshairCtx.moveTo(size / 4, 0); crosshairCtx.lineTo(size / 2, 0); crosshairCtx.moveTo(0, -size / 2); crosshairCtx.lineTo(0, -size / 4); crosshairCtx.moveTo(0, size / 4); crosshairCtx.lineTo(0, size / 2); break; case 'Dynamic Dot': const pulseSize = size / 5 + Math.sin(Date.now() / 300) * (size / 10); crosshairCtx.arc(0, 0, pulseSize, 0, Math.PI * 2); break; case 'Circle': crosshairCtx.arc(0, 0, size / 2, 0, Math.PI * 2); break; case 'Plus': crosshairCtx.moveTo(-size / 2, 0); crosshairCtx.lineTo(size / 2, 0); crosshairCtx.moveTo(0, -size / 2); crosshairCtx.lineTo(0, size / 2); break; case 'T-Shape': crosshairCtx.moveTo(-size / 2, -size / 2); crosshairCtx.lineTo(size / 2, -size / 2); crosshairCtx.moveTo(0, -size / 2); crosshairCtx.lineTo(0, size / 2); break; case 'Gap Cross': crosshairCtx.moveTo(-size / 2, -size / 2); crosshairCtx.lineTo(-size / 4, -size / 4); crosshairCtx.moveTo(size / 4, size / 4); crosshairCtx.lineTo(size / 2, size / 2); crosshairCtx.moveTo(-size / 2, size / 2); crosshairCtx.lineTo(-size / 4, size / 4); crosshairCtx.moveTo(size / 4, -size / 4); crosshairCtx.lineTo(size / 2, -size / 2); break; case 'Star': for (let i = 0; i < 8; i++) { const angle = i * Math.PI / 4; const r = i % 2 === 0 ? size / 2 : size / 4; crosshairCtx.lineTo(Math.cos(angle) * r, Math.sin(angle) * r); } crosshairCtx.closePath(); break; case 'Triangle': crosshairCtx.moveTo(0, -size / 2); crosshairCtx.lineTo(size / 2, size / 2); crosshairCtx.lineTo(-size / 2, size / 2); crosshairCtx.closePath(); break; case 'Dynamic Circle': const dynamicRadius = size / 2 + Math.sin(Date.now() / 500) * (size / 10); crosshairCtx.arc(0, 0, dynamicRadius, 0, Math.PI * 2); break; case 'Dynamic Star': for (let i = 0; i < 8; i++) { const angle = i * Math.PI / 4; const r = i % 2 === 0 ? size / 2 : size / 4; crosshairCtx.lineTo(Math.cos(angle) * r, Math.sin(angle) * r); } crosshairCtx.closePath(); break; } crosshairCtx[method](); } } // Stats rendering function initStatsCanvas() { statsCanvas = document.createElement('canvas'); statsCanvas.id = 'stats-canvas'; statsCanvas.style.width = '100%'; statsCanvas.style.height = '80px'; statsCanvas.style.display = 'block'; document.querySelector('#emu-stats-hud')?.appendChild(statsCanvas); statsCtx = statsCanvas.getContext('2d'); resizeStats(); } function resizeStats() { if (!statsCanvas || !statsCanvas.parentElement) return; statsCanvas.width = statsCanvas.parentElement.offsetWidth * devicePixelRatio; statsCanvas.height = 80 * devicePixelRatio; statsCanvas.style.transform = `scale(${1 / devicePixelRatio})`; statsCanvas.style.transformOrigin = 'top left'; drawStats(); } function drawStats() { if (!statsCtx || !statsCanvas) return; statsCtx.clearRect(0, 0, statsCanvas.width, statsCanvas.height); if (!settings.showFPSGraph && !settings.showLatencyGraph) return; const width = statsCanvas.width; const height = statsCanvas.height; const step = width / maxHistory; if (settings.showFPSGraph) { statsCtx.strokeStyle = '#00ff00'; statsCtx.lineWidth = 2; statsCtx.beginPath(); fpsHistory.forEach((value, i) => { const y = height - (value / 120) * height / 2; if (i === 0) statsCtx.moveTo(i * step, y); else statsCtx.lineTo(i * step, y); }); statsCtx.stroke(); } if (settings.showLatencyGraph) { statsCtx.strokeStyle = '#ff0000'; statsCtx.lineWidth = 2; statsCtx.beginPath(); latencyHistory.forEach((value, i) => { const y = height - (value / 200) * height / 2; if (i === 0) statsCtx.moveTo(i * step, y); else statsCtx.lineTo(i * step, y); }); statsCtx.stroke(); } } // Update stats function updateStats() { const now = performance.now(); const delta = now - lastFrameTime; fps = Math.round(1000 / delta); lastFrameTime = now; // Simulate latency (Kirka.io doesn't expose WebSocket directly) latency = Math.round(50 + Math.random() * 50); fpsHistory.push(fps); latencyHistory.push(latency); if (fpsHistory.length > maxHistory) fpsHistory.shift(); if (latencyHistory.length > maxHistory) latencyHistory.shift(); drawStats(); updateHUD(); } // Update HUD function updateHUD() { const hud = document.querySelector('#emu-stats-hud'); if (!hud) return; const counters = hud.querySelector('#stats-counters'); let html = ''; if (settings.showFPS) { html += `<span class="status-item tooltip" title="Frames per second"><i class="fas fa-tachometer-alt"></i> FPS: <span class="status-value">${fps}</span></span>`; } if (settings.showLatency) { html += `<span class="status-item tooltip" title="Network latency"><i class="fas fa-network-wired"></i> Latency: <span class="status-value">${latency}ms</span></span>`; } counters.innerHTML = html; const isVisible = settings.showFPS || settings.showLatency || settings.showFPSGraph || settings.showLatencyGraph; hud.style.display = isVisible ? 'block' : 'none'; if (isVisible && !statsCanvas && (settings.showFPSGraph || settings.showLatencyGraph)) { initStatsCanvas(); } } // Update status bar function updateStatus() { const statusBar = document.querySelector('#status-bar'); if (!statusBar) return; statusBar.innerHTML = ` <span class="status-item tooltip" title="Chams status"><i class="fas fa-eye"></i> Chams: <span class="${settings.enabled ? 'active' : ''}">${settings.enabled ? 'ON' : 'OFF'}</span></span> <span class="status-item tooltip" title="Crosshair type"><i class="fas fa-crosshairs"></i> Crosshair: <span class="status-value">${settings.crosshairType}</span></span> `; } // Animation loop function animate() { updateStats(); drawCrosshair(); requestAnimationFrame(animate); } // GUI creation function function createGUI() { // Inject styles const styleSheet = document.createElement('style'); styleSheet.id = 'emuChamsStyle'; styleSheet.innerHTML = ` @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Orbitron:wght@700;800&display=swap'); @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css'); :root { --accent-color: #00ccff; --accent-shadow: rgba(0, 204, 255, 0.4); --bg-gradient: linear-gradient(to bottom, rgba(0, 10, 20, 0.9), rgba(5, 15, 30, 0.9)); --btn-bg: rgba(20, 30, 50, 0.7); --btn-hover-bg: rgba(0, 204, 255, 0.3); --text-color: #f0f6ff; --border-color: #1a2538; --divider-color: #2e3a50; } [data-theme="obsidian-black"] { --accent-color: #00ccff; --accent-shadow: rgba(0, 204, 255, 0.4); --bg-gradient: linear-gradient(to bottom, rgba(0, 10, 20, 0.9), rgba(5, 15, 30, 0.9)); --btn-bg: rgba(20, 30, 50, 0.7); --btn-hover-bg: rgba(0, 204, 255, 0.3); --text-color: #f0f6ff; --border-color: #1a2538; --divider-color: #2e3a50; } [data-theme="arctic-white"] { --accent-color: #0066cc; --accent-shadow: rgba(0, 102, 204, 0.3); --bg-gradient: linear-gradient(to bottom, rgba(255, 255, 255, 0.9), rgba(235, 245, 255, 0.9)); --btn-bg: rgba(245, 250, 255, 0.4); --btn-hover-bg: rgba(0, 102, 204, 0.2); --text-color: #1a2530; --border-color: #d5e0f0; --divider-color: #e0e5f0; } [data-theme="crimson-pulse"] { --accent-color: #ff3333; --accent-shadow: rgba(255, 51, 51, 0.3); --bg-gradient: linear-gradient(to bottom, rgba(45, 0, 0, 0.9), rgba(30, 5, 5, 0.9)); --btn-bg: rgba(60, 15, 15, 0.7); --btn-hover-bg: rgba(255, 51, 51, 0.5); --text-color: #ffcc99; --border-color: #4a2525; --divider-color: #5a3f3f; } [data-theme="toxic-green"] { --accent-color: #00ff33; --accent-shadow: rgba(0, 255, 51, 0.3); --bg-gradient: linear-gradient(to bottom, rgba(0, 40, 0, 0.9), rgba(5, 25, 0, 0.9)); --btn-bg: rgba(20, 60, 20, 0.7); --btn-hover-bg: rgba(0, 255, 51, 0.2); --text-color: #ccff99; --border-color: #2f4a2f; --divider-color: #3f5a3f; } #emu-chams-gui { position: absolute; width: 260px; background: var(--bg-gradient); backdrop-filter: blur(12px); border: 1px solid var(--accent-color); border-radius: 8px; box-shadow: 0 4px 25px var(--accent-shadow), inset 0 0 5px rgba(255, 255, 255, 0.1); z-index: 999999; font-family: 'Inter', sans-serif; color: var(--text-color); transition: opacity 0.3s ease, transform 0.3s ease, height 0.3s ease; left: ${settings.menuPosition.left}; top: ${settings.menuPosition.top}; opacity: ${settings.menuOpacity}; transform: scale(${settings.menuScale}); } #emu-chams-gui.hidden { opacity: 0; transform: scale(${settings.menuScale * 0.95}); pointer-events: none; } #emu-chams-gui.minimized { height: 32px; overflow: hidden; } #emu-chams-gui.dragging, #emu-stats-hud.dragging { cursor: grabbing; } #emu-stats-hud { position: absolute; width: 200px; background: var(--bg-gradient); backdrop-filter: blur(8px); border: 1px solid var(--accent-color); border-radius: 6px; box-shadow: 0 4px 15px var(--accent-shadow); z-index: 999996; font-family: 'Inter', sans-serif; color: var(--text-color); left: ${settings.hudPosition.left}; top: ${settings.hudPosition.top}; padding: 8px; cursor: move; display: ${settings.showFPS || settings.showLatency || settings.showFPSGraph || settings.showLatencyGraph ? 'block' : 'none'}; } #stats-counters { display: flex; justify-content: space-between; margin-bottom: 8px; } #gui-header { padding: 8px; background: rgba(0, 0, 0, 0.3); display: flex; align-items: center; border-bottom: 1px solid var(--border-color); cursor: move; } #gui-logo { width: 16px; height: 16px; margin-right: 8px; background: conic-gradient(from 45deg, transparent 0deg 90deg, var(--accent-color) 90deg 180deg, transparent 180deg 270deg, var(--accent-color) 270deg 360deg); clip-path: polygon(50% 0%, 100% 100%, 0% 100%); transform: rotate(45deg); animation: spin 4s linear infinite; } #gui-title { font-size: 14px; font-weight: 800; font-family: 'Orbitron', sans-serif; background: linear-gradient(45deg, var(--accent-color), #ff4081); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 3px var(--accent-shadow); flex-grow: 1; } #gui-badge { font-size: 8px; padding: 2px 6px; background: linear-gradient(45deg, var(--accent-color), #ff4081); color: var(--btn-bg); border-radius: 3px; text-transform: uppercase; font-weight: 800; } #gui-controls button { background: none; border: none; color: var(--text-color); font-size: 12px; padding: 4px; cursor: pointer; transition: color 0.2s, transform 0.2s; margin-left: 4px; } #gui-controls button:hover { color: var(--accent-color); transform: scale(1.1); } #gui-tabs { display: flex; background: rgba(0, 0, 0, 0.4); border-bottom: 1px solid var(--border-color); } #gui-tabs button { flex: 1; background: transparent; border: none; color: var(--text-color); padding: 6px; cursor: pointer; font-size: 11px; font-weight: 700; font-family: 'Orbitron', sans-serif; transition: all 0.2s; text-transform: uppercase; } #gui-tabs button:hover { background: var(--btn-hover-bg); } #gui-tabs button.active { color: var(--accent-color); background: var(--btn-bg); border-bottom: 2px solid var(--accent-color); } #gui-body { padding: 10px; max-height: 300px; overflow-y: auto; } #gui-body::-webkit-scrollbar { width: 6px; } #gui-body::-webkit-scrollbar-track { background: var(--btn-bg); border-radius: 3px; } #gui-body::-webkit-scrollbar-thumb { background: var(--accent-color); border-radius: 3px; } .tab-content { display: none; animation: fadeIn 0.3s ease; } .tab-content.active { display: block; } @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } } .toggle-btn { width: 100%; background: var(--btn-bg); border: 1px solid var(--accent-color); color: var(--text-color); font-family: 'Orbitron', sans-serif; font-size: 12px; font-weight: 700; padding: 8px; border-radius: 6px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; gap: 5px; text-transform: uppercase; margin-bottom: 10px; } .toggle-btn:hover { background: var(--btn-hover-bg); box-shadow: 0 0 10px var(--accent-shadow); transform: scale(1.02); } .toggle-btn:active { transform: scale(0.98); } .toggle-btn.enabled { background: var(--accent-color); color: var(--btn-bg); } .cheat-btn { width: 100%; background: var(--btn-bg); border: 1px solid var(--border-color); color: var(--text-color); font-family: 'Orbitron', sans-serif; font-size: 11px; font-weight: 700; padding: 6px; border-radius: 6px; cursor: pointer; transition: all 0.3s ease; text-transform: uppercase; margin: 5px 0; } .cheat-btn:hover { background: var(--btn-hover-bg); box-shadow: 0 0 10px var(--accent-shadow); transform: scale(1.02); } .cheat-btn:active { transform: scale(0.98); } .cheat-btn.active { background: var(--accent-color); color: var(--btn-bg); } select, input[type="color"], input[type="range"] { width: 100%; background: var(--btn-bg); border: 1px solid var(--border-color); color: var(--text-color); font-family: 'Inter', sans-serif; font-size: 12px; padding: 6px; border-radius: 6px; margin: 5px 0; cursor: pointer; } input[type="range"] { -webkit-appearance: none; height: 6px; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; background: var(--accent-color); border-radius: 50%; border: 1px solid var(--border-color); cursor: pointer; } label { font-size: 11px; font-weight: 500; margin: 5px 0 2px; display: block; } .slider-value { font-size: 11px; margin-left: 5px; } #status-bar { padding: 6px 10px; background: rgba(0, 0, 0, 0.4); border-top: 1px solid var(--border-color); font-size: 10px; color: var(--text-color); display: flex; flex-wrap: wrap; gap: 5px; } .status-item { background: var(--btn-bg); padding: 2px 8px; border-radius: 10px; display: flex; align-items: center; gap: 4px; cursor: pointer; } .status-item:hover { background: var(--btn-hover-bg); } .status-value, .active { color: var(--accent-color); font-weight: 600; } .notification { position: fixed; bottom: 20px; right: 20px; background: var(--bg-gradient); border: 1px solid var(--accent-color); color: var(--text-color); padding: 6px 12px; border-radius: 5px; box-shadow: 0 4px 15px var(--accent-shadow); opacity: 0; transition: opacity 0.3s ease, transform 0.3s ease; transform: translateX(20px); z-index: 999997; font-family: 'Inter', sans-serif; font-size: 11px; backdropFilter: blur(12px); } .tooltip::after { content: attr(title); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--btn-bg); color: var(--text-color); padding: 3px 6px; border-radius: 4px; font-size: 10px; white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.2s; z-index: 10; border: 1px solid var(--border-color); } .tooltip:hover::after { opacity: 1; } @keyframes spin { to { transform: rotate(405deg); } } hr { border: 0; border-top: 1px solid var(--divider-color); margin: 8px 0; } `; document.head.appendChild(styleSheet); // Create GUI const gui = document.createElement('div'); gui.id = 'emu-chams-gui'; gui.dataset.theme = settings.theme; gui.classList.toggle('hidden', !menuVisible); gui.classList.toggle('minimized', settings.menuMinimized); const header = document.createElement('div'); header.id = 'gui-header'; header.innerHTML = ` <div id="gui-logo"></div> <span id="gui-title">Emu's Chams Client</span> <span id="gui-badge">PREMIUM</span> <div id="gui-controls"> <button id="minimize-btn" aria-label="Minimize menu"><i class="fas fa-${settings.menuMinimized ? 'plus' : 'minus'}"></i></button> <button id="close-btn" aria-label="Close menu"><i class="fas fa-times"></i></button> </div> `; const tabs = document.createElement('div'); tabs.id = 'gui-tabs'; tabs.innerHTML = ` <button class="tab-btn active" data-tab="main">Main</button> <button class="tab-btn" data-tab="crosshairs">Crosshairs</button> <button class="tab-btn" data-tab="settings">Settings</button> `; const body = document.createElement('div'); body.id = 'gui-body'; const statusBar = document.createElement('div'); statusBar.id = 'status-bar'; gui.appendChild(header); gui.appendChild(tabs); gui.appendChild(body); gui.appendChild(statusBar); document.body.appendChild(gui); // Create Stats HUD const statsHud = document.createElement('div'); statsHud.id = 'emu-stats-hud'; statsHud.innerHTML = ` <div id="stats-counters"></div> `; document.body.appendChild(statsHud); // Tab content const tabContents = { main: ` <button id="toggle-chams" class="toggle-btn ${settings.enabled ? 'enabled' : ''} tooltip" title="Toggle wallhacks"> <i class="fas fa-eye"></i> ${settings.enabled ? 'Disable' : 'Enable'} Chams </button> <hr> <select id="theme-selector" title="Select theme"> <option value="obsidian-black" ${settings.theme === 'obsidian-black' ? 'selected' : ''}>Obsidian Black</option> <option value="arctic-white" ${settings.theme === 'arctic-white' ? 'selected' : ''}>Arctic White</option> <option value="crimson-pulse" ${settings.theme === 'crimson-pulse' ? 'selected' : ''}>Crimson Pulse</option> <option value="toxic-green" ${settings.theme === 'toxic-green' ? 'selected' : ''}>Toxic Green</option> </select> `, crosshairs: ` <label>Crosshair Type</label> <select id="crosshair-selector" title="Select crosshair style"> <option value="None" ${settings.crosshairType === 'None' ? 'selected' : ''}>None</option> <option value="Dot" ${settings.crosshairType === 'Dot' ? 'selected' : ''}>Dot</option> <option value="Cross" ${settings.crosshairType === 'Cross' ? 'selected' : ''}>Cross</option> <option value="Dynamic Dot" ${settings.crosshairType === 'Dynamic Dot' ? 'selected' : ''}>Dynamic Dot</option> <option value="Circle" ${settings.crosshairType === 'Circle' ? 'selected' : ''}>Circle</option> <option value="Plus" ${settings.crosshairType === 'Plus' ? 'selected' : ''}>Plus</option> <option value="T-Shape" ${settings.crosshairType === 'T-Shape' ? 'selected' : ''}>T-Shape</option> <option value="Gap Cross" ${settings.crosshairType === 'Gap Cross' ? 'selected' : ''}>Gap Cross</option> <option value="Star" ${settings.crosshairType === 'Star' ? 'selected' : ''}>Star</option> <option value="Triangle" ${settings.crosshairType === 'Triangle' ? 'selected' : ''}>Triangle</option> <option value="Dynamic Circle" ${settings.crosshairType === 'Dynamic Circle' ? 'selected' : ''}>Dynamic Circle</option> <option value="Dynamic Star" ${settings.crosshairType === 'Dynamic Star' ? 'selected' : ''}>Dynamic Star</option> </select> <label>Crosshair Size: <span id="crosshair-size-value">${settings.crosshairSize}px</span></label> <input type="range" id="crosshair-size" min="5" max="100" step="5" value="${settings.crosshairSize}"> <label>Crosshair Thickness: <span id="crosshair-thickness-value">${settings.crosshairThickness}px</span></label> <input type="range" id="crosshair-thickness" min="1" max="10" step="1" value="${settings.crosshairThickness}"> <label>Crosshair Color</label> <input type="color" id="crosshair-color" value="${settings.crosshairColor}"> <button id="toggle-outline" class="cheat-btn ${settings.crosshairOutline ? 'active' : ''} tooltip" title="Toggle black outline">Outline: ${settings.crosshairOutline ? 'ON' : 'OFF'}</button> <label>Outline Thickness: <span id="crosshair-outline-thickness-value">${settings.crosshairOutlineThickness}px</span></label> <input type="range" id="crosshair-outline-thickness" min="0" max="5" step="0.5" value="${settings.crosshairOutlineThickness}" ${settings.crosshairOutline ? '' : 'disabled'}> <label>Crosshair Opacity: <span id="crosshair-opacity-value">${settings.crosshairOpacity}</span></label> <input type="range" id="crosshair-opacity" min="0.1" max="1" step="0.1" value="${settings.crosshairOpacity}"> <label>Crosshair Rotation: <span id="crosshair-rotation-value">${settings.crosshairRotation}°</span></label> <input type="range" id="crosshair-rotation" min="0" max="360" step="5" value="${settings.crosshairRotation}"> `, settings: ` <button id="toggle-fps" class="cheat-btn ${settings.showFPS ? 'active' : ''} tooltip" title="Show FPS counter">FPS Counter: ${settings.showFPS ? 'ON' : 'OFF'}</button> <button id="toggle-latency" class="cheat-btn ${settings.showLatency ? 'active' : ''} tooltip" title="Show latency counter">Latency Counter: ${settings.showLatency ? 'ON' : 'OFF'}</button> <button id="toggle-fps-graph" class="cheat-btn ${settings.showFPSGraph ? 'active' : ''} tooltip" title="Show FPS graph">FPS Graph: ${settings.showFPSGraph ? 'ON' : 'OFF'}</button> <button id="toggle-latency-graph" class="cheat-btn ${settings.showLatencyGraph ? 'active' : ''} tooltip" title="Show latency graph">Latency Graph: ${settings.showLatencyGraph ? 'ON' : 'OFF'}</button> <hr> <label>Menu Opacity: <span id="menu-opacity-value">${settings.menuOpacity}</span></label> <input type="range" id="menu-opacity" min="0.5" max="1" step="0.05" value="${settings.menuOpacity}"> <label>Menu Scale: <span id="menu-scale-value">${settings.menuScale}</span></label> <input type="range" id="menu-scale" min="0.8" max="1.5" step="0.05" value="${settings.menuScale}"> <hr> <button id="reset-settings" class="cheat-btn tooltip" title="Reset all settings to default">Reset Settings</button> ` }; let currentTab = 'main'; function updateTabContent() { body.innerHTML = tabContents[currentTab]; if (currentTab === 'main') { const toggleBtn = document.getElementById('toggle-chams'); toggleBtn.onclick = () => { settings.enabled = !settings.enabled; toggleBtn.classList.toggle('enabled', settings.enabled); toggleBtn.innerHTML = `<i class="fas fa-eye"></i> ${settings.enabled ? 'Disable' : 'Enable'} Chams`; showNotification(`Chams ${settings.enabled ? 'enabled' : 'disabled'}`); observeMaterials(); updateStatus(); saveSettings(); }; const themeSelector = document.getElementById('theme-selector'); themeSelector.onchange = () => { settings.theme = themeSelector.value; gui.dataset.theme = settings.theme; statsHud.dataset.theme = settings.theme; showNotification(`Theme changed to ${themeSelector.options[themeSelector.selectedIndex].text}`); saveSettings(); updateStatus(); }; } else if (currentTab === 'crosshairs') { const crosshairSelector = document.getElementById('crosshair-selector'); crosshairSelector.onchange = () => { settings.crosshairType = crosshairSelector.value; showNotification(`Crosshair set to ${settings.crosshairType}`); drawCrosshair(); updateStatus(); saveSettings(); }; const sizeSlider = document.getElementById('crosshair-size'); const sizeValue = document.getElementById('crosshair-size-value'); sizeSlider.oninput = () => { settings.crosshairSize = parseInt(sizeSlider.value); sizeValue.textContent = `${settings.crosshairSize}px`; showNotification(`Crosshair size set to ${settings.crosshairSize}px`); drawCrosshair(); saveSettings(); }; const thicknessSlider = document.getElementById('crosshair-thickness'); const thicknessValue = document.getElementById('crosshair-thickness-value'); thicknessSlider.oninput = () => { settings.crosshairThickness = parseInt(thicknessSlider.value); thicknessValue.textContent = `${settings.crosshairThickness}px`; showNotification(`Crosshair thickness set to ${settings.crosshairThickness}px`); drawCrosshair(); saveSettings(); }; const colorPicker = document.getElementById('crosshair-color'); colorPicker.onchange = () => { settings.crosshairColor = colorPicker.value; showNotification(`Crosshair color set to ${colorPicker.value}`); drawCrosshair(); saveSettings(); }; const outlineToggle = document.getElementById('toggle-outline'); const outlineThicknessSlider = document.getElementById('crosshair-outline-thickness'); outlineToggle.onclick = () => { settings.crosshairOutline = !settings.crosshairOutline; outlineToggle.classList.toggle('active', settings.crosshairOutline); outlineToggle.textContent = `Outline: ${settings.crosshairOutline ? 'ON' : 'OFF'}`; outlineThicknessSlider.disabled = !settings.crosshairOutline; showNotification(`Crosshair outline ${settings.crosshairOutline ? 'enabled' : 'disabled'}`); drawCrosshair(); saveSettings(); }; const outlineThicknessValue = document.getElementById('crosshair-outline-thickness-value'); outlineThicknessSlider.oninput = () => { settings.crosshairOutlineThickness = parseFloat(outlineThicknessSlider.value); outlineThicknessValue.textContent = `${settings.crosshairOutlineThickness}px`; showNotification(`Outline thickness set to ${settings.crosshairOutlineThickness}px`); drawCrosshair(); saveSettings(); }; const opacitySlider = document.getElementById('crosshair-opacity'); const opacityValue = document.getElementById('crosshair-opacity-value'); opacitySlider.oninput = () => { settings.crosshairOpacity = parseFloat(opacitySlider.value); opacityValue.textContent = settings.crosshairOpacity.toFixed(1); showNotification(`Crosshair opacity set to ${settings.crosshairOpacity}`); drawCrosshair(); saveSettings(); }; const rotationSlider = document.getElementById('crosshair-rotation'); const rotationValue = document.getElementById('crosshair-rotation-value'); rotationSlider.oninput = () => { settings.crosshairRotation = parseInt(rotationSlider.value); rotationValue.textContent = `${settings.crosshairRotation}°`; showNotification(`Crosshair rotation set to ${settings.crosshairRotation}°`); drawCrosshair(); saveSettings(); }; } else if (currentTab === 'settings') { const fpsToggle = document.getElementById('toggle-fps'); fpsToggle.onclick = () => { settings.showFPS = !settings.showFPS; fpsToggle.classList.toggle('active', settings.showFPS); fpsToggle.textContent = `FPS Counter: ${settings.showFPS ? 'ON' : 'OFF'}`; showNotification(`FPS counter ${settings.showFPS ? 'enabled' : 'disabled'}`); updateHUD(); saveSettings(); }; const latencyToggle = document.getElementById('toggle-latency'); latencyToggle.onclick = () => { settings.showLatency = !settings.showLatency; latencyToggle.classList.toggle('active', settings.showLatency); latencyToggle.textContent = `Latency Counter: ${settings.showLatency ? 'ON' : 'OFF'}`; showNotification(`Latency counter ${settings.showLatency ? 'enabled' : 'disabled'}`); updateHUD(); saveSettings(); }; const fpsGraphToggle = document.getElementById('toggle-fps-graph'); fpsGraphToggle.onclick = () => { settings.showFPSGraph = !settings.showFPSGraph; fpsGraphToggle.classList.toggle('active', settings.showFPSGraph); fpsGraphToggle.textContent = `FPS Graph: ${settings.showFPSGraph ? 'ON' : 'OFF'}`; showNotification(`FPS graph ${settings.showFPSGraph ? 'enabled' : 'disabled'}`); updateHUD(); saveSettings(); }; const latencyGraphToggle = document.getElementById('toggle-latency-graph'); latencyGraphToggle.onclick = () => { settings.showLatencyGraph = !settings.showLatencyGraph; latencyGraphToggle.classList.toggle('active', settings.showLatencyGraph); latencyGraphToggle.textContent = `Latency Graph: ${settings.showLatencyGraph ? 'ON' : 'OFF'}`; showNotification(`Latency graph ${settings.showLatencyGraph ? 'enabled' : 'disabled'}`); updateHUD(); saveSettings(); }; const opacitySlider = document.getElementById('menu-opacity'); const opacityValue = document.getElementById('menu-opacity-value'); opacitySlider.oninput = () => { settings.menuOpacity = parseFloat(opacitySlider.value); opacityValue.textContent = settings.menuOpacity.toFixed(2); gui.style.opacity = settings.menuOpacity; showNotification(`Menu opacity set to ${settings.menuOpacity}`); saveSettings(); }; const scaleSlider = document.getElementById('menu-scale'); const scaleValue = document.getElementById('menu-scale-value'); scaleSlider.oninput = () => { settings.menuScale = parseFloat(scaleSlider.value); scaleValue.textContent = settings.menuScale.toFixed(2); gui.style.transform = `scale(${settings.menuScale})`; showNotification(`Menu scale set to ${settings.menuScale}`); saveSettings(); }; const resetBtn = document.getElementById('reset-settings'); resetBtn.onclick = () => { resetSettings(); }; } } // Tab switching tabs.querySelectorAll('.tab-btn').forEach(btn => { btn.onclick = () => { currentTab = btn.dataset.tab; tabs.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); updateTabContent(); showNotification(`Switched to ${currentTab} tab`); }; }); // Initial tab content updateTabContent(); // Event listeners const minimizeBtn = document.getElementById('minimize-btn'); minimizeBtn.onclick = () => { settings.menuMinimized = !settings.menuMinimized; gui.classList.toggle('minimized', settings.menuMinimized); minimizeBtn.innerHTML = `<i class="fas fa-${settings.menuMinimized ? 'plus' : 'minus'}"></i>`; showNotification(`Menu ${settings.menuMinimized ? 'minimized' : 'restored'}`); saveSettings(); }; const closeBtn = document.getElementById('close-btn'); closeBtn.onclick = () => { menuVisible = false; gui.classList.add('hidden'); showNotification('Menu closed'); saveSettings(); }; // Draggable GUI let isDragging = false, offsetX = 0, offsetY = 0; header.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - parseFloat(gui.style.left || 120); offsetY = e.clientY - parseFloat(gui.style.top || 120); gui.classList.add('dragging'); document.body.style.userSelect = 'none'; }); window.addEventListener('mousemove', (e) => { if (isDragging) { let newX = e.clientX - offsetX; let newY = e.clientY - offsetY; newX = Math.max(0, Math.min(newX, window.innerWidth - gui.offsetWidth * settings.menuScale)); newY = Math.max(0, Math.min(newY, window.innerHeight - gui.offsetHeight * settings.menuScale)); gui.style.left = `${newX}px`; gui.style.top = `${newY}px`; settings.menuPosition = { left: `${newX}px`, top: `${newY}px` }; saveSettings(); } }); window.addEventListener('mouseup', () => { isDragging = false; gui.classList.remove('dragging'); document.body.style.userSelect = ''; }); // Draggable HUD let hudIsDragging = false, hudOffsetX = 0, hudOffsetY = 0; statsHud.addEventListener('mousedown', (e) => { hudIsDragging = true; hudOffsetX = e.clientX - parseFloat(statsHud.style.left || 400); hudOffsetY = e.clientY - parseFloat(statsHud.style.top || 120); statsHud.classList.add('dragging'); document.body.style.userSelect = 'none'; }); window.addEventListener('mousemove', (e) => { if (hudIsDragging) { let newX = e.clientX - hudOffsetX; let newY = e.clientY - hudOffsetY; newX = Math.max(0, Math.min(newX, window.innerWidth - statsHud.offsetWidth)); newY = Math.max(0, Math.min(newY, window.innerHeight - statsHud.offsetHeight)); statsHud.style.left = `${newX}px`; statsHud.style.top = `${newY}px`; settings.hudPosition = { left: `${newX}px`, top: `${newY}px` }; saveSettings(); } }); window.addEventListener('mouseup', () => { hudIsDragging = false; statsHud.classList.remove('dragging'); document.body.style.userSelect = ''; }); // Toggle menu with semicolon document.addEventListener('keydown', (e) => { if (e.key === ';') { menuVisible = !menuVisible; gui.classList.toggle('hidden', !menuVisible); showNotification(`Menu ${menuVisible ? 'opened' : 'closed'}`); saveSettings(); } }); // Initialize canvases initCrosshairCanvas(); if (settings.showFPSGraph || settings.showLatencyGraph) initStatsCanvas(); window.addEventListener('resize', () => { resizeCrosshair(); if (statsCanvas) resizeStats(); }); updateStatus(); updateHUD(); animate(); } // Wait for DOM to be ready then create GUI if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createGUI); } else { createGUI(); } // Initial call to start watching materials observeMaterials(); })(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址