猫猫放置强化助手

强化自动化工具

当前为 2025-06-18 提交的版本,查看 最新版本

// ==UserScript==
// @name         猫猫放置强化助手
// @version      v2.4
// @description  强化自动化工具
// @author       YuoHira
// @license      MIT
// @match        https://www.moyu-idle.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=moyu-idle.com
// @grant        none
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/pako.min.js
// @namespace https://gf.qytechs.cn/users/397156
// ==/UserScript==

(function() {
    'use strict';
  
    // —— 默认配置 ——
    let TARGET_LEVEL = 5;           // 目标强化等级
    let ENHANCE_INTERVAL = 1000;    // 强化间隔(毫秒)
    let isAutoEnhancing = false;    // 自动强化状态
    let enhanceTimer = null;        // 强化定时器
    let storedEnhanceData = null;   // 储存的强化数据
    let currentEnhanceItem = null;  // 当前强化物品信息

    let waitingForResult = false;   // 等待强化结果
    
    // —— 强化统计数据 ——
    let enhanceStats = {
        baseItem: '',               // 基础物品名称
        currentLevel: 0,            // 当前等级
        targetLevel: 0,             // 目标等级
        levelStats: {},             // 每级统计 {level: {attempts: 0, success: 0}}
        totalAttempts: 0,           // 总尝试次数
        totalSuccess: 0,            // 总成功次数
        startTime: null             // 开始时间
    };
    
    // —— 本地存储键名 ——
    const STORAGE_KEYS = {
        POSITION: 'enhanceHelper_position',
        TARGET_LEVEL: 'enhanceHelper_targetLevel',
        INTERVAL: 'enhanceHelper_interval',
        CURRENT_ITEM: 'enhanceHelper_currentItem',
        STORED_REQUEST: 'enhanceHelper_storedRequest'
    };
    
    // —— 加载本地配置 ——
    function loadConfig() {
        const savedTarget = localStorage.getItem(STORAGE_KEYS.TARGET_LEVEL);
        const savedInterval = localStorage.getItem(STORAGE_KEYS.INTERVAL);
        const savedCurrentItem = localStorage.getItem(STORAGE_KEYS.CURRENT_ITEM);
        const savedStoredRequest = localStorage.getItem(STORAGE_KEYS.STORED_REQUEST);
        
        if (savedTarget) TARGET_LEVEL = parseInt(savedTarget, 10);
        if (savedInterval) ENHANCE_INTERVAL = parseInt(savedInterval, 10);
        
        // 恢复当前强化物品
        if (savedCurrentItem) {
            try {
                currentEnhanceItem = JSON.parse(savedCurrentItem);
            } catch (e) {
                currentEnhanceItem = null;
            }
        }
        
        // 恢复储存的请求数据
        if (savedStoredRequest) {
            storedEnhanceData = savedStoredRequest;
        }
    }
    
    // —— 保存配置 ——
    function saveConfig() {
        localStorage.setItem(STORAGE_KEYS.TARGET_LEVEL, TARGET_LEVEL);
        localStorage.setItem(STORAGE_KEYS.INTERVAL, ENHANCE_INTERVAL);
    }
    
    // —— 保存当前强化物品 ——
    function saveCurrentItem() {
        if (currentEnhanceItem) {
            localStorage.setItem(STORAGE_KEYS.CURRENT_ITEM, JSON.stringify(currentEnhanceItem));
        } else {
            localStorage.removeItem(STORAGE_KEYS.CURRENT_ITEM);
        }
    }
    
    // —— 保存强化请求数据 ——
    function saveStoredRequest() {
        if (storedEnhanceData) {
            localStorage.setItem(STORAGE_KEYS.STORED_REQUEST, storedEnhanceData);
        } else {
            localStorage.removeItem(STORAGE_KEYS.STORED_REQUEST);
        }
    }
    
    // —— 保存位置 ——
    function savePosition(x, y) {
        localStorage.setItem(STORAGE_KEYS.POSITION, JSON.stringify({x, y}));
    }
    
    // —— 加载位置 ——
    function loadPosition() {
        const saved = localStorage.getItem(STORAGE_KEYS.POSITION);
        if (saved) {
            try {
                return JSON.parse(saved);
            } catch (e) {
                return {x: 20, y: 20};
            }
        }
        return {x: 20, y: 20};
    }
  
    // —— 辅助:检测压缩格式 ——
    function detectCompression(buf) {
      const b = new Uint8Array(buf);
      if (b.length >= 2) {
        if (b[0] === 0x1f && b[1] === 0x8b) return 'gzip';
        if (b[0] === 0x78 && (((b[0] << 8) | b[1]) % 31) === 0) return 'zlib';
      }
      return 'deflate';
    }
  
    // —— 判断是否为强化请求 ——
    function isEnhanceRequest(data) {
      if (typeof data === 'string') {
        try {
          // 检查是否包含 enhance:require 事件
          return data.includes('"enhance:require"') || data.includes('enhance:require');
        } catch (e) {
          return false;
        }
      }
      return false;
    }
    
    // —— 解析强化数据 ——
    function parseEnhanceData(data) {
      try {
        if (typeof data === 'string') {
          // 尝试解析Socket.IO格式的数据
          const match = data.match(/\["enhance:require",(.+)\]/);
          if (match) {
            const payload = JSON.parse(match[1]);
            if (payload.data && payload.data.resourceId) {
              return {
                resourceId: payload.data.resourceId,
                user: payload.user ? payload.user.name : 'Unknown'
              };
            }
          }
        }
      } catch (e) {
        // 解析失败,忽略
      }
      return null;
    }
    
    // —— 解析强化结果 ——
    function parseEnhanceResult(text) {
      try {
        const data = JSON.parse(text);
        if (data.data && data.data.hasOwnProperty('success') && data.data.enhanceResultId) {
          return {
            success: data.data.success,
            message: data.data.msg,
            resultId: data.data.enhanceResultId,
            user: data.user ? data.user.name : 'Unknown'
          };
        }
      } catch (e) {
        // 不是强化结果,忽略
      }
      return null;
    }
    
    // —— 解析物品等级 ——
    function parseItemLevel(itemId) {
      const match = itemId.match(/(.+?)\+(\d+)$/);
      if (match) {
        return {
          baseItem: match[1],
          level: parseInt(match[2], 10)
        };
      }
      return {
        baseItem: itemId,
        level: 0
      };
    }
    
    // —— 初始化统计数据 ——
    function initStats(itemId, targetLevel) {
      const parsed = parseItemLevel(itemId);
      enhanceStats = {
        baseItem: parsed.baseItem,
        currentLevel: parsed.level,
        targetLevel: targetLevel,
        levelStats: {},
        totalAttempts: 0,
        totalSuccess: 0,
        startTime: Date.now()
      };
      
      // 初始化每级统计 - 始终从+1到目标等级
      for (let i = 0; i < targetLevel; i++) {
        enhanceStats.levelStats[i] = { attempts: 0, success: 0 };
      }
    }
    
    // —— 更新统计数据 ——
    function updateStats(result) {
      // 解析结果物品等级
      const resultItem = parseItemLevel(result.resultId);
      
      // 记录这次尝试
      const attemptLevel = enhanceStats.currentLevel;
      const levelStats = enhanceStats.levelStats[attemptLevel];
      if (levelStats) {
        levelStats.attempts++;
        enhanceStats.totalAttempts++;
        
        if (result.success) {
          levelStats.success++;
          enhanceStats.totalSuccess++;
        }
      }
      
      // 更新当前等级为结果等级
      enhanceStats.currentLevel = resultItem.level;
      
      updateStatsDisplay();
    }
  
    // —— 自动强化函数 ——
    function startAutoEnhance(ws) {
      if (enhanceTimer) {
        clearTimeout(enhanceTimer);
      }
      
      // 发送第一次强化请求
      sendEnhanceRequest(ws);
    }
    
    // —— 发送强化请求 ——
    function sendEnhanceRequest(ws) {
      if (!isAutoEnhancing || !ws || ws.readyState !== WebSocket.OPEN || !currentEnhanceItem || !storedEnhanceData) {
        return;
      }
      
      // 检查是否达到目标等级
      if (enhanceStats.currentLevel >= enhanceStats.targetLevel) {
        stopAutoEnhance();
        updateItemDisplay(currentEnhanceItem, '已完成');
        return;
      }
      
      // 解析原始请求获取用户信息
      let userInfo = null;
      try {
        const match = storedEnhanceData.match(/\["enhance:require",(.+)\]/);
        if (match) {
          const payload = JSON.parse(match[1]);
          userInfo = payload.user;
        }
      } catch (e) {
        // 解析失败,使用默认值
      }
      
      // 构造当前物品的强化请求,使用真实用户信息
      const enhanceRequest = `42["enhance:require",{"user":${JSON.stringify(userInfo)},"data":{"resourceId":"${currentEnhanceItem.resourceId}"}}]`;
      
      waitingForResult = true;
      ws.__originalSend(enhanceRequest);
    }
    
    // —— 处理强化结果 ——
    function handleEnhanceResult(result) {
      waitingForResult = false;
      
      // 总是更新当前强化物品为结果物品(不管成功失败)
      const wasFirstCapture = !currentEnhanceItem;
      
      currentEnhanceItem = {
        resourceId: result.resultId,
        user: result.user
      };
      
      // 保存到本地存储
      saveCurrentItem();
      
      // 如果是第一次捕获物品,启用按钮
      if (wasFirstCapture) {
        updateItemDisplay(currentEnhanceItem);
      } else {
        // 更新UI显示当前物品
        updateItemDisplay(currentEnhanceItem);
        
        // 更新统计数据(只有在自动强化时才统计)
        if (isAutoEnhancing) {
          updateStats(result);
        }
      }
      
      // 如果还在自动强化模式,延迟后继续
      if (isAutoEnhancing) {
        enhanceTimer = setTimeout(() => {
          sendEnhanceRequest(window.currentWS);
        }, ENHANCE_INTERVAL);
      }
    }
  
    function stopAutoEnhance() {
      if (enhanceTimer) {
        clearTimeout(enhanceTimer);
        enhanceTimer = null;
      }
      waitingForResult = false;
    }
  
    // —— 初始化配置 ——
    loadConfig();
    
    // 如果有恢复的物品,延迟更新UI显示
    if (currentEnhanceItem) {
        setTimeout(() => {
            updateItemDisplay(currentEnhanceItem);
        }, 100);
    }
    
    // —— 创建浮动控制面板 ——
    const panel = document.createElement('div');
    const savedPos = loadPosition();
    panel.style.cssText = `
      position: fixed; top: ${savedPos.y}px; right: ${savedPos.x}px;
      width: 480px; padding: 12px;
      background: rgba(25,35,45,0.95); color: #fff;
      font-family: 'Consolas', 'Monaco', monospace; font-size: 12px;
      border-radius: 10px; z-index: 9999;
      cursor: move; border: 1px solid rgba(100,200,255,0.3);
      box-shadow: 0 6px 25px rgba(0,0,0,0.4);
      backdrop-filter: blur(5px);
    `;
    panel.innerHTML = `
      <div style="cursor: default; margin-bottom:10px; font-weight:bold; color:#64B5F6; display:flex; align-items:center;">
        <span>🛠️ 强化助手</span>
        <div style="margin-left:auto; font-size:10px; color:#888;">v2.4</div>
      </div>
      
      <!-- 主要内容区域:左右分布 -->
      <div style="display: flex; gap: 12px;">
        <!-- 左侧控制区 -->
        <div style="flex: 1; min-width: 220px;">
          <div style="background:rgba(0,0,0,0.3); padding:8px; border-radius:6px; margin-bottom:8px;">
            <div style="font-size:10px; color:#aaa; margin-bottom:4px;">目标物品:</div>
            <div id="enhanceItemDisplay" style="color:#FFA726; font-weight:bold; min-height:16px;">
              等待强化结果...
            </div>
          </div>
          
          <div style="display:flex; gap:8px; margin-bottom:8px;">
            <label style="flex:1;">
              目标等级:
              <input id="enhanceTargetInput" type="number" min="1" max="15" value="${TARGET_LEVEL}"
                     style="width:100%; padding:4px; border-radius:4px; border:none; background:rgba(255,255,255,0.1); color:#fff; margin-top:2px;">
            </label>
            <label style="flex:1;">
              间隔(ms):
              <input id="enhanceIntervalInput" type="number" min="100" value="${ENHANCE_INTERVAL}"
                     style="width:100%; padding:4px; border-radius:4px; border:none; background:rgba(255,255,255,0.1); color:#fff; margin-top:2px;">
            </label>
          </div>
          

          
          <button id="enhanceToggleBtn" style="
            width:100%; padding:10px;
            background:linear-gradient(45deg, #4CAF50, #45a049); color:white; border:none;
            border-radius:6px; cursor:pointer; font-size:13px; font-weight:bold;
            transition: all 0.3s ease;
          " disabled>🚀 开始强化</button>
          
          <div style="display:flex; justify-content:space-between; font-size:10px; color:#aaa; margin-top:8px;">
            <span>状态: <span id="enhanceStatus" style="color:#FFA726;">待机中</span></span>
            <span id="enhanceCounter">就绪</span>
          </div>
          
          <button id="clearDataBtn" style="
            width:100%; padding:6px; margin-top:6px;
            background:rgba(244,67,54,0.8); color:white; border:none;
            border-radius:4px; cursor:pointer; font-size:10px;
            transition: all 0.3s ease;
          ">🗑️ 清除保存数据</button>
        </div>
        
        <!-- 右侧统计区 -->
        <div style="flex: 1; min-width: 220px;">
          <div style="background:rgba(0,0,0,0.3); padding:8px; border-radius:6px; height: 100%;">
            <div style="font-size:10px; color:#aaa; margin-bottom:6px; display:flex; align-items:center;">
              <span>📊 强化统计</span>
            </div>
            <div id="enhanceStatsDisplay" style="font-size:10px; color:#FFA726;">
              等待开始强化...
            </div>
          </div>
        </div>
      </div>
    `;
    document.body.appendChild(panel);
  
    // —— 获取控制元素 ——
    const targetInput = document.getElementById('enhanceTargetInput');
    const intervalInput = document.getElementById('enhanceIntervalInput');
    const toggleBtn = document.getElementById('enhanceToggleBtn');
    const statusSpan = document.getElementById('enhanceStatus');
    const itemDisplay = document.getElementById('enhanceItemDisplay');
    const counterSpan = document.getElementById('enhanceCounter');

    const statsDisplay = document.getElementById('enhanceStatsDisplay');
    const clearDataBtn = document.getElementById('clearDataBtn');
  
    // —— 拖拽逻辑 ——
    (function makeDraggable(el) {
      let isDown = false, offsetX = 0, offsetY = 0;
      el.addEventListener('mousedown', e => {
        if (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON') return;
        isDown = true;
        offsetX = e.clientX - el.offsetLeft;
        offsetY = e.clientY - el.offsetTop;
      });
      document.addEventListener('mousemove', e => {
        if (!isDown) return;
        const newX = e.clientX - offsetX;
        const newY = e.clientY - offsetY;
        el.style.left = newX + 'px';
        el.style.top = newY + 'px';
      });
      document.addEventListener('mouseup', () => { 
        if (isDown) {
          // 保存新位置
          const rect = el.getBoundingClientRect();
          savePosition(window.innerWidth - rect.right, rect.top);
        }
        isDown = false; 
      });
    })(panel);
  
    // —— 更新UI显示 ——
    function updateItemDisplay(itemInfo, customStatus = null) {
      if (itemInfo) {
        itemDisplay.textContent = itemInfo.resourceId; // 保持英文原始名称
        itemDisplay.title = `用户: ${itemInfo.user}`;
        toggleBtn.disabled = false;
        toggleBtn.style.opacity = '1';
        statusSpan.textContent = customStatus || '就绪';
        statusSpan.style.color = customStatus === '已完成' ? '#4CAF50' : '#4CAF50';
        counterSpan.textContent = customStatus === '已完成' ? '完成' : '已捕获';
      } else {
        itemDisplay.textContent = '等待强化结果...';
        itemDisplay.title = '';
        toggleBtn.disabled = true;
        toggleBtn.style.opacity = '0.5';
        statusSpan.textContent = '等待中';
        statusSpan.style.color = '#FFA726';
        counterSpan.textContent = '就绪';
      }
    }
    
    // —— 更新统计显示 ——
    function updateStatsDisplay() {
      if (!enhanceStats.baseItem) {
        statsDisplay.innerHTML = '等待开始强化...';
        return;
      }
      
      const totalRate = enhanceStats.totalAttempts > 0 ? 
        (enhanceStats.totalSuccess / enhanceStats.totalAttempts * 100).toFixed(1) : '0.0';
      
      let html = `
        <div style="margin-bottom:6px; padding-bottom:6px; border-bottom:1px solid rgba(255,255,255,0.1);">
          <div style="color:#64B5F6; font-weight:bold; margin-bottom:2px;">${enhanceStats.baseItem}</div>
          <div style="font-size:11px; color:#FFA726;">
            进度: Lv${enhanceStats.currentLevel}/${enhanceStats.targetLevel} | 
            总计: ${enhanceStats.totalAttempts}次 (${totalRate}%)
          </div>
        </div>
      `;
      
      // 显示每级详细统计 - 每级一行,从高到低排序
      const levels = Object.keys(enhanceStats.levelStats).sort((a, b) => parseInt(b) - parseInt(a));
      if (levels.length > 0) {
        html += '<div>';
        levels.forEach(level => {
          const stats = enhanceStats.levelStats[level];
          const levelNum = parseInt(level);
          const targetLevelNum = levelNum + 1;
          const rate = stats.attempts > 0 ? (stats.success / stats.attempts * 100).toFixed(1) : '0.0';
          const isCurrentLevel = levelNum === enhanceStats.currentLevel;
          const hasAttempts = stats.attempts > 0;
          const isCompleted = levelNum < enhanceStats.currentLevel;
          
          // 确定显示样式
          let bgColor, textColor, displayText;
          if (isCurrentLevel) {
            bgColor = 'rgba(100,181,246,0.2)';
            textColor = '#64B5F6';
            displayText = hasAttempts ? `${stats.attempts}次 (${rate}%)` : '进行中';
          } else if (isCompleted) {
            bgColor = 'rgba(76,175,80,0.1)';
            textColor = '#81C784';
            displayText = hasAttempts ? `${stats.attempts}次 (${rate}%)` : '已完成';
          } else {
            bgColor = 'transparent';
            textColor = '#666';
            displayText = '未开始';
          }
          
          html += `
            <div style="
              display:flex; justify-content:space-between; align-items:center;
              padding:2px 4px; margin:1px 0; border-radius:3px;
              background:${bgColor}; font-size:9px; color:${textColor};
            ">
              <span>Lv${targetLevelNum}</span>
              <span>${displayText}</span>
            </div>
          `;
        });
        html += '</div>';
      }
      
      statsDisplay.innerHTML = html;
    }
    
    // —— 事件监听器 ——
    targetInput.addEventListener('change', e => {
      const v = parseInt(e.target.value, 10);
      if (!isNaN(v) && v > 0 && v <= 15) {
        TARGET_LEVEL = v;
        saveConfig();
      }
    });
  
    intervalInput.addEventListener('change', e => {
      const v = parseInt(e.target.value, 10);
      if (!isNaN(v) && v >= 100) {
        ENHANCE_INTERVAL = v;
        saveConfig();
      }
    });
  
    toggleBtn.addEventListener('click', () => {
      if (!isAutoEnhancing) {
        if (!currentEnhanceItem) {
          return; // 按钮应该是禁用状态
        }
        
        // 初始化统计数据
        initStats(currentEnhanceItem.resourceId, TARGET_LEVEL);
        updateStatsDisplay();
        
        // 开始自动强化
        isAutoEnhancing = true;
        toggleBtn.innerHTML = '⏹️ 停止强化';
        toggleBtn.style.background = 'linear-gradient(45deg, #f44336, #d32f2f)';
        statusSpan.textContent = '运行中';
        statusSpan.style.color = '#4CAF50';
        counterSpan.textContent = '活动中';
        
        if (window.currentWS) {
          startAutoEnhance(window.currentWS);
        }
      } else {
        // 停止自动强化
        isAutoEnhancing = false;
        stopAutoEnhance();
        toggleBtn.innerHTML = '🚀 开始强化';
        toggleBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
        statusSpan.textContent = '已停止';
        statusSpan.style.color = '#f44336';
        counterSpan.textContent = '就绪';
      }
    });
    
    // —— 清除数据按钮事件 ——
    clearDataBtn.addEventListener('click', () => {
      if (confirm('确定要清除所有保存的数据吗?这将清除当前强化物品和请求数据。')) {
        // 清除内存中的数据
        currentEnhanceItem = null;
        storedEnhanceData = null;
        
        // 清除本地存储
        localStorage.removeItem(STORAGE_KEYS.CURRENT_ITEM);
        localStorage.removeItem(STORAGE_KEYS.STORED_REQUEST);
        
        // 重置UI
        updateItemDisplay(null);
        
        // 如果正在强化,停止强化
        if (isAutoEnhancing) {
          isAutoEnhancing = false;
          stopAutoEnhance();
          toggleBtn.innerHTML = '🚀 开始强化';
          toggleBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
          statusSpan.textContent = '已清除';
          statusSpan.style.color = '#f44336';
          counterSpan.textContent = '就绪';
        }
        

      }
    });
  
    // —— 拦截全局 WebSocket ——
    const NativeWS = window.WebSocket;
    window.WebSocket = function(url, protocols) {
      const ws = protocols ? new NativeWS(url, protocols) : new NativeWS(url);
      
      // 保存当前WebSocket实例
      window.currentWS = ws;
  
      // —— 拦截 send ——
      const originalSend = ws.send;
      ws.__originalSend = originalSend; // 保存原始方法供自动强化使用
      ws.send = function(data) {
        // 检查是否为强化请求
        if (isEnhanceRequest(data)) {
          // 储存强化数据供后续自动使用(但不更新当前物品)
          storedEnhanceData = data;
          saveStoredRequest(); // 保存到本地存储
        }
        
        // 正常发送原始请求,不影响游戏运行
        originalSend.call(this, data);
      };
  
      // —— 拦截接收消息并解压 ——
      ws.addEventListener('message', ev => {
        if (ev.data instanceof ArrayBuffer) {
          try {
            const format = detectCompression(ev.data);
            let text;
            switch (format) {
              case 'gzip':
                text = pako.ungzip(new Uint8Array(ev.data), { to: 'string' });
                break;
              case 'zlib':
                text = pako.inflate(new Uint8Array(ev.data), { to: 'string' });
                break;
              default:
                text = pako.inflateRaw(new Uint8Array(ev.data), { to: 'string' });
            }
            
            // 检查是否为强化结果(不管是否在等待,都要处理)
            const enhanceResult = parseEnhanceResult(text);
            if (enhanceResult) {
              handleEnhanceResult(enhanceResult);
            }
          } catch (err) {
            // 解压失败,忽略
          }
        }
      });
      
      // WebSocket关闭时清理
      ws.addEventListener('close', () => {
        if (isAutoEnhancing) {
          stopAutoEnhance();
          isAutoEnhancing = false;
          toggleBtn.innerHTML = '🚀 开始强化';
          toggleBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)';
          statusSpan.textContent = '连接断开';
          statusSpan.style.color = '#f44336';
          counterSpan.textContent = '离线';
        }
      });
  
      return ws;
    };
  
    // 继承原型与静态属性
    window.WebSocket.prototype = NativeWS.prototype;
    Object.getOwnPropertyNames(NativeWS).forEach(prop => {
      if (!(prop in window.WebSocket)) {
        window.WebSocket[prop] = NativeWS[prop];
      }
    });
  

  
})(); 

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址