// ==UserScript== // @name 猫猫放置强化助手 // @version v4.6 // @description 强化自动化工具 // @author YuoHira // @license MIT // @match https://www.moyu-idle.com/* // @match https://moyu-idle.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=moyu-idle.com // @require https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako.min.js // @namespace https://greasyfork.org/users/397156 // @grant GM_xmlhttpRequest // @grant unsafeWindow // @connect kokdmexaezqaylurjprj.supabase.co // @connect *.supabase.co // @downloadURL https://update.greasyfork.icu/scripts/539892/%E7%8C%AB%E7%8C%AB%E6%94%BE%E7%BD%AE%E5%BC%BA%E5%8C%96%E5%8A%A9%E6%89%8B.user.js // @updateURL https://update.greasyfork.icu/scripts/539892/%E7%8C%AB%E7%8C%AB%E6%94%BE%E7%BD%AE%E5%BC%BA%E5%8C%96%E5%8A%A9%E6%89%8B.meta.js // ==/UserScript== (function () { 'use strict'; // —— 默认配置 —— let TARGET_LEVEL = 5; // 目标强化等级 let ENHANCE_INTERVAL = 3000; // 强化间隔(毫秒) let isAutoEnhancing = false; // 自动强化状态 let enhanceTimer = null; // 强化定时器 let storedEnhanceData = null; // 储存的强化数据(完整的请求对象) let currentEnhanceItem = null; // 当前强化物品信息 let DEBUG_MODE = false; // 调试模式(默认关闭) let PROTECT_START_LEVEL = 3; // 从几级开始使用保护材料 let PROTECT_MODE = 'none'; // 保护模式: 'none'=不使用, 'item'=使用物品, 'essence'=使用精华 let BATCH_COUNT = 1; // 批量强化次数 let currentBatchCount = 0; // 当前剩余强化次数 let waitingForResult = false; // 等待强化结果 let enhanceHistory = {}; // 强化历史记录 {baseItem: {sessions: []}} let isHistoryPanelOpen = false; // 历史记录面板是否打开 let currentEnhanceRecordId = null; // 当前强化记录ID(用于继承) let isContinuedFromHistory = false; // 是否从历史记录继续强化(不存档) let lastEnhanceBaseItem = null; // 上一次强化的基础物品名称(用于智能继续检测) let ENABLE_HISTORY_RECORDING = true; // 是否启用历史记录功能(存档) let savedUserName = null; // 保存的用户名称 // —— 强化统计数据 —— let enhanceStats = { baseItem: '', // 基础物品名称 currentLevel: 0, // 当前等级 targetLevel: 0, // 目标等级 maxReachedLevel: 0, // 历史最大等级 levelStats: {}, // 每级统计 {level: {attempts: 0, success: 0}} totalAttempts: 0, // 总尝试次数 totalSuccess: 0, // 总成功次数 startTime: null // 开始时间 }; // —— 可强化装备ID到中文名称的映射 —— const enhanceableItemsMap = { ancientFishboneNecklace: "远古鱼骨项链", axe: "斧头", catFurCuteHat: "毛毛可爱帽", catPotionSilverBracelet: "猫薄荷手链", collectingBracelet: "采集手环", emberAegis: "余烬庇护", fermentationStirrer: "酿造搅拌器", fishingHat: "钓鱼帽", forestDagger: "冰霜匕首", frostCrown: "霜之王冠", goblinDaggerPlus: "哥布林匕首·改", iceFeatherBoots: "冰羽靴", icePickaxe: "冰镐", ironCoat: "铁甲衣", ironGloves: "铁护手", ironHat: "铁头盔", ironMachinistHammer: "铁锤", ironPants: "铁护腿", ironPot: "铁锅", ironShovel: "铁铲", ironSword: "铁剑", magicBook: "魔法书", mewShadowStaff: "喵影法杖", mithrilCoat: "秘银护甲", mithrilDagger: "秘银匕首", mithrilGloves: "秘银手套", mithrilHat: "秘银头盔", mithrilPants: "秘银护腿", mithrilSword: "秘银剑", moonlightPendant: "月光吊坠", moonlightStaff: "月光法杖", overloadGuardianCore: "过载核心", silkDexGloves: "丝质绑带手套", silkDexHeadScarf: "丝质裹头巾", silkMageBurqa: "丝质罩袍", silkMageHat: "丝质法师帽", silkMageLongGloves: "丝质法师手套", silkMagePants: "丝质法师裤", silkTightsCloth: "丝质夜行衣", silkTightsPants: "丝质宽松裤", silverCoat: "银护甲", silverDagger: "银质匕首", silverGloves: "银护手", silverHat: "银头盔", silverPants: "银护腿", silverSword: "银质剑", snowWolfCloak: "雪狼皮披风", starDustMagicBook: "星辰魔法书", steelCoat: "钢甲衣", steelGloves: "钢护手", steelHammer: "钢制重锤", steelHat: "钢头盔", steelMachinistHammer: "钢锤", steelPants: "钢护腿", steelPot: "钢锅", steelShovel: "钢铲", steelSword: "钢剑", woodStaff: "木法杖", woodSword: "木剑", woolArtisanOutfit: "羊毛工匠服", woolBurqa: "羊毛罩袍", woolCuteGloves: "羊毛可爱手套", woolCuteHat: "羊毛可爱帽", woolDexGloves: "羊毛绑带手套", woolDexHeadScarf: "羊毛裹头巾", woolMageHat: "羊毛法师帽", woolMageLongGloves: "羊毛法师手套", woolMagePants: "羊毛法师裤", woolTailorClothes: "羊毛裁缝服", woolTailorGloves: "羊毛裁缝手套", woolTightsCloth: "羊毛紧身衣", woolTightsPants: "羊毛紧身裤", starEssence: "星辉精华", }; // —— 本地存储键名 —— const STORAGE_KEYS = { POSITION: 'enhanceHelper_position', TARGET_LEVEL: 'enhanceHelper_targetLevel', INTERVAL: 'enhanceHelper_interval', CURRENT_ITEM: 'enhanceHelper_currentItem', STORED_REQUEST: 'enhanceHelper_storedRequest', DEBUG_MODE: 'enhanceHelper_debugMode', PROTECT_START_LEVEL: 'enhanceHelper_protectStartLevel', PROTECT_MODE: 'enhanceHelper_protectMode', IS_MINIMIZED: 'enhanceHelper_isMinimized', BATCH_COUNT: 'enhanceHelper_batchCount', CURRENT_BATCH_COUNT: 'enhanceHelper_currentBatchCount', ENHANCE_HISTORY: 'enhanceHelper_enhanceHistory', ENABLE_HISTORY_RECORDING: 'enhanceHelper_enableHistoryRecording', USER_NAME: 'enhanceHelper_userName' }; // —— 数据库配置 —— // 如果你是其他的脚本开发者,请自行前往supabase创建自己的数据库和表(感谢配合) // 表结构: item_name (text), player_name (text), enhance_num (integer) const SUPABASE_CONFIG = { url: 'https://kokdmexaezqaylurjprj.supabase.co', key: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imtva2RtZXhhZXpxYXlsdXJqcHJqIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTEyNzMzNzQsImV4cCI6MjA2Njg0OTM3NH0.fuHqBV4RWd6gHUn-ff3pmsOu6BAdNTmDb_0Eclqz8aM' }; const TABLE_NAME = '弱化之王'; // —— 界面状态 —— let isMinimized = false; // —— 加载本地配置 —— 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); const savedDebugMode = localStorage.getItem(STORAGE_KEYS.DEBUG_MODE); const savedProtectStartLevel = localStorage.getItem(STORAGE_KEYS.PROTECT_START_LEVEL); const savedProtectMode = localStorage.getItem(STORAGE_KEYS.PROTECT_MODE); const savedIsMinimized = localStorage.getItem(STORAGE_KEYS.IS_MINIMIZED); const savedBatchCount = localStorage.getItem(STORAGE_KEYS.BATCH_COUNT); const savedCurrentBatchCount = localStorage.getItem(STORAGE_KEYS.CURRENT_BATCH_COUNT); const savedEnhanceHistory = localStorage.getItem(STORAGE_KEYS.ENHANCE_HISTORY); const savedEnableHistoryRecording = localStorage.getItem(STORAGE_KEYS.ENABLE_HISTORY_RECORDING); const storedUserName = localStorage.getItem(STORAGE_KEYS.USER_NAME); if (savedTarget) TARGET_LEVEL = parseInt(savedTarget, 10); if (savedInterval) ENHANCE_INTERVAL = parseInt(savedInterval, 10); if (savedDebugMode) DEBUG_MODE = savedDebugMode === 'true'; if (savedProtectStartLevel) PROTECT_START_LEVEL = parseInt(savedProtectStartLevel, 10); if (savedProtectMode) PROTECT_MODE = savedProtectMode; if (savedIsMinimized) isMinimized = savedIsMinimized === 'true'; if (savedBatchCount) BATCH_COUNT = parseInt(savedBatchCount, 10); if (savedCurrentBatchCount) currentBatchCount = parseInt(savedCurrentBatchCount, 10); if (savedEnableHistoryRecording !== null) ENABLE_HISTORY_RECORDING = savedEnableHistoryRecording === 'true'; // 恢复用户名 if (storedUserName) { savedUserName = storedUserName; } // 恢复强化历史记录 if (savedEnhanceHistory) { try { enhanceHistory = JSON.parse(savedEnhanceHistory); } catch (e) { enhanceHistory = {}; } } // 恢复当前强化物品 if (savedCurrentItem) { try { currentEnhanceItem = JSON.parse(savedCurrentItem); } catch (e) { currentEnhanceItem = null; } } // 恢复储存的请求数据 if (savedStoredRequest) { try { storedEnhanceData = JSON.parse(savedStoredRequest); } catch (e) { storedEnhanceData = null; } } } // —— 保存配置 —— function saveConfig() { localStorage.setItem(STORAGE_KEYS.TARGET_LEVEL, TARGET_LEVEL); localStorage.setItem(STORAGE_KEYS.INTERVAL, ENHANCE_INTERVAL); localStorage.setItem(STORAGE_KEYS.DEBUG_MODE, DEBUG_MODE); localStorage.setItem(STORAGE_KEYS.PROTECT_START_LEVEL, PROTECT_START_LEVEL); localStorage.setItem(STORAGE_KEYS.PROTECT_MODE, PROTECT_MODE); localStorage.setItem(STORAGE_KEYS.IS_MINIMIZED, isMinimized); localStorage.setItem(STORAGE_KEYS.BATCH_COUNT, BATCH_COUNT); localStorage.setItem(STORAGE_KEYS.CURRENT_BATCH_COUNT, currentBatchCount); localStorage.setItem(STORAGE_KEYS.ENABLE_HISTORY_RECORDING, ENABLE_HISTORY_RECORDING); // 保存用户名 if (savedUserName) { localStorage.setItem(STORAGE_KEYS.USER_NAME, savedUserName); } } // —— 保存强化历史记录 —— function saveEnhanceHistory() { localStorage.setItem(STORAGE_KEYS.ENHANCE_HISTORY, JSON.stringify(enhanceHistory)); } // —— 生成完全随机的强化记录ID —— function generateEnhanceRecordId() { const timestamp = Date.now().toString(36); const randomPart1 = Math.random().toString(36).substr(2, 8); const randomPart2 = Math.random().toString(36).substr(2, 8); const randomPart3 = Math.random().toString(36).substr(2, 8); return `${timestamp}_${randomPart1}_${randomPart2}_${randomPart3}`; } // —— 保存当前强化物品 —— 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, JSON.stringify(storedEnhanceData)); } else { localStorage.removeItem(STORAGE_KEYS.STORED_REQUEST); } } // —— 边界检查函数 —— function constrainPosition(x, y, panelWidth = 480, panelHeight = 400) { const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; // 确保面板至少有50px在可见范围内 const minVisible = 50; // 检查右边界(x是right值) if (x < 0) { x = 20; // 默认右边距 } else if (x > windowWidth - minVisible) { x = windowWidth - minVisible; } // 检查上下边界(y是top值) if (y < 0) { y = 20; // 默认上边距 } else if (y > windowHeight - minVisible) { y = windowHeight - minVisible; } return { x, y }; } // —— 保存位置 —— function savePosition(x, y) { const constrained = constrainPosition(x, y); localStorage.setItem(STORAGE_KEYS.POSITION, JSON.stringify(constrained)); } // —— 加载位置 —— function loadPosition() { const saved = localStorage.getItem(STORAGE_KEYS.POSITION); let position = { x: 20, y: 20 }; // 默认位置 if (saved) { try { position = JSON.parse(saved); } catch (e) { position = { x: 20, y: 20 }; } } // 加载时也进行边界检查,防止窗口大小改变后面板跑到屏幕外 return constrainPosition(position.x, position.y); } // —— 辅助:检测压缩格式 —— 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, protectedResourceId: payload.data.protectedResourceId || null, user: payload.user ? payload.user.name : 'Unknown', fullPayload: payload // 保存完整的payload用于重构请求 }; } } } } 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 }; } // —— 物品ID翻译函数 —— function translateItemId(itemId) { if (!itemId) return itemId; // 解析物品等级 const itemInfo = parseItemLevel(itemId); const baseItemId = itemInfo.baseItem; const level = itemInfo.level; // 获取中文名称 const chineseName = enhanceableItemsMap[baseItemId] || baseItemId; // 如果有等级后缀,添加等级显示 if (level > 0) { return `${chineseName}+${level}`; } return chineseName; } // —— 初始化统计数据 —— function initStats(itemId, targetLevel, inheritRecordId = null) { const parsed = parseItemLevel(itemId); // 如果有继承的记录ID,使用它;否则生成新的 const recordId = inheritRecordId || generateEnhanceRecordId(); currentEnhanceRecordId = recordId; enhanceStats = { baseItem: parsed.baseItem, startLevel: parsed.level, // 记录起始等级 currentLevel: parsed.level, targetLevel: targetLevel, maxReachedLevel: parsed.level, // 初始化为当前等级 levelStats: {}, totalAttempts: 0, totalSuccess: 0, startTime: Date.now(), sessionId: Date.now() + '_' + Math.random().toString(36).substr(2, 9), // 唯一会话ID recordId: recordId // 强化记录ID(用于继承和合并) }; // 初始化每级统计 - 始终从+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; // 更新历史最大等级 if (resultItem.level > enhanceStats.maxReachedLevel) { enhanceStats.maxReachedLevel = resultItem.level; } updateStatsDisplay(); } // —— 保存当前强化会话到历史记录 —— function saveCurrentSessionToHistory() { if (!ENABLE_HISTORY_RECORDING || !enhanceStats.baseItem || !enhanceStats.sessionId) return; const baseItem = enhanceStats.baseItem; // 初始化物品历史记录 if (!enhanceHistory[baseItem]) { enhanceHistory[baseItem] = { sessions: [] }; } // 创建历史记录条目 const historyEntry = { sessionId: enhanceStats.sessionId, recordId: enhanceStats.recordId, // 强化记录ID startLevel: enhanceStats.startLevel, // 使用记录的起始等级 endLevel: enhanceStats.currentLevel, targetLevel: enhanceStats.targetLevel, maxReachedLevel: enhanceStats.maxReachedLevel, levelStats: JSON.parse(JSON.stringify(enhanceStats.levelStats)), // 深拷贝 totalAttempts: enhanceStats.totalAttempts, totalSuccess: enhanceStats.totalSuccess, startTime: enhanceStats.startTime, endTime: Date.now(), completed: enhanceStats.currentLevel >= enhanceStats.targetLevel }; // 检查是否已存在相同recordId的记录,如果存在则直接覆盖,否则添加 const existingIndex = enhanceHistory[baseItem].sessions.findIndex(s => s.recordId === enhanceStats.recordId); if (existingIndex >= 0) { const existingEntry = enhanceHistory[baseItem].sessions[existingIndex]; // 直接覆盖记录:保留最早的开始时间和最初的起始等级 historyEntry.startTime = existingEntry.startTime; // 保持最早的开始时间 historyEntry.startLevel = existingEntry.startLevel; // 保持最初的起始等级 // 直接覆盖记录(不累加) enhanceHistory[baseItem].sessions[existingIndex] = historyEntry; } else { enhanceHistory[baseItem].sessions.push(historyEntry); } // 保存到本地存储 saveEnhanceHistory(); // Debug模式记录历史保存 if (DEBUG_MODE) { console.group('📚 [强化助手] 保存强化历史记录'); console.log('记录信息:', { 记录ID: historyEntry.recordId, 会话ID: historyEntry.sessionId, 物品: baseItem, 等级进度: `+${historyEntry.startLevel} → +${historyEntry.endLevel}`, 操作类型: existingIndex >= 0 ? '覆盖现有记录' : '新增记录', 总尝试: historyEntry.totalAttempts, 总成功: historyEntry.totalSuccess }); console.groupEnd(); } } // —— 自动强化函数 —— 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) { // 获取当前输入框的批量次数 const currentInputValue = parseInt(batchCountInput.value, 10); // 批量次数-1,直接修改输入框的值 if (currentInputValue > 1) { batchCountInput.value = currentInputValue - 1; BATCH_COUNT = currentInputValue - 1; // 同步内部变量 currentBatchCount = currentInputValue - 1; // 同步当前批量次数 saveConfig(); // 保存配置 // 获取基础物品ID(去掉+数字后缀) const currentItemInfo = parseItemLevel(currentEnhanceItem.resourceId); const baseItemId = currentItemInfo.baseItem; // 基础物品ID,不包含+数字 // 更新当前强化物品为基础版本 currentEnhanceItem.resourceId = baseItemId; saveCurrentItem(); // 保存更新后的物品信息 // 重置统计数据,准备下一轮强化(使用基础物品ID,生成新的记录ID) initStats(baseItemId, TARGET_LEVEL); // 不传递inheritRecordId,让每轮批量强化生成新的记录ID updateStatsDisplay(); updateItemDisplay(currentEnhanceItem, `批量剩余: ${currentInputValue - 1}`); updateMinimizedDisplay(); // 批量强化中不重置继续强化标记,保持当前状态 // Debug模式记录批量循环信息 if (DEBUG_MODE) { console.group('🔄 [强化助手] 批量强化循环'); console.log('批量信息:', { 完成轮次: BATCH_COUNT - (currentInputValue - 1) + 1, 剩余次数: currentInputValue - 1, 基础物品ID: baseItemId, 原强化物品ID: enhanceStats.baseItem + '+' + enhanceStats.targetLevel, 新记录ID: currentEnhanceRecordId, // 显示新生成的记录ID 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } // 继续发送强化请求 setTimeout(() => { sendEnhanceRequest(ws); }, ENHANCE_INTERVAL); return; } // 批量完成,停止自动强化并更新UI状态 isAutoEnhancing = false; // 先保存历史记录再停止 if (enhanceStats.baseItem) { saveCurrentSessionToHistory(); } stopAutoEnhance(); updateItemDisplay(currentEnhanceItem, '批量完成'); updateToggleButtonState(); updateMinimizedDisplay(); // 重置继续强化标记和上次强化记录 isContinuedFromHistory = false; lastEnhanceBaseItem = null; return; } // 构造当前物品的强化请求,使用完整保存的数据 const requestData = { user: storedEnhanceData.user, data: { resourceId: currentEnhanceItem.resourceId } }; // 根据保护模式和当前等级决定是否使用保护材料 if (enhanceStats.currentLevel >= PROTECT_START_LEVEL && PROTECT_MODE !== 'none') { if (PROTECT_MODE === 'essence') { // 使用精华保护 requestData.data.protectedResourceId = 'starEssence'; } else if (PROTECT_MODE === 'item') { // 使用物品保护:当前强化物品的等级-4,最低为0级 const currentItemInfo = parseItemLevel(currentEnhanceItem.resourceId); const protectLevel = Math.max(0, currentItemInfo.level - 4); const protectItemId = protectLevel > 0 ? `${currentItemInfo.baseItem}+${protectLevel}` : currentItemInfo.baseItem; requestData.data.protectedResourceId = protectItemId; } } const enhanceRequest = `42["enhance:require",${JSON.stringify(requestData)}]`; // Debug模式记录自动强化请求 if (DEBUG_MODE) { console.group('🤖 [强化助手] 发送自动强化请求'); console.log('请求数据:', enhanceRequest); console.log('构造的请求对象:', requestData); console.log('目标物品:', { 物品ID: currentEnhanceItem.resourceId, 保护材料ID: requestData.data.protectedResourceId || '无', 当前等级: enhanceStats.currentLevel, 目标等级: enhanceStats.targetLevel, 批量进度: `${BATCH_COUNT - currentBatchCount + 1}/${BATCH_COUNT}`, 剩余次数: currentBatchCount, 保护模式: PROTECT_MODE, 保护设置: `≥${PROTECT_START_LEVEL}级使用`, 实际使用保护: requestData.data.protectedResourceId ? '是' : '否', 用户: requestData.user.name, 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } waitingForResult = true; ws.__originalSend(enhanceRequest); } // —— 处理强化结果 —— function handleEnhanceResult(result) { // 添加错误处理,防止我们的代码影响游戏运行 try { waitingForResult = false; // 解析结果物品信息 const resultItemInfo = parseItemLevel(result.resultId); const resultBaseItem = resultItemInfo.baseItem; // 检查是否需要智能继续强化 let shouldSmartContinue = false; if (!isAutoEnhancing && lastEnhanceBaseItem && resultBaseItem === lastEnhanceBaseItem) { // 停止强化状态下,如果结果物品和上次强化的是同一种基础物品,启用智能继续 shouldSmartContinue = true; isContinuedFromHistory = true; // Debug模式记录智能继续 if (DEBUG_MODE) { console.group('🔄 [强化助手] 智能继续检测'); console.log('继续信息:', { 上次基础物品: lastEnhanceBaseItem, 当前结果物品: result.resultId, 结果基础物品: resultBaseItem, 是否继续: shouldSmartContinue, 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } } // 总是更新当前强化物品为结果物品(不管成功失败) const wasFirstCapture = !currentEnhanceItem; currentEnhanceItem = { resourceId: result.resultId, user: result.user }; // 保存到本地存储 saveCurrentItem(); // 保存用户名到本地存储 if (result.user && !savedUserName) { savedUserName = result.user; saveConfig(); // 保存用户名到本地存储 } // 如果是第一次捕获物品,启用按钮 if (wasFirstCapture) { updateItemDisplay(currentEnhanceItem); } else { // 更新UI显示当前物品 updateItemDisplay(currentEnhanceItem); // 更新统计数据(只有在自动强化时才统计) if (isAutoEnhancing) { updateStats(result); // 自动强化时每次都保存历史记录 saveCurrentSessionToHistory(); } // 如果启用了智能继续,且当前有统计数据,继续累加统计 if (shouldSmartContinue && enhanceStats.baseItem === resultBaseItem) { updateStats(result); // 智能继续时也保存历史记录 saveCurrentSessionToHistory(); } // 手动强化:如果当前有统计数据且是同一物品,也要更新统计和保存历史 if (!isAutoEnhancing && !shouldSmartContinue && enhanceStats.baseItem === resultBaseItem) { updateStats(result); saveCurrentSessionToHistory(); } } // 如果还在自动强化模式,延迟后继续 if (isAutoEnhancing) { enhanceTimer = setTimeout(() => { sendEnhanceRequest(unsafeWindow.currentWS); }, ENHANCE_INTERVAL); } } catch (error) { // 捕获并记录错误,但不影响游戏运行 if (DEBUG_MODE) { console.error('[强化助手] 处理强化结果时发生错误:', error); console.error('错误堆栈:', error.stack); console.log('强化结果数据:', result); } // 重置等待状态,避免卡住 waitingForResult = false; } } function stopAutoEnhance() { if (enhanceTimer) { clearTimeout(enhanceTimer); enhanceTimer = null; } waitingForResult = false; // 记录上次强化的基础物品名称,用于智能继续检测 if (enhanceStats.baseItem) { lastEnhanceBaseItem = enhanceStats.baseItem; // 保存当前会话到历史记录 saveCurrentSessionToHistory(); } // 注意:这里不重置 isContinuedFromHistory 标记 // 因为停止后用户可能还想继续,标记会在下次开始强化时处理 } // —— 初始化配置 —— loadConfig(); // Debug模式启动提示 if (DEBUG_MODE) { console.log('🐛 [强化助手] 调试模式已启用,将记录所有WebSocket强化请求和结果'); } // 检查权限配置 checkPermissions(); // 如果有恢复的物品,延迟更新UI显示 if (currentEnhanceItem) { setTimeout(() => { updateItemDisplay(currentEnhanceItem); }, 100); } // 初始化保护显示 setTimeout(() => { updateProtectDisplay(); updateProtectModeButtons(); // 初始化保护模式按钮样式 // 初始化保护等级提示 if (PROTECT_START_LEVEL === 0) { protectLevelHint.textContent = '不使用保护'; protectLevelHint.style.color = '#f44336'; } else { protectLevelHint.textContent = `≥${PROTECT_START_LEVEL}级使用保护`; protectLevelHint.style.color = '#aaa'; } // 如果有恢复的物品,更新显示 if (currentEnhanceItem) { updateItemDisplay(currentEnhanceItem); } // 如果页面加载时是收起状态,调整面板宽度和显示状态 if (isMinimized) { panel.style.width = '280px'; titleBar.style.display = 'none'; mainContent.style.display = 'none'; minimizedBar.style.display = 'flex'; } // 初始化收起状态显示 updateMinimizedDisplay(); // 初始化历史记录按钮状态 historyBtn.disabled = !ENABLE_HISTORY_RECORDING; historyBtn.style.opacity = ENABLE_HISTORY_RECORDING ? '1' : '0.5'; }, 100); // —— 创建浮动控制面板 —— const panel = document.createElement('div'); panel.id = 'enhanceHelperPanel'; // 添加唯一ID 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 = `
🛠️ 强化助手
v4.6
等待强化结果...
目标物品:
等待强化结果...
剩余次数会自动减少
1=单次强化
保护设置:
≥${PROTECT_START_LEVEL}级使用保护
0=不使用保护
状态: 待机中 就绪
📊 强化统计
等待开始强化...
`; document.body.appendChild(panel); // —— 创建历史记录面板 —— const historyPanel = document.createElement('div'); historyPanel.id = 'enhanceHelperHistoryPanel'; historyPanel.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 600px; max-height: 80vh; padding: 16px; background: rgba(25,35,45,0.98); color: #fff; font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; border-radius: 12px; z-index: 10000; border: 1px solid rgba(100,200,255,0.4); box-shadow: 0 8px 32px rgba(0,0,0,0.6); backdrop-filter: blur(8px); display: none; overflow-y: auto; `; historyPanel.innerHTML = `

📚 强化历史记录

`; document.body.appendChild(historyPanel); // —— 获取控制元素 —— const targetInput = document.getElementById('enhanceHelper_targetInput'); const intervalInput = document.getElementById('enhanceHelper_intervalInput'); const batchCountInput = document.getElementById('enhanceHelper_batchCountInput'); const protectStartLevelInput = document.getElementById('enhanceHelper_protectStartLevelInput'); const protectModeButtons = document.querySelectorAll('.protect-mode-btn'); const enableHistoryCheckbox = document.getElementById('enhanceHelper_enableHistoryCheckbox'); const debugCheckbox = document.getElementById('enhanceHelper_debugModeCheckbox'); const toggleBtn = document.getElementById('enhanceHelper_toggleBtn'); const statusSpan = document.getElementById('enhanceHelper_status'); const itemDisplay = document.getElementById('enhanceHelper_itemDisplay'); const protectMaterialDisplay = document.getElementById('enhanceHelper_protectMaterialDisplay'); const protectLevelHint = document.getElementById('enhanceHelper_protectLevelHint'); const counterSpan = document.getElementById('enhanceHelper_counter'); const statsDisplay = document.getElementById('enhanceHelper_statsDisplay'); const clearDataBtn = document.getElementById('enhanceHelper_clearDataBtn'); const historyBtn = document.getElementById('enhanceHelper_historyBtn'); const weakKingBtn = document.getElementById('enhanceHelper_weakKingBtn'); // 历史记录面板相关元素 const closeHistoryBtn = document.getElementById('enhanceHelper_closeHistoryBtn'); const historyList = document.getElementById('enhanceHelper_historyList'); const historyListView = document.getElementById('enhanceHelper_historyListView'); const historyDetailView = document.getElementById('enhanceHelper_historyDetailView'); const backToListBtn = document.getElementById('enhanceHelper_backToListBtn'); const historyDetailTitle = document.getElementById('enhanceHelper_historyDetailTitle'); const historyDetailStats = document.getElementById('enhanceHelper_historyDetailStats'); const continueEnhanceBtn = document.getElementById('enhanceHelper_continueEnhanceBtn'); const deleteRecordBtn = document.getElementById('enhanceHelper_deleteRecordBtn'); const deleteAllHistoryBtn = document.getElementById('enhanceHelper_deleteAllHistoryBtn'); // 收起/展开相关元素 const titleBar = document.getElementById('enhanceHelper_titleBar'); const minimizeBtn = document.getElementById('enhanceHelper_minimizeBtn'); const expandBtn = document.getElementById('enhanceHelper_expandBtn'); const mainContent = document.getElementById('enhanceHelper_mainContent'); const minimizedBar = document.getElementById('enhanceHelper_minimizedBar'); const minimizedStatus = document.getElementById('enhanceHelper_minimizedStatus'); // —— 拖拽逻辑 —— (function makeDraggable(el) { let isDown = false, offsetX = 0, offsetY = 0, hasMoved = false; el.addEventListener('mousedown', e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON') return; isDown = true; hasMoved = false; offsetX = e.clientX - el.offsetLeft; offsetY = e.clientY - el.offsetTop; }); document.addEventListener('mousemove', e => { if (!isDown) return; hasMoved = true; const newX = e.clientX - offsetX; const newY = e.clientY - offsetY; el.style.left = newX + 'px'; el.style.top = newY + 'px'; el.style.right = 'auto'; // 拖拽时清除right定位 }); document.addEventListener('mouseup', () => { if (isDown && hasMoved) { // 只有真正拖拽过才应用边界检查 setTimeout(() => { const rect = el.getBoundingClientRect(); const rightDistance = window.innerWidth - rect.right; const topDistance = rect.top; // 保存并应用边界约束后的位置 const constrained = constrainPosition(rightDistance, topDistance); savePosition(constrained.x, constrained.y); // 重新设置为right定位 el.style.right = constrained.x + 'px'; el.style.top = constrained.y + 'px'; el.style.left = 'auto'; }, 0); // 使用setTimeout避免干扰点击事件 } isDown = false; hasMoved = false; }); })(panel); // —— 更新保护材料显示 —— function updateProtectDisplay() { let displayText = ''; let statusColor = '#aaa'; if (PROTECT_MODE === 'none') { displayText = '🛡️ 保护: 不使用'; statusColor = '#f44336'; } else if (PROTECT_START_LEVEL === 0) { displayText = `🛡️ 保护: ${PROTECT_MODE === 'essence' ? translateItemId('starEssence') : '物品'} (已禁用)`; statusColor = '#f44336'; } else { const protectType = PROTECT_MODE === 'essence' ? translateItemId('starEssence') : '当前物品-4级'; displayText = `🛡️ 保护: ${protectType} (≥${PROTECT_START_LEVEL}级)`; statusColor = '#64B5F6'; } protectMaterialDisplay.innerHTML = displayText; } // —— 更新UI显示 —— function updateItemDisplay(itemInfo, customStatus = null) { if (itemInfo) { itemDisplay.textContent = translateItemId(itemInfo.resourceId); // 显示中文名称 // 构建标题信息,包含用户和继续状态 let titleText = `用户: ${itemInfo.user}`; if (isContinuedFromHistory) { titleText += ' | 🔄 从历史记录继续'; } // 在title中显示原始英文ID,方便调试 titleText += ` | 原始ID: ${itemInfo.resourceId}`; itemDisplay.title = titleText; toggleBtn.disabled = false; toggleBtn.style.opacity = '1'; statusSpan.textContent = customStatus || (isContinuedFromHistory ? '继续就绪' : '就绪'); statusSpan.style.color = customStatus === '已完成' ? '#4CAF50' : '#4CAF50'; counterSpan.textContent = customStatus === '已完成' ? '完成' : (isContinuedFromHistory ? '继续' : '已捕获'); } else { itemDisplay.textContent = '等待强化结果...'; itemDisplay.title = ''; toggleBtn.disabled = true; toggleBtn.style.opacity = '0.5'; statusSpan.textContent = '等待中'; statusSpan.style.color = '#FFA726'; counterSpan.textContent = '就绪'; } // 更新保护材料显示 updateProtectDisplay(); // 更新收起状态显示 updateMinimizedDisplay(); } // —— 更新统计显示 —— function updateStatsDisplay() { if (!enhanceStats.baseItem) { statsDisplay.innerHTML = '等待开始强化...'; return; } const totalRate = enhanceStats.totalAttempts > 0 ? (enhanceStats.totalSuccess / enhanceStats.totalAttempts * 100).toFixed(1) : '0.0'; let html = `
${translateItemId(enhanceStats.baseItem)}
进度: Lv${enhanceStats.currentLevel}/${enhanceStats.targetLevel} | 总计: ${enhanceStats.totalAttempts}次 (${totalRate}%)
`; // 显示每级详细统计 - 每级一行,从高到低排序 const levels = Object.keys(enhanceStats.levelStats).sort((a, b) => parseInt(b) - parseInt(a)); if (levels.length > 0) { html += '
'; 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 targetLevel = levelNum + 1; // 目标等级 (Lv1, Lv2, etc.) const currentItemLevel = enhanceStats.currentLevel; // 当前物品等级 const maxReachedLevel = enhanceStats.maxReachedLevel; // 历史最大等级 // 确定显示样式 let bgColor, textColor; if (targetLevel === currentItemLevel + 1) { // 当前正在强化的目标等级(蓝色)- 优先级最高 bgColor = 'rgba(100,181,246,0.2)'; textColor = '#64B5F6'; } else if (targetLevel <= maxReachedLevel) { // 历史上到过的等级(绿色) bgColor = 'rgba(76,175,80,0.1)'; textColor = '#81C784'; } else { // 还没到过的等级(灰色) bgColor = 'transparent'; textColor = '#666'; } const displayText = `${stats.attempts}次 (${rate}%)`; html += `
Lv${targetLevelNum} ${displayText}
`; }); html += '
'; } statsDisplay.innerHTML = html; } // —— 收起/展开功能 —— function toggleMinimize() { isMinimized = !isMinimized; if (isMinimized) { titleBar.style.display = 'none'; mainContent.style.display = 'none'; minimizedBar.style.display = 'flex'; panel.style.width = '280px'; } else { titleBar.style.display = 'flex'; mainContent.style.display = 'block'; minimizedBar.style.display = 'none'; minimizeBtn.textContent = '📌'; panel.style.width = '480px'; } saveConfig(); updateMinimizedDisplay(); } // —— 更新收起状态显示 —— function updateMinimizedDisplay() { if (!isMinimized) return; let statusText = '等待强化结果...'; if (currentEnhanceItem) { const itemInfo = parseItemLevel(currentEnhanceItem.resourceId); const translatedName = translateItemId(itemInfo.baseItem); const baseItem = translatedName.length > 15 ? translatedName.substring(0, 15) + '..' : translatedName; const currentLevel = itemInfo.level; if (isAutoEnhancing) { // 获取当前输入框的剩余次数 const remainingCount = parseInt(batchCountInput.value, 10); const batchInfo = remainingCount > 1 ? ` [剩余${remainingCount}次]` : ''; statusText = `🔨 ${baseItem} +${currentLevel} → +${TARGET_LEVEL}${batchInfo}`; } else { const status = enhanceStats.currentLevel >= enhanceStats.targetLevel ? '已完成' : '就绪'; statusText = `${status}: ${baseItem} +${currentLevel}`; if (status === '已完成') { statusText = `✅ ${baseItem} +${currentLevel} 已完成`; } } } minimizedStatus.textContent = statusText; } // —— 更新保护模式按钮样式 —— function updateProtectModeButtons() { protectModeButtons.forEach(btn => { const mode = btn.dataset.mode; const isActive = mode === PROTECT_MODE; if (mode === 'none') { btn.style.background = isActive ? 'rgba(244,67,54,0.3)' : 'rgba(255,255,255,0.1)'; btn.style.color = isActive ? '#f44336' : '#aaa'; btn.style.border = isActive ? '1px solid #f44336' : '1px solid transparent'; } else if (mode === 'item') { btn.style.background = isActive ? 'rgba(100,181,246,0.3)' : 'rgba(255,255,255,0.1)'; btn.style.color = isActive ? '#64B5F6' : '#aaa'; btn.style.border = isActive ? '1px solid #64B5F6' : '1px solid transparent'; } else if (mode === 'essence') { btn.style.background = isActive ? 'rgba(129,199,132,0.3)' : 'rgba(255,255,255,0.1)'; btn.style.color = isActive ? '#81C784' : '#aaa'; btn.style.border = isActive ? '1px solid #81C784' : '1px solid transparent'; } }); } // —— 更新按钮状态 —— function updateToggleButtonState() { if (isAutoEnhancing) { toggleBtn.innerHTML = '⏹️ 停止强化'; toggleBtn.style.background = 'linear-gradient(45deg, #f44336, #d32f2f)'; statusSpan.textContent = '运行中'; statusSpan.style.color = '#4CAF50'; counterSpan.textContent = '活动中'; } else { toggleBtn.innerHTML = '🚀 开始强化'; toggleBtn.style.background = 'linear-gradient(45deg, #4CAF50, #45a049)'; if (enhanceStats.currentLevel >= enhanceStats.targetLevel && enhanceStats.baseItem) { statusSpan.textContent = '已完成'; statusSpan.style.color = '#4CAF50'; counterSpan.textContent = '完成'; } else { statusSpan.textContent = '已停止'; statusSpan.style.color = '#f44336'; counterSpan.textContent = '就绪'; } } } // —— 显示历史记录列表 —— function showHistoryList() { historyList.innerHTML = ''; // 计算总记录数 const totalRecords = Object.keys(enhanceHistory).reduce((total, baseItem) => { return total + (enhanceHistory[baseItem].sessions ? enhanceHistory[baseItem].sessions.length : 0); }, 0); // 控制删除全部按钮的显示和文本 if (deleteAllHistoryBtn) { if (totalRecords > 0) { deleteAllHistoryBtn.style.display = 'inline-block'; deleteAllHistoryBtn.textContent = `🗑️ 删除全部历史记录 (${totalRecords})`; } else { deleteAllHistoryBtn.style.display = 'none'; } } if (Object.keys(enhanceHistory).length === 0) { historyList.innerHTML = `
📝
暂无强化历史记录
开始强化后会自动记录历史
`; return; } // 按物品分组显示历史记录 Object.keys(enhanceHistory).forEach(baseItem => { const itemHistory = enhanceHistory[baseItem]; const sessions = itemHistory.sessions.sort((a, b) => b.endTime - a.endTime); // 按结束时间倒序 if (sessions.length === 0) return; // 物品分组标题 const itemGroupDiv = document.createElement('div'); itemGroupDiv.style.cssText = ` margin-bottom: 12px; padding: 8px; border-radius: 6px; background: rgba(100,181,246,0.1); border-left: 3px solid #64B5F6; `; itemGroupDiv.innerHTML = `
${translateItemId(baseItem)}
`; // 会话列表 sessions.forEach(session => { const sessionDiv = document.createElement('div'); sessionDiv.style.cssText = ` margin: 4px 0; padding: 8px; border-radius: 4px; cursor: pointer; background: rgba(255,255,255,0.05); border: 1px solid transparent; transition: all 0.2s ease; `; sessionDiv.addEventListener('mouseenter', () => { sessionDiv.style.background = 'rgba(255,255,255,0.1)'; sessionDiv.style.borderColor = 'rgba(100,181,246,0.3)'; }); sessionDiv.addEventListener('mouseleave', () => { sessionDiv.style.background = 'rgba(255,255,255,0.05)'; sessionDiv.style.borderColor = 'transparent'; }); const startDate = new Date(session.startTime); const endDate = new Date(session.endTime); const duration = Math.round((session.endTime - session.startTime) / 1000); const successRate = session.totalAttempts > 0 ? (session.totalSuccess / session.totalAttempts * 100).toFixed(1) : '0.0'; sessionDiv.innerHTML = `
+${session.startLevel} → +${session.endLevel} 目标: +${session.targetLevel} | 最高: +${session.maxReachedLevel}
${startDate.toLocaleDateString()} ${startDate.toLocaleTimeString()}
${session.totalAttempts}次 (${successRate}%) | ${duration}秒
${session.completed ? '✅ 已完成' : '⏸️ 未完成'} ${DEBUG_MODE ? `ID: ${session.recordId ? session.recordId.split('_')[0] : 'N/A'}` : ''}
`; // 点击显示详情 sessionDiv.addEventListener('click', () => { showHistoryDetail(baseItem, session); }); itemGroupDiv.appendChild(sessionDiv); }); historyList.appendChild(itemGroupDiv); }); } // —— 显示历史记录详情 —— function showHistoryDetail(baseItem, session) { historyListView.style.display = 'none'; historyDetailView.style.display = 'block'; const startDate = new Date(session.startTime); const endDate = new Date(session.endTime); const duration = Math.round((session.endTime - session.startTime) / 1000); const totalRate = session.totalAttempts > 0 ? (session.totalSuccess / session.totalAttempts * 100).toFixed(1) : '0.0'; historyDetailTitle.textContent = `${translateItemId(baseItem)} (+${session.startLevel} → +${session.endLevel})`; // 构建详细统计信息 let statsHtml = `
${translateItemId(baseItem)}
进度: +${session.startLevel} → +${session.endLevel} (目标: +${session.targetLevel})
开始时间: ${startDate.toLocaleString()}
结束时间: ${endDate.toLocaleString()}
持续时间: ${duration}秒 | 总计: ${session.totalAttempts}次 (${totalRate}%) ${DEBUG_MODE && session.recordId ? `
记录ID: ${session.recordId}` : ''}
`; // 显示每级详细统计 const levels = Object.keys(session.levelStats).sort((a, b) => parseInt(b) - parseInt(a)); if (levels.length > 0) { statsHtml += '
'; levels.forEach(level => { const stats = session.levelStats[level]; const levelNum = parseInt(level); const targetLevel = levelNum + 1; const rate = stats.attempts > 0 ? (stats.success / stats.attempts * 100).toFixed(1) : '0.0'; // 确定显示样式 let bgColor, textColor; if (targetLevel === session.endLevel + 1) { // 当前等级(蓝色) bgColor = 'rgba(100,181,246,0.2)'; textColor = '#64B5F6'; } else if (targetLevel <= session.maxReachedLevel) { // 历史上到过的等级(绿色) bgColor = 'rgba(76,175,80,0.1)'; textColor = '#81C784'; } else { // 还没到过的等级(灰色) bgColor = 'transparent'; textColor = '#666'; } const displayText = `${stats.attempts}次 (${rate}%)`; statsHtml += `
Lv${targetLevel} ${displayText}
`; }); statsHtml += '
'; } historyDetailStats.innerHTML = statsHtml; // 存储当前查看的会话信息,供继续强化和删除使用 continueEnhanceBtn.dataset.baseItem = baseItem; continueEnhanceBtn.dataset.sessionData = JSON.stringify(session); deleteRecordBtn.dataset.baseItem = baseItem; deleteRecordBtn.dataset.recordId = session.recordId; } // —— 从历史记录继续强化 —— function continueFromHistory(baseItem, sessionData) { // 如果正在自动强化,先停止 if (isAutoEnhancing) { isAutoEnhancing = false; stopAutoEnhance(); } // 设置当前强化物品为会话结束时的物品 const itemId = sessionData.endLevel > 0 ? `${baseItem}+${sessionData.endLevel}` : baseItem; currentEnhanceItem = { resourceId: itemId, user: 'HistoryRestore' }; // 保存当前物品 saveCurrentItem(); // 恢复目标等级(使用历史记录中的目标等级) TARGET_LEVEL = sessionData.targetLevel; targetInput.value = TARGET_LEVEL; // 初始化统计数据,继承历史记录ID initStats(itemId, TARGET_LEVEL, sessionData.recordId); // 直接使用历史数据替换当前统计(而不是累加) enhanceStats.maxReachedLevel = sessionData.maxReachedLevel; enhanceStats.totalAttempts = sessionData.totalAttempts; enhanceStats.totalSuccess = sessionData.totalSuccess; // 直接使用历史等级统计数据(而不是累加) Object.keys(sessionData.levelStats).forEach(level => { if (enhanceStats.levelStats[level]) { enhanceStats.levelStats[level].attempts = sessionData.levelStats[level].attempts; enhanceStats.levelStats[level].success = sessionData.levelStats[level].success; } }); // 更新UI updateItemDisplay(currentEnhanceItem, '已从历史恢复'); updateStatsDisplay(); updateToggleButtonState(); updateMinimizedDisplay(); // 设置继续强化标记 isContinuedFromHistory = true; // 关闭历史记录面板 closeHistoryPanel(); // 保存配置 saveConfig(); // Debug模式记录恢复信息 if (DEBUG_MODE) { console.group('🔄 [强化助手] 从历史记录恢复强化'); console.log('恢复信息:', { 记录ID: sessionData.recordId, 物品: itemId, 目标等级: TARGET_LEVEL, 恢复最高等级: sessionData.maxReachedLevel, 恢复总尝试: sessionData.totalAttempts, 恢复总成功: sessionData.totalSuccess, 操作类型: '数据恢复(非累加)' }); console.groupEnd(); } } // —— 打开历史记录面板 —— function openHistoryPanel() { isHistoryPanelOpen = true; historyPanel.style.display = 'block'; historyListView.style.display = 'block'; historyDetailView.style.display = 'none'; showHistoryList(); } // —— 关闭历史记录面板 —— function closeHistoryPanel() { isHistoryPanelOpen = false; historyPanel.style.display = 'none'; } // —— 删除单个历史记录 —— function deleteHistoryRecord(baseItem, recordId) { if (!enhanceHistory[baseItem] || !enhanceHistory[baseItem].sessions) { return false; } const sessionIndex = enhanceHistory[baseItem].sessions.findIndex(s => s.recordId === recordId); if (sessionIndex >= 0) { // 删除记录 enhanceHistory[baseItem].sessions.splice(sessionIndex, 1); // 如果该物品没有更多记录,删除整个物品条目 if (enhanceHistory[baseItem].sessions.length === 0) { delete enhanceHistory[baseItem]; } // 保存到本地存储 saveEnhanceHistory(); // Debug模式记录删除操作 if (DEBUG_MODE) { console.log('🗑️ [强化助手] 删除历史记录:', { 物品: baseItem, 记录ID: recordId, 剩余记录数: enhanceHistory[baseItem] ? enhanceHistory[baseItem].sessions.length : 0 }); } return true; } return false; } // —— 删除全部历史记录 —— function deleteAllHistory() { const recordCount = Object.keys(enhanceHistory).reduce((total, baseItem) => { return total + (enhanceHistory[baseItem].sessions ? enhanceHistory[baseItem].sessions.length : 0); }, 0); // 清空历史记录 enhanceHistory = {}; // 保存到本地存储 saveEnhanceHistory(); // Debug模式记录删除操作 if (DEBUG_MODE) { console.log('🗑️ [强化助手] 删除全部历史记录:', { 删除记录数: recordCount, 操作时间: new Date().toLocaleString() }); } return recordCount; } // —— 双击标题栏重置位置 —— titleBar.addEventListener('dblclick', () => { const defaultPos = { x: 20, y: 20 }; panel.style.right = defaultPos.x + 'px'; panel.style.top = defaultPos.y + 'px'; panel.style.left = 'auto'; savePosition(defaultPos.x, defaultPos.y); // 显示重置提示 const oldTitle = titleBar.querySelector('span').textContent; titleBar.querySelector('span').textContent = '🔄 位置已重置'; setTimeout(() => { titleBar.querySelector('span').textContent = oldTitle; }, 1000); }); // —— 事件监听器 —— 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(); } }); batchCountInput.addEventListener('change', e => { const v = parseInt(e.target.value, 10); if (!isNaN(v) && v >= 1 && v <= 99) { BATCH_COUNT = v; saveConfig(); } }); protectStartLevelInput.addEventListener('change', e => { const v = parseInt(e.target.value, 10); if (!isNaN(v) && v >= 0 && v <= 15) { PROTECT_START_LEVEL = v; saveConfig(); updateProtectDisplay(); // 更新保护显示 // 更新提示文本 if (v === 0) { protectLevelHint.textContent = '不使用保护'; protectLevelHint.style.color = '#f44336'; } else { protectLevelHint.textContent = `≥${v}级使用保护`; protectLevelHint.style.color = '#aaa'; } } }); // 保护模式按钮事件监听器 protectModeButtons.forEach(btn => { btn.addEventListener('click', () => { const newMode = btn.dataset.mode; if (newMode !== PROTECT_MODE) { PROTECT_MODE = newMode; saveConfig(); updateProtectModeButtons(); updateProtectDisplay(); } }); }); enableHistoryCheckbox.addEventListener('change', e => { ENABLE_HISTORY_RECORDING = e.target.checked; saveConfig(); // 更新历史记录按钮的可用状态 historyBtn.disabled = !ENABLE_HISTORY_RECORDING; historyBtn.style.opacity = ENABLE_HISTORY_RECORDING ? '1' : '0.5'; if (DEBUG_MODE) { console.log(`[强化助手] 历史记录功能已${ENABLE_HISTORY_RECORDING ? '启用' : '禁用'}`); } }); debugCheckbox.addEventListener('change', e => { DEBUG_MODE = e.target.checked; saveConfig(); console.log(`[强化助手] 调试模式已${DEBUG_MODE ? '开启' : '关闭'}`); }); toggleBtn.addEventListener('click', () => { if (!isAutoEnhancing) { if (!currentEnhanceItem) { return; // 按钮应该是禁用状态 } // 获取当前批量次数设置 const inputBatchCount = parseInt(batchCountInput.value, 10); BATCH_COUNT = inputBatchCount; currentBatchCount = inputBatchCount; // 检查是否从历史记录继续强化 if (!isContinuedFromHistory) { // 正常的新强化流程 // 如果是批量强化(>1次),确保从基础物品开始 if (inputBatchCount > 1) { const currentItemInfo = parseItemLevel(currentEnhanceItem.resourceId); const baseItemId = currentItemInfo.baseItem; // 基础物品ID,不包含+数字 // 更新当前强化物品为基础版本 currentEnhanceItem.resourceId = baseItemId; saveCurrentItem(); // 保存更新后的物品信息 // 初始化统计数据(使用基础物品ID) initStats(baseItemId, TARGET_LEVEL); // Debug模式记录批量开始信息 if (DEBUG_MODE) { console.group('🚀 [强化助手] 开始批量强化'); console.log('批量设置:', { 批量次数: inputBatchCount, 基础物品ID: baseItemId, 原物品ID: currentItemInfo.baseItem + (currentItemInfo.level > 0 ? '+' + currentItemInfo.level : ''), 目标等级: TARGET_LEVEL, 记录ID: currentEnhanceRecordId, // 显示生成的记录ID 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } } else { // 单次强化,使用当前物品 initStats(currentEnhanceItem.resourceId, TARGET_LEVEL); // Debug模式记录单次强化开始信息 if (DEBUG_MODE) { console.group('🚀 [强化助手] 开始单次强化'); console.log('强化设置:', { 物品ID: currentEnhanceItem.resourceId, 目标等级: TARGET_LEVEL, 记录ID: currentEnhanceRecordId, // 显示生成的记录ID 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } } updateStatsDisplay(); } else { // 从历史记录继续强化,不重新初始化统计数据 // 重置继续强化标记 isContinuedFromHistory = false; // Debug模式记录继续强化信息 if (DEBUG_MODE) { console.group('🔄 [强化助手] 继续历史强化'); console.log('继续信息:', { 物品ID: currentEnhanceItem.resourceId, 记录ID: currentEnhanceRecordId, 当前等级: enhanceStats.currentLevel, 目标等级: enhanceStats.targetLevel, 已有尝试: enhanceStats.totalAttempts, 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } } // 开始自动强化 isAutoEnhancing = true; updateToggleButtonState(); updateMinimizedDisplay(); if (unsafeWindow.currentWS) { startAutoEnhance(unsafeWindow.currentWS); } } else { // 停止自动强化 isAutoEnhancing = false; stopAutoEnhance(); updateToggleButtonState(); updateMinimizedDisplay(); // 注意:这里不重置继续强化标记和上次强化记录 // 因为手动停止后,用户可能想要继续强化同一物品 } }); // —— 收起/展开按钮事件 —— minimizeBtn.addEventListener('click', toggleMinimize); expandBtn.addEventListener('click', toggleMinimize); // —— 清除数据按钮事件 —— clearDataBtn.addEventListener('click', () => { if (confirm('确定要清除所有保存的数据吗?这将清除当前强化物品和请求数据。')) { // 清除内存中的数据 currentEnhanceItem = null; storedEnhanceData = null; currentBatchCount = 0; // 重置批量次数 isContinuedFromHistory = false; // 重置继续强化标记 lastEnhanceBaseItem = null; // 清除上次强化的基础物品记录 // 重置批量次数输入框 batchCountInput.value = 1; BATCH_COUNT = 1; // 清除本地存储 localStorage.removeItem(STORAGE_KEYS.CURRENT_ITEM); localStorage.removeItem(STORAGE_KEYS.STORED_REQUEST); // 重置UI updateItemDisplay(null); updateProtectDisplay(); // 如果正在强化,停止强化 if (isAutoEnhancing) { isAutoEnhancing = false; stopAutoEnhance(); updateToggleButtonState(); } // 更新收起状态显示 updateMinimizedDisplay(); // 保存配置 saveConfig(); } }); // —— 历史记录按钮事件 —— historyBtn.addEventListener('click', () => { if (!ENABLE_HISTORY_RECORDING) { alert('历史记录功能已禁用,请先启用历史记录功能!'); return; } openHistoryPanel(); }); // —— 弱化之王按钮事件 —— weakKingBtn.addEventListener('click', () => { if (!checkPermissions()) { alert('弱化之王功能需要网络权限!\n\n请确保:\n1. 油猴脚本已正确安装\n2. @grant GM_xmlhttpRequest 权限已配置\n3. @connect 域名权限已设置\n\n如果问题持续,请重新安装脚本。'); return; } openWeakKingPanel(); }); // —— 历史记录面板事件监听器 —— closeHistoryBtn.addEventListener('click', () => { closeHistoryPanel(); }); backToListBtn.addEventListener('click', () => { historyListView.style.display = 'block'; historyDetailView.style.display = 'none'; }); continueEnhanceBtn.addEventListener('click', () => { const baseItem = continueEnhanceBtn.dataset.baseItem; const sessionData = JSON.parse(continueEnhanceBtn.dataset.sessionData); continueFromHistory(baseItem, sessionData); }); // —— 删除单个记录按钮事件 —— deleteRecordBtn.addEventListener('click', () => { const baseItem = deleteRecordBtn.dataset.baseItem; const recordId = deleteRecordBtn.dataset.recordId; if (!baseItem || !recordId) { alert('无法获取记录信息,删除失败!'); return; } // 检查是否正在删除当前强化的记录 let warningMessage = `确定要删除这条强化记录吗?\n\n物品: ${baseItem}\n记录ID: ${recordId}`; if (currentEnhanceRecordId === recordId) { warningMessage += '\n\n⚠️ 警告:这是当前正在强化的记录!'; } warningMessage += '\n\n此操作无法撤销!'; if (confirm(warningMessage)) { const success = deleteHistoryRecord(baseItem, recordId); if (success) { // 删除成功,返回列表页面并刷新 historyListView.style.display = 'block'; historyDetailView.style.display = 'none'; showHistoryList(); // 显示删除成功提示 const oldTitle = historyPanel.querySelector('h3').textContent; historyPanel.querySelector('h3').textContent = '✅ 记录已删除'; historyPanel.querySelector('h3').style.color = '#4CAF50'; setTimeout(() => { historyPanel.querySelector('h3').textContent = oldTitle; historyPanel.querySelector('h3').style.color = '#64B5F6'; }, 2000); } else { alert('删除失败,记录不存在或已被删除!'); } } }); // —— 删除全部历史记录按钮事件 —— deleteAllHistoryBtn.addEventListener('click', () => { const recordCount = Object.keys(enhanceHistory).reduce((total, baseItem) => { return total + (enhanceHistory[baseItem].sessions ? enhanceHistory[baseItem].sessions.length : 0); }, 0); if (recordCount === 0) { alert('没有历史记录可以删除!'); return; } if (confirm(`确定要删除全部 ${recordCount} 条强化历史记录吗?\n\n此操作将清除所有物品的强化历史,无法撤销!`)) { const deletedCount = deleteAllHistory(); // 刷新列表显示 showHistoryList(); // 显示删除成功提示 const oldTitle = historyPanel.querySelector('h3').textContent; historyPanel.querySelector('h3').textContent = `✅ 已删除 ${deletedCount} 条记录`; historyPanel.querySelector('h3').style.color = '#4CAF50'; setTimeout(() => { historyPanel.querySelector('h3').textContent = oldTitle; historyPanel.querySelector('h3').style.color = '#64B5F6'; }, 3000); } }); // —— 拦截全局 WebSocket(增强助手命名空间) —— const NativeWS = unsafeWindow.WebSocket; // 检查是否已经被其他脚本拦截 if (!unsafeWindow.WebSocket.__enhanceHelperIntercepted) { const OriginalWebSocket = unsafeWindow.WebSocket; unsafeWindow.WebSocket = function (url, protocols) { const ws = protocols ? new OriginalWebSocket(url, protocols) : new OriginalWebSocket(url); // 保存当前WebSocket实例 unsafeWindow.currentWS = ws; // —— 拦截 send —— const originalSend = ws.send; ws.__originalSend = originalSend; // 保存原始方法供自动强化使用 ws.send = function (data) { // 检查是否为强化请求 if (isEnhanceRequest(data)) { const enhanceData = parseEnhanceData(data); if (enhanceData && enhanceData.fullPayload) { // 储存完整的强化数据供后续自动使用 storedEnhanceData = enhanceData.fullPayload; saveStoredRequest(); // 保存到本地存储 updateProtectDisplay(); // 更新保护材料显示 // 保存用户名到本地存储 if (enhanceData.user && !savedUserName) { savedUserName = enhanceData.user; saveConfig(); // 保存用户名到本地存储 } // 检测到手动强化指令,如果批量次数为0,设为1 if (currentBatchCount === 0) { currentBatchCount = 1; batchCountInput.value = 1; BATCH_COUNT = 1; saveConfig(); // 保存批量次数 updateMinimizedDisplay(); // 更新收起状态显示 } // Debug模式记录强化请求保存 if (DEBUG_MODE) { console.group('💾 [强化助手] 保存强化请求数据'); console.log('原始数据:', data); console.log('保存的完整数据:', storedEnhanceData); console.log('解析结果:', { 物品ID: enhanceData.resourceId, 保护材料ID: enhanceData.protectedResourceId || '无', 用户: enhanceData.user, 批量次数设置: currentBatchCount, 时间: new Date().toLocaleTimeString() }); console.groupEnd(); } } // Debug模式记录强化请求拦截 if (DEBUG_MODE) { console.group('🔨 [强化助手] 拦截到强化请求'); console.log('原始数据:', data); if (enhanceData) { console.log('解析结果:', { 物品ID: enhanceData.resourceId, 保护材料ID: enhanceData.protectedResourceId || '无', 用户: enhanceData.user, 时间: new Date().toLocaleTimeString() }); } console.groupEnd(); } } // 正常发送原始请求,不影响游戏运行 originalSend.call(this, data); }; // —— 拦截接收消息并解压 —— // 保存原始的 onmessage 处理器(如果存在) const originalOnMessage = ws.onmessage; // 添加我们的消息监听器(不会替换游戏的处理器) // 使用 capture 阶段监听,确保不干扰游戏的正常消息处理 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 && (currentEnhanceItem || isAutoEnhancing)) { // Debug模式记录强化结果 if (DEBUG_MODE) { console.group('✨ [强化助手] 拦截到强化结果'); console.log('原始数据:', text); console.log('解析结果:', { 成功: enhanceResult.success, 消息: enhanceResult.message, 结果物品ID: enhanceResult.resultId, 用户: enhanceResult.user, 时间: new Date().toLocaleTimeString() }); // 如果有保存的请求数据,也显示相关信息 if (storedEnhanceData && storedEnhanceData.data) { console.log('关联的请求信息:', { 原始物品ID: storedEnhanceData.data.resourceId, 保护材料ID: storedEnhanceData.data.protectedResourceId || '无' }); } console.groupEnd(); } // 异步处理强化结果,避免阻塞游戏的消息处理 // 使用更长的延迟,确保游戏先处理完消息 setTimeout(() => { try { handleEnhanceResult(enhanceResult); } catch (error) { if (DEBUG_MODE) { console.error('[强化助手] 异步处理强化结果时发生错误:', error); } } }, 50); // 增加延迟到50ms,让游戏有足够时间处理消息 } } catch (err) { // 解压失败,忽略 if (DEBUG_MODE) { console.warn('[强化助手] 消息解压失败:', err); } } } // 注意:不阻止事件传播,让游戏的原始处理器也能处理消息 }); // WebSocket关闭时清理 ws.addEventListener('close', () => { if (isAutoEnhancing) { stopAutoEnhance(); isAutoEnhancing = false; updateToggleButtonState(); statusSpan.textContent = '连接断开'; statusSpan.style.color = '#f44336'; counterSpan.textContent = '离线'; updateMinimizedDisplay(); // 连接断开时重置继续强化标记和上次强化记录 isContinuedFromHistory = false; lastEnhanceBaseItem = null; } }); return ws; }; // 继承原型与静态属性 unsafeWindow.WebSocket.prototype = OriginalWebSocket.prototype; Object.getOwnPropertyNames(OriginalWebSocket).forEach(prop => { if (!(prop in unsafeWindow.WebSocket)) { unsafeWindow.WebSocket[prop] = OriginalWebSocket[prop]; } }); // 标记已被强化助手拦截 unsafeWindow.WebSocket.__enhanceHelperIntercepted = true; } // —— 窗口大小改变时检查面板位置 —— window.addEventListener('resize', () => { const rect = panel.getBoundingClientRect(); const rightDistance = window.innerWidth - rect.right; const topDistance = rect.top; // 检查并应用边界约束 const constrained = constrainPosition(rightDistance, topDistance); // 如果位置需要调整,立即应用 if (constrained.x !== rightDistance || constrained.y !== topDistance) { panel.style.right = constrained.x + 'px'; panel.style.top = constrained.y + 'px'; panel.style.left = 'auto'; savePosition(constrained.x, constrained.y); } }); // —— 数据库服务类 —— class SupabaseService { constructor(config) { this.url = config.url; this.key = config.key; this.headers = { 'apikey': config.key, 'Authorization': `Bearer ${config.key}`, 'Content-Type': 'application/json' }; } /** * 执行HTTP请求的通用方法 */ _request(method, url, options = {}) { return new Promise((resolve, reject) => { // 检查是否有 GM_xmlhttpRequest 可用 if (typeof GM_xmlhttpRequest !== 'undefined') { const requestConfig = { method: method, url: url, headers: { ...this.headers, ...options.headers }, onload: (response) => { if (response.status >= 200 && response.status < 300) { try { const data = response.responseText ? JSON.parse(response.responseText) : null; resolve(data); } catch (e) { reject(new Error('解析响应数据失败: ' + e.message)); } } else { reject(new Error(`HTTP ${response.status}: ${response.responseText}`)); } }, onerror: (error) => reject(new Error('网络请求失败: ' + error.message)) }; if (options.data) { requestConfig.data = JSON.stringify(options.data); } GM_xmlhttpRequest(requestConfig); } else { // 备用方案:使用 fetch (可能受到 CORS 限制) const fetchOptions = { method: method, headers: { ...this.headers, ...options.headers } }; if (options.data) { fetchOptions.body = JSON.stringify(options.data); } fetch(url, fetchOptions) .then(response => { if (response.ok) { return response.text(); } else { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } }) .then(text => { try { const data = text ? JSON.parse(text) : null; resolve(data); } catch (e) { reject(new Error('解析响应数据失败: ' + e.message)); } }) .catch(error => { reject(new Error(`网络请求失败: ${error.message}. 请确保油猴脚本权限配置正确。`)); }); } }); } /** * 构建查询URL参数 */ _buildQueryParams(options) { const params = new URLSearchParams(); if (options.select) params.append('select', options.select); if (options.eq) { Object.entries(options.eq).forEach(([key, value]) => { params.append(key, `eq.${value}`); }); } if (options.limit) params.append('limit', options.limit); if (options.order) params.append('order', options.order); if (options.offset) params.append('offset', options.offset); return params.toString(); } /** * 查询数据 */ async select(table, options = {}) { let url = `${this.url}/rest/v1/${table}`; const queryParams = this._buildQueryParams(options); if (queryParams) { url += '?' + queryParams; } return await this._request('GET', url); } /** * 插入数据 */ async insert(table, data) { const url = `${this.url}/rest/v1/${table}`; const headers = { 'Prefer': 'return=representation' }; return await this._request('POST', url, { data, headers }); } /** * 更新数据 */ async update(table, data, conditions) { let url = `${this.url}/rest/v1/${table}`; if (conditions) { const params = new URLSearchParams(); Object.entries(conditions).forEach(([key, value]) => { params.append(key, `eq.${value}`); }); url += '?' + params.toString(); } const headers = { 'Prefer': 'return=representation' }; return await this._request('PATCH', url, { data, headers }); } /** * UPSERT操作 - 插入或更新数据,避免409冲突 * @param {string} table - 表名 * @param {Object} data - 要插入/更新的数据 * @param {string|Array} onConflict - 冲突检测的列名(字符串或数组) * @param {Object} options - 额外选项 * @returns {Promise} 操作结果 */ async upsert(table, data, onConflict = null, options = {}) { const url = `${this.url}/rest/v1/${table}`; // 构建请求头 - 使用正确的Supabase UPSERT语法 const headers = { 'Prefer': 'resolution=merge-duplicates,return=representation', 'Content-Type': 'application/json' }; // 构建请求体 const requestBody = data; // 构建URL参数 const params = new URLSearchParams(); // 如果指定了冲突列,添加到URL参数中 if (onConflict) { const conflictStr = Array.isArray(onConflict) ? onConflict.join(',') : onConflict; params.append('on_conflict', conflictStr); } let requestUrl = url; if (params.toString()) { requestUrl += '?' + params.toString(); } // 使用POST方法进行UPSERT try { return await this._request('POST', requestUrl, { data: requestBody, headers }); } catch (error) { // 如果遇到409冲突,尝试使用更新操作作为后备方案 if (error.message.includes('409') || error.message.includes('duplicate key')) { console.warn('[SupabaseService] UPSERT失败,尝试更新操作作为后备方案...'); // 构建更新条件 const conditions = {}; const conflictCols = Array.isArray(onConflict) ? onConflict : (onConflict ? [onConflict] : []); conflictCols.forEach(col => { if (data[col] !== undefined) { conditions[col] = data[col]; } }); // 如果没有冲突列信息,无法构建更新条件 if (Object.keys(conditions).length === 0) { throw new Error('无法执行更新操作:缺少冲突列信息'); } return await this.update(table, data, conditions); } throw error; } } } // —— 创建数据库服务实例 —— const supabaseService = new SupabaseService(SUPABASE_CONFIG); // —— 检查权限配置 —— function checkPermissions() { if (typeof GM_xmlhttpRequest === 'undefined') { console.warn('[强化助手] GM_xmlhttpRequest 不可用,弱化之王功能可能受限'); console.warn('[强化助手] 请确保油猴脚本的 @grant GM_xmlhttpRequest 权限已正确配置'); return false; } return true; } // —— 弱化之王功能 —— let weakKingPanel = null; let isWeakKingPanelOpen = false; // —— 创建弱化之王面板 —— function createWeakKingPanel() { weakKingPanel = document.createElement('div'); weakKingPanel.id = 'enhanceHelper_weakKingPanel'; weakKingPanel.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 500px; max-height: 80vh; padding: 16px; background: rgba(25,35,45,0.98); color: #fff; font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; border-radius: 12px; z-index: 10001; border: 1px solid rgba(255,215,0,0.4); box-shadow: 0 8px 32px rgba(0,0,0,0.6); backdrop-filter: blur(8px); display: none; overflow-y: auto; `; weakKingPanel.innerHTML = `

👑 弱化之王排行榜

"即使土豆早已发芽,也请您成为弱化之王"
👑
请先选择一个强化物品
`; document.body.appendChild(weakKingPanel); // 绑定关闭按钮事件 document.getElementById('enhanceHelper_closeWeakKingBtn').addEventListener('click', closeWeakKingPanel); } // —— 打开弱化之王面板 —— function openWeakKingPanel() { if (!weakKingPanel) { createWeakKingPanel(); } isWeakKingPanelOpen = true; weakKingPanel.style.display = 'block'; loadWeakKingData(); } // —— 关闭弱化之王面板 —— function closeWeakKingPanel() { isWeakKingPanelOpen = false; if (weakKingPanel) { weakKingPanel.style.display = 'none'; } } // —— 加载弱化之王数据 —— async function loadWeakKingData() { const contentEl = document.getElementById('enhanceHelper_weakKingContent'); if (!currentEnhanceItem) { contentEl.innerHTML = `
👑
请先选择一个强化物品
`; return; } // 构造查询的物品名称(基础物品名 + 目标等级) const currentItemInfo = parseItemLevel(currentEnhanceItem.resourceId); const targetItemName = `${currentItemInfo.baseItem}+${TARGET_LEVEL}`; contentEl.innerHTML = `
🔍
正在查询 ${translateItemId(targetItemName)} 的排行榜数据...
`; try { // 查询数据库中该物品的记录(按次数降序排列,次数越高排名越前) const records = await supabaseService.select(TABLE_NAME, { eq: { item_name: targetItemName }, order: 'enhance_num.desc' }); // 获取当前用户的强化统计 const currentUserName = savedUserName || (currentEnhanceItem.user || 'Unknown'); const currentAttempts = enhanceStats.totalAttempts || 0; displayWeakKingResults(targetItemName, records, currentUserName, currentAttempts); } catch (error) { contentEl.innerHTML = `
查询失败: ${error.message}
请检查网络连接或数据库配置
`; } } // —— 显示弱化之王结果 —— function displayWeakKingResults(targetItemName, records, currentUserName, currentAttempts) { const contentEl = document.getElementById('enhanceHelper_weakKingContent'); let html = `
🎯 目标物品: ${translateItemId(targetItemName)}
当前用户: ${currentUserName} | 当前尝试次数: ${currentAttempts}
`; if (records.length === 0) { html += `
🏆
暂无 ${translateItemId(targetItemName)} 的弱化记录
成为第一个弱化之王!
`; // 如果有尝试次数,显示上传按钮 if (currentAttempts > 0) { html += `
`; } } else { // 显示弱化排行榜(次数越高越厉害) const bestRecord = records[0]; const canUpload = currentAttempts > 0 && currentAttempts > bestRecord.enhance_num; html += `

🏆 弱化之王排行榜

`; records.forEach((record, index) => { const isCurrentUser = record.player_name === currentUserName; const rankIcon = index === 0 ? '🥇' : (index === 1 ? '🥈' : (index === 2 ? '🥉' : `${index + 1}.`)); html += `
${rankIcon} ${record.player_name}${isCurrentUser ? ' (我)' : ''}
${record.enhance_num}次
`; }); html += `
`; // 显示自己的统计 html += `
📊 我的统计
当前尝试次数: ${currentAttempts}次
当前弱化之王: ${bestRecord.enhance_num}次 (${bestRecord.player_name})
`; // 如果可以上传,显示上传按钮 if (canUpload) { html += `
🎉 恭喜!你超越了当前弱化之王!
`; } else if (currentAttempts > 0) { html += `
还需要努力哦!目标: 超过 ${bestRecord.enhance_num} 次成为弱化之王
`; } } contentEl.innerHTML = html; // 绑定上传按钮事件 const uploadBtn = document.getElementById('enhanceHelper_uploadWeakKingBtn'); if (uploadBtn) { uploadBtn.addEventListener('click', () => uploadWeakKingRecord(targetItemName, currentUserName, currentAttempts)); } } // —— 上传弱化之王记录 —— async function uploadWeakKingRecord(itemName, playerName, attempts) { const uploadBtn = document.getElementById('enhanceHelper_uploadWeakKingBtn'); if (!uploadBtn) return; const originalText = uploadBtn.textContent; uploadBtn.disabled = true; uploadBtn.textContent = '上传中...'; // 添加防重复提交保护 const uploadKey = `${itemName}_${playerName}_${attempts}`; const lastUploadKey = uploadBtn.dataset.lastUpload; if (lastUploadKey === uploadKey) { uploadBtn.disabled = false; uploadBtn.textContent = originalText; return; } uploadBtn.dataset.lastUpload = uploadKey; try { // 先查询是否已存在记录 const existingRecords = await supabaseService.select(TABLE_NAME, { eq: { item_name: itemName, player_name: playerName } }); let result; if (existingRecords && existingRecords.length > 0) { // 记录已存在,执行更新操作 result = await supabaseService.update(TABLE_NAME, { enhance_num: attempts }, { item_name: itemName, player_name: playerName }); // Debug模式记录更新操作 if (DEBUG_MODE) { console.group('👑 [强化助手] 弱化之王记录更新'); console.log('更新结果:', { 物品: itemName, 玩家: playerName, 尝试次数: attempts, 操作类型: '更新现有记录', 操作结果: result ? '成功' : '未知', 时间: new Date().toLocaleString() }); console.groupEnd(); } } else { // 记录不存在,执行插入操作 result = await supabaseService.insert(TABLE_NAME, { item_name: itemName, player_name: playerName, enhance_num: attempts }); // Debug模式记录插入操作 if (DEBUG_MODE) { console.group('👑 [强化助手] 弱化之王记录插入'); console.log('插入结果:', { 物品: itemName, 玩家: playerName, 尝试次数: attempts, 操作类型: '插入新记录', 操作结果: result ? '成功' : '未知', 时间: new Date().toLocaleString() }); console.groupEnd(); } } // 显示成功提示 const oldTitle = weakKingPanel.querySelector('h3').textContent; weakKingPanel.querySelector('h3').textContent = '✅ 记录上传成功!'; weakKingPanel.querySelector('h3').style.color = '#4CAF50'; setTimeout(() => { weakKingPanel.querySelector('h3').textContent = oldTitle; weakKingPanel.querySelector('h3').style.color = '#FFD700'; }, 2000); // 重新加载数据 setTimeout(() => { loadWeakKingData(); }, 1000); } catch (error) { // 处理可能的竞争条件:如果在查询和插入之间有其他用户插入了相同的记录 if ((error.message.includes('409') || error.message.includes('duplicate key')) && !error.message.includes('update')) { // 出现重复键错误,说明在我们查询后有人插入了记录,尝试更新 try { const result = await supabaseService.update(TABLE_NAME, { enhance_num: attempts }, { item_name: itemName, player_name: playerName }); // 更新成功,显示成功提示 const oldTitle = weakKingPanel.querySelector('h3').textContent; weakKingPanel.querySelector('h3').textContent = '✅ 记录更新成功!'; weakKingPanel.querySelector('h3').style.color = '#4CAF50'; setTimeout(() => { weakKingPanel.querySelector('h3').textContent = oldTitle; weakKingPanel.querySelector('h3').style.color = '#FFD700'; }, 2000); setTimeout(() => { loadWeakKingData(); }, 1000); uploadBtn.disabled = false; uploadBtn.textContent = originalText; return; } catch (retryError) { error.message = `竞争条件处理失败: ${retryError.message}`; } } // 错误处理和用户友好提示 let errorMessage = error.message; if (error.message.includes('network') || error.message.includes('timeout')) { errorMessage = '网络连接失败,请检查网络后重试'; } else if (error.message.includes('permission') || error.message.includes('unauthorized')) { errorMessage = '权限不足,请检查数据库配置'; } else if (error.message.includes('42P10')) { errorMessage = '数据库表结构配置问题,请联系开发者'; } alert(`上传失败: ${errorMessage}`); // Debug模式记录错误详情 if (DEBUG_MODE) { console.group('❌ [强化助手] 弱化之王记录上传失败'); console.error('错误详情:', { 原始错误: error.message, 处理后错误: errorMessage, 物品: itemName, 玩家: playerName, 尝试次数: attempts, 时间: new Date().toLocaleString() }); console.groupEnd(); } uploadBtn.disabled = false; uploadBtn.textContent = originalText; // 清除防重复标记,允许重试 delete uploadBtn.dataset.lastUpload; } } })();