// ==UserScript== // @name 通用时间加速器(修复版:关闭后恢复) // @namespace http://tampermonkey.net/ // @version 1.2 // @description 通用时间加速插件,关闭后网页恢复正常,支持多游戏 // @author ZMM // @match *://*/* // @grant none // @run-at document-start // ==/UserScript== (function () { 'use strict'; /* ========== 配置持久化(可选) ========== */ const CFG_KEY = '__time_cheat_cfg__'; const defaultCfg = { enabled: false, multiplier: 2 // 默认2倍速 }; let cfg = Object.assign({}, defaultCfg); try { cfg = Object.assign(cfg, JSON.parse(localStorage.getItem(CFG_KEY) || '{}')); } catch (e) { localStorage.removeItem(CFG_KEY); } function saveCfg() { localStorage.setItem(CFG_KEY, JSON.stringify(cfg)); } /* ========== 核心:可恢复的时间加速引擎 ========== */ let timeEngineLastReal = performance.now(); let timeEngineFakeTime = timeEngineLastReal; let timeEngineStarted = false; // 标记引擎是否已启动 // 保存原始函数(关键修复:关闭时恢复) const OrigPerfNow = performance.now.bind(performance); const OrigDateNow = Date.now; // 重写 performance.now(游戏常用) performance.now = function() { const realNow = OrigPerfNow(); const realDelta = realNow - timeEngineLastReal; // 防止时间跳跃过大(如页面切换或游戏暂停) if (realDelta > 1000) { // 超过1秒的跳跃视为异常,重置引擎 timeEngineLastReal = realNow; timeEngineFakeTime = realNow; return realNow; } timeEngineLastReal = realNow; const multiplier = cfg.enabled ? (Number(cfg.multiplier) || 1) : 1; // 防止倍率异常(如 NaN、Infinity) if (isNaN(multiplier) || !isFinite(multiplier)) { return realNow; // 回退到真实时间 } timeEngineFakeTime += realDelta * multiplier; return timeEngineFakeTime; }; // 重写 Date.now(部分游戏/逻辑使用) Date.now = function() { return Math.floor(timeEngineFakeTime); }; /* ========== 注入 UI:可移动浮窗(优化版) ========== */ function injectUI() { try { // 浮窗样式(简洁、低干扰) const css = document.createElement('style'); css.textContent = ` #time-cheat-btn{ position:fixed; z-index:2147483647; width:42px; height:42px; border-radius:50%; border:2px solid #4CAF50; background:linear-gradient(135deg,#2E7D32 0%,#4CAF50 100%); color:#fff; font:bold 18px/42px sans-serif; text-align:center; cursor:pointer; user-select:none; box-shadow:0 2px 12px rgba(0,0,0,.6); transition:transform .15s,box-shadow .15s; right:16px; top:16px; touch-action:none; } #time-cheat-btn:hover{ transform:scale(1.12); box-shadow:0 0 18px rgba(76,175,80,.5); } #time-cheat-panel{ position:fixed; z-index:2147483646; right:70px; top:16px; width:280px; max-height:90vh; overflow-y:auto; background:rgba(30,30,30,.95); border:1.5px solid #4CAF50; border-radius:10px; box-shadow:0 4px 30px rgba(0,0,0,.7); font:13px/1.5 'Segoe UI',sans-serif; color:#e0e0e0; transition:opacity .2s,transform .2s; transform-origin:top right; } #time-cheat-panel.tc-hidden{ opacity:0; transform:scale(.92); pointer-events:none; } .tc-hd{ display:flex; align-items:center; justify-content:space-between; padding:10px 14px; background:rgba(76,175,80,.12); border-bottom:1px solid rgba(76,175,80,.25); cursor:move; border-radius:10px 10px 0 0; user-select:none; } .tc-hd span{ color:#4CAF50; font-weight:700; font-size:14px; letter-spacing:.5px; } .tc-close{ background:none; border:none; color:#4CAF50; font-size:20px; cursor:pointer; line-height:1; } .tc-close:hover{ color:#fff; } .tc-body{ padding:12px 14px 16px; } .tc-row{ display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; } .tc-row label{ flex:1; color:#bbb; font-size:12px; } .tc-row input[type=number]{ width:100px; padding:4px 8px; border:1px solid rgba(76,175,80,.35); border-radius:5px; background:rgba(0,0,0,.35); color:#e0e0e0; font:13px monospace; outline:none; text-align:right; } .tc-row input[type=number]:focus{ border-color:#4CAF50; box-shadow:0 0 0 2px rgba(76,175,80,.2); } .tc-toggle{ display:flex; align-items:center; gap:8px; margin-bottom:10px; cursor:pointer; } .tc-toggle input{ display:none; } .tc-sw{ position:relative; width:36px; height:20px; border-radius:10px; background:rgba(255,255,255,.12); transition:background .2s; flex-shrink:0; } .tc-sw::after{ content:''; position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:#888; transition:transform .2s,background .2s; } .tc-toggle input:checked+.tc-sw{ background:rgba(76,175,80,.35); } .tc-toggle input:checked+.tc-sw::after{ transform:translateX(16px); background:#4CAF50; } .tc-toggle span:last-child{ font-size:12px; color:#bbb; } .tc-sep{ height:1px; background:rgba(76,175,80,.18); margin:10px 0; } .tc-apply{ display:block; width:100%; padding:9px 0; margin-top:6px; border:none; border-radius:6px; cursor:pointer; background:linear-gradient(135deg,#4CAF50,#388E3C); color:#1a1a1a; font:bold 13px sans-serif; letter-spacing:.5px; transition:filter .15s,transform .1s; } .tc-apply:hover{ filter:brightness(1.15); } .tc-apply:active{ transform:scale(.97); } .tc-hint{ text-align:center; font-size:11px; color:#776; margin-top:6px; transition:color .2s; min-height: 16px; } `; document.head.appendChild(css); // 浮窗按钮 const btn = document.createElement('div'); btn.id = 'time-cheat-btn'; btn.textContent = '⏩'; btn.title = '时间加速器'; document.body.appendChild(btn); // 浮窗面板 const panel = document.createElement('div'); panel.id = 'time-cheat-panel'; panel.classList.add('tc-hidden'); panel.innerHTML = `
时间加速器
开启后立即生效,关闭后网页恢复正常
`; document.body.appendChild(panel); /* --- 浮窗移动逻辑(优化:避免干扰游戏) --- */ (function makeBtnDraggable() { const el = btn; let dragging = false, startX = 0, startY = 0, origLeft = 0, origTop = 0; function onPointerDown(e) { if (e.button !== undefined && e.button !== 0) return; dragging = true; const point = e.touches ? e.touches[0] : e; startX = point.clientX; startY = point.clientY; const rect = el.getBoundingClientRect(); origLeft = rect.left; origTop = rect.top; el.style.right = 'auto'; el.style.left = origLeft + 'px'; el.style.top = origTop + 'px'; e.preventDefault(); } function onPointerMove(e) { if (!dragging) return; const point = e.touches ? e.touches[0] : e; const dx = point.clientX - startX; const dy = point.clientY - startY; el.style.left = (origLeft + dx) + 'px'; el.style.top = (origTop + dy) + 'px'; e.preventDefault(); } function onPointerUp(e) { if (!dragging) return; dragging = false; const point = e.changedTouches ? e.changedTouches[0] : e; const dx = point.clientX - startX; const dy = point.clientY - startY; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 5) { panel.classList.toggle('tc-hidden'); } } el.addEventListener('mousedown', onPointerDown); document.addEventListener('mousemove', onPointerMove); document.addEventListener('mouseup', onPointerUp); el.addEventListener('touchstart', onPointerDown, { passive: false }); document.addEventListener('touchmove', onPointerMove, { passive: false }); el.addEventListener('touchend', onPointerUp); })(); /* --- 提示语逻辑 --- */ const hintEl = panel.querySelector('.tc-hint'); function showHint(msg, isError = false) { hintEl.textContent = msg; hintEl.style.color = isError ? '#ff6b6b' : '#4CAF50'; setTimeout(() => { hintEl.textContent = "开启后立即生效,关闭后网页恢复正常"; hintEl.style.color = '#776'; }, 3000); } /* --- 交互逻辑(关键修复:关闭时恢复原始函数) --- */ panel.querySelector('.tc-close').onclick = () => panel.classList.add('tc-hidden'); // 应用设置(重置时间引擎,确保关闭时恢复) panel.querySelector('.tc-apply').onclick = () => { cfg.enabled = document.getElementById('tc-enabled').checked; cfg.multiplier = document.getElementById('tc-multiplier').value; saveCfg(); // 关键修复:关闭时恢复原始时间函数 if (!cfg.enabled) { performance.now = OrigPerfNow; // 恢复 performance.now Date.now = OrigDateNow; // 恢复 Date.now timeEngineLastReal = OrigPerfNow(); // 重置时间引擎 timeEngineFakeTime = timeEngineLastReal; showHint("✅ 时间加速已关闭,网页恢复正常"); } else { // 开启时重置时间引擎(避免倍率切换异常) timeEngineLastReal = OrigPerfNow(); timeEngineFakeTime = timeEngineLastReal; showHint(`✅ 时间加速已开启,倍率:${cfg.multiplier}x`); } }; // 实时更新倍率(可选,按需启用) document.getElementById('tc-multiplier').addEventListener('input', function() { cfg.multiplier = this.value; saveCfg(); }); document.getElementById('tc-enabled').addEventListener('change', function () { cfg.enabled = this.checked; saveCfg(); }); } catch(err) { console.error("时间加速器 UI Error:", err); } } // 辅助函数:根据布尔值返回 checked 属性 function checkedAttr(v) { return v ? ' checked' : ''; } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', injectUI); } else { injectUI(); } })();