MWI_Toolkit

MWI工具集

À partir de 2025-10-29. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         MWI_Toolkit
// @namespace    http://tampermonkey.net/
// @version      5.0.4
// @description  MWI工具集
// @author       zqzhang1996
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/libs/lz-string.min.js
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-body
// @license      MIT
// ==/UserScript==
(function () {
    'use strict';
    //#region Calculator
    class TargetItemCategory {
        constructor(categoryHrid, needCalc = true) {
            this.needCalc = true;
            this.categoryDetailsElement = null;
            this.categorySummaryElement = null;
            this.needCalcCheckbox = null;
            this.categoryHrid = categoryHrid;
            this.needCalc = needCalc;
        }
        updateDisplayElement() {
            this.categoryDetailsElement.style.background = this.needCalc ? '#0E4F32' : '#2c2e45';
            this.categorySummaryElement.style.background = this.needCalc ? '#147147' : '#393a5b';
            this.needCalcCheckbox.checked = this.needCalc;
        }
    }
    class DisplayItem {
        constructor(itemHrid, count) {
            this.itemHrid = itemHrid;
            this.count = count;
            this.initDisplayProperties();
        }
        initDisplayProperties() {
            if (Object.values(MWI_Toolkit_ActionDetailPlus.processableItemList).includes(this.itemHrid)) {
                this.categoryHrid = '/item_categories/materials';
            }
            else {
                this.categoryHrid = MWI_Toolkit.initClientData?.itemDetailMap?.[this.itemHrid].categoryHrid;
            }
            this.displayName = MWI_Toolkit_I18n.getItemName(this.itemHrid);
            this.iconHref = MWI_Toolkit_Utils.getIconHrefByItemHrid(this.itemHrid);
            this.sortIndex = MWI_Toolkit_Utils.getSortIndexByItemHrid(this.itemHrid);
        }
        getOwnedCount() {
            return MWI_Toolkit_ItemsMap.getCount(this.itemHrid);
        }
    }
    class TargetItem extends DisplayItem {
        constructor(itemHrid, count, needCalc = true) {
            super(itemHrid, count);
            this.needCalc = true;
            this.displayElement = null;
            this.needCalcCheckbox = null;
            this.ownedSpan = null;
            this.targetInput = null;
            this.needCalc = needCalc;
        }
        updateDisplayElement() {
            if (this.needCalcCheckbox) {
                this.needCalcCheckbox.checked = this.needCalc;
                this.displayElement.style.background = this.needCalc ? '' : '#2c2e45';
            }
            if (this.ownedSpan) {
                const newText = MWI_Toolkit_Utils.formatNumber(this.getOwnedCount());
                if (this.ownedSpan.textContent !== newText) {
                    this.ownedSpan.textContent = newText;
                }
            }
            if (this.targetInput) {
                const newText = this.count.toString();
                if (this.targetInput.value.trim() === '' && this.count != 0) {
                    this.targetInput.value = newText;
                }
            }
        }
        removeDisplayElement() {
            this.displayElement?.remove();
        }
    }
    class TargetHouseRoom extends TargetItem {
        constructor(houseRoomHrid, level, needCalc = true) {
            super(houseRoomHrid, level, needCalc);
        }
        initDisplayProperties() {
            this.categoryHrid = '/item_categories/house_rooms';
            this.displayName = MWI_Toolkit_I18n.getName(this.itemHrid, 'houseRoomNames');
            this.iconHref = MWI_Toolkit_Utils.getIconHrefByHouseRoomHrid(this.itemHrid);
            this.sortIndex = MWI_Toolkit_Utils.getSortIndexByHouseRoomHrid(this.itemHrid);
        }
        getOwnedCount() {
            return MWI_Toolkit.gameObject?.state?.characterHouseRoomDict?.[this.itemHrid]?.level || 0;
        }
    }
    class RequiredItem extends DisplayItem {
        constructor(itemHrid, count, equivalentCount) {
            super(itemHrid, count);
            this.equivalentCount = 0;
            this.shortageDisplayElement = null;
            this.requiredDisplayElement = null;
            this.shortageSpan = null;
            this.ownedSpan = null;
            this.equivalentSpan = null;
            this.requiredSpan = null;
            this.requiredDiv = null;
            this.equivalentCount = equivalentCount;
        }
        getShortageCount() {
            return this.count - this.getOwnedCount() - this.equivalentCount;
        }
        updateDisplayElement() {
            const ownedCount = this.getOwnedCount();
            const shortageCount = this.getShortageCount();
            if (this.shortageSpan) {
                const newText = MWI_Toolkit_Utils.formatNumber(shortageCount);
                if (this.shortageSpan.textContent !== newText) {
                    this.shortageSpan.textContent = newText;
                }
                this.shortageDisplayElement.style.display = shortageCount > 0 ? 'flex' : 'none';
            }
            if (this.equivalentSpan) {
                const newText = MWI_Toolkit_Utils.formatNumber(this.equivalentCount) + '+';
                if (this.equivalentSpan.textContent !== newText) {
                    this.equivalentSpan.textContent = newText;
                }
                this.equivalentSpan.hidden = this.equivalentCount <= 0;
            }
            if (this.ownedSpan) {
                const newText = MWI_Toolkit_Utils.formatNumber(ownedCount) + '/';
                if (this.ownedSpan.textContent !== newText) {
                    this.ownedSpan.textContent = newText;
                }
            }
            if (this.requiredSpan) {
                const newText = MWI_Toolkit_Utils.formatNumber(this.count);
                if (this.requiredSpan.textContent !== newText) {
                    this.requiredSpan.textContent = newText;
                }
                this.requiredDiv.style.color = shortageCount > 0 ? '#f44336' : '#E7E7E7';
            }
        }
        removeDisplayElement() {
            this.shortageDisplayElement?.remove();
            this.requiredDisplayElement?.remove();
        }
    }
    class MWI_Toolkit_Calculator {
        static getStorageKey(characterID = null) {
            if (!characterID) {
                characterID = MWI_Toolkit?.gameObject?.state?.character?.id;
            }
            return `MWI_Toolkit_Calculator_TargetItems_${characterID}`;
        }
        // 保存目标物品
        static saveTargetItems() {
            const storageKey = MWI_Toolkit_Calculator.getStorageKey();
            const storageKey_Category = storageKey.replace('TargetItems', 'TargetItemCategories');
            const dataToSave = [...MWI_Toolkit_Calculator.targetItemsMap.values()].map(item => ({
                itemHrid: item.itemHrid,
                count: item.count,
                needCalc: item.needCalc
            }));
            const dataToSave_Category = [...MWI_Toolkit_Calculator.targetItemCategoryMap.values()].map(category => ({
                categoryHrid: category.categoryHrid,
                needCalc: category.needCalc
            }));
            try {
                GM_setValue(storageKey, JSON.stringify(dataToSave));
                GM_setValue(storageKey_Category, JSON.stringify(dataToSave_Category));
                return true;
            }
            catch (error) {
                console.error('[MWI_Toolkit]' + error);
                return false;
            }
        }
        // 从特定角色ID加载数据
        static loadTargetItems(characterID = null) {
            const storageKey = MWI_Toolkit_Calculator.getStorageKey(characterID);
            const storageKey_Category = storageKey.replace('TargetItems', 'TargetItemCategories');
            try {
                const savedData = GM_getValue(storageKey, '[]');
                const savedData_Category = GM_getValue(storageKey_Category, '[]');
                const loadedItems = JSON.parse(savedData);
                const loadedCategories = JSON.parse(savedData_Category);
                // 验证并转换为Item实例
                const validItemsMap = new Map(loadedItems.map((item) => {
                    try {
                        if (item.itemHrid.includes('/items/')) {
                            return [item.itemHrid, new TargetItem(item.itemHrid, item.count, typeof item.needCalc === 'boolean' ? item.needCalc : true)];
                        }
                        if (item.itemHrid.includes('/house_rooms/')) {
                            return [item.itemHrid, new TargetHouseRoom(item.itemHrid, item.count, typeof item.needCalc === 'boolean' ? item.needCalc : true)];
                        }
                    }
                    catch {
                        return null;
                    }
                }).filter((item) => item !== null));
                loadedCategories.forEach((category) => {
                    if (MWI_Toolkit_Calculator.targetItemCategoryMap.has(category.categoryHrid)) {
                        MWI_Toolkit_Calculator.targetItemCategoryMap.get(category.categoryHrid).needCalc = category.needCalc;
                    }
                    else {
                        MWI_Toolkit_Calculator.targetItemCategoryMap.set(category.categoryHrid, new TargetItemCategory(category.categoryHrid, category.needCalc));
                    }
                });
                if (validItemsMap.size > 0) {
                    MWI_Toolkit_Calculator.clearAllTargetItems();
                    MWI_Toolkit_Calculator.targetItemsMap = validItemsMap;
                    MWI_Toolkit_Calculator.renderItemsDisplay();
                    MWI_Toolkit_Calculator.saveTargetItems();
                }
            }
            catch (error) {
                console.error('[MWI_Toolkit]' + error);
            }
        }
        // 更新目标物品
        static updateTargetItem(itemHrid, count = 1) {
            if (!itemHrid)
                return;
            const item = MWI_Toolkit_Calculator.targetItemsMap.get(itemHrid);
            if (item) {
                item.count = count;
            }
            else {
                // 添加新物品
                if (itemHrid.includes('/items/')) {
                    MWI_Toolkit_Calculator.targetItemsMap.set(itemHrid, new TargetItem(itemHrid, count));
                }
                if (itemHrid.includes('/house_rooms/')) {
                    MWI_Toolkit_Calculator.targetItemsMap.set(itemHrid, new TargetHouseRoom(itemHrid, count));
                }
            }
            MWI_Toolkit_Calculator.saveAndScheduleRender();
        }
        // 删除目标物品
        static removeTargetItem(itemHrid) {
            if (!itemHrid)
                return;
            MWI_Toolkit_Calculator.targetItemsMap.get(itemHrid)?.removeDisplayElement();
            MWI_Toolkit_Calculator.targetItemsMap.delete(itemHrid);
            MWI_Toolkit_Calculator.saveAndScheduleRender();
        }
        // 清空目标物品
        static clearAllTargetItems() {
            MWI_Toolkit_Calculator.targetItemsMap.forEach(item => item.removeDisplayElement());
            MWI_Toolkit_Calculator.targetItemsMap.clear();
            MWI_Toolkit_Calculator.saveAndScheduleRender();
        }
        // 保存数据并计划渲染
        static saveAndScheduleRender() {
            // 保存数据到存储
            MWI_Toolkit_Calculator.saveTargetItems();
            MWI_Toolkit_Calculator.scheduleRender();
        }
        // 计划延迟渲染
        static scheduleRender() {
            // 清除之前的计时器
            if (MWI_Toolkit_Calculator.renderTimeout) {
                clearTimeout(MWI_Toolkit_Calculator.renderTimeout);
            }
            // 设置新的计时器
            MWI_Toolkit_Calculator.renderTimeout = setTimeout(() => {
                MWI_Toolkit_Calculator.renderItemsDisplay();
                MWI_Toolkit_Calculator.renderTimeout = null;
            }, 300); // 300ms 防抖延迟
        }
        // 递归计算所需材料
        static calculateRequiredItems(targetItem) {
            if (targetItem.count === 0)
                return [];
            if (targetItem.itemHrid.includes('/house_rooms/')) {
                // 处理房屋房间逻辑
                return this.calculateRequiredItemsForHouseRoom(targetItem.itemHrid, targetItem.count);
            }
            let requiredItems = new Array();
            requiredItems.push({ itemHrid: targetItem.itemHrid, count: targetItem.count });
            const actionTypes = ["cheesesmithing", "crafting", "tailoring", "cooking", "brewing"];
            const itemName = targetItem.itemHrid.split('/').pop();
            for (const actionType of actionTypes) {
                const actionHrid = `/actions/${actionType}/${itemName}`;
                if (MWI_Toolkit.initClientData?.actionDetailMap?.hasOwnProperty(actionHrid)) {
                    const actionDetail = MWI_Toolkit.initClientData?.actionDetailMap[actionHrid];
                    const upgradeItemHrid = actionDetail.upgradeItemHrid;
                    const inputItems = actionDetail.inputItems;
                    let outputCount = 1;
                    const outputItems = actionDetail.outputItems;
                    if (outputItems && outputItems.length > 0) {
                        const matchingOutput = outputItems.find(output => output.itemHrid === targetItem.itemHrid);
                        if (matchingOutput) {
                            outputCount = matchingOutput.count;
                        }
                    }
                    const actionTypeDrinkSlots = MWI_Toolkit_ActionDetailPlus.getActionTypeDrinkSlots(actionType);
                    // 检查工匠茶加成
                    let artisanBuff = 0;
                    if (actionTypeDrinkSlots?.some(itemHrid => itemHrid === '/items/artisan_tea')) {
                        artisanBuff = 0.1 * MWI_Toolkit_ActionDetailPlus.getDrinkConcentration();
                    }
                    // 检查美食茶加成
                    let gourmetBuff = 0;
                    if (actionTypeDrinkSlots?.some(itemHrid => itemHrid === '/items/gourmet_tea')) {
                        gourmetBuff = 0.12 * MWI_Toolkit_ActionDetailPlus.getDrinkConcentration();
                    }
                    // 递归计算输入材料
                    for (const input of inputItems) {
                        const adjustedCount = input.count * targetItem.count / outputCount / (1 + gourmetBuff) * (1 - artisanBuff);
                        requiredItems = MWI_Toolkit_Calculator.mergeItemArrays(requiredItems, MWI_Toolkit_Calculator.calculateRequiredItems({ itemHrid: input.itemHrid, count: adjustedCount }));
                    }
                    // 处理升级物品(不适用工匠茶加成)
                    if (upgradeItemHrid) {
                        requiredItems = MWI_Toolkit_Calculator.mergeItemArrays(requiredItems, MWI_Toolkit_Calculator.calculateRequiredItems({ itemHrid: upgradeItemHrid, count: targetItem.count / outputCount / (1 + gourmetBuff) }));
                    }
                    return requiredItems;
                }
            }
            // 添加地下城代币兑换材料计算
            if (requiredItems.length === 1) {
                const shopHrid = `/shop_items/${itemName}`;
                if (MWI_Toolkit.initClientData?.shopItemDetailMap?.hasOwnProperty(shopHrid)) {
                    const shopItemDetail = MWI_Toolkit.initClientData?.shopItemDetailMap[shopHrid];
                    if (shopItemDetail.category === "/shop_categories/dungeon") {
                        shopItemDetail.costs.forEach(cost => {
                            requiredItems.push({ itemHrid: cost.itemHrid, count: cost.count * targetItem.count });
                        });
                    }
                }
            }
            return requiredItems;
        }
        // 批量计算材料需求
        static batchCalculateRequiredItems(targetItems) {
            let allRequiredItems = new Array();
            for (const targetItem of targetItems) {
                const requiredItems = MWI_Toolkit_Calculator.calculateRequiredItems(targetItem);
                allRequiredItems = MWI_Toolkit_Calculator.mergeItemArrays(allRequiredItems, requiredItems);
            }
            return allRequiredItems;
        }
        // 计算房屋房间所需材料
        static calculateRequiredItemsForHouseRoom(targetHouseRoomHrid, targetHouseRoomLevel) {
            let targetItems = Array();
            const characterHouseRoomLevel = MWI_Toolkit.gameObject.state.characterHouseRoomDict?.[targetHouseRoomHrid]?.level || 0;
            const upgradeCostsMap = MWI_Toolkit.initClientData?.houseRoomDetailMap?.[targetHouseRoomHrid]?.upgradeCostsMap;
            for (let i = characterHouseRoomLevel + 1; i <= targetHouseRoomLevel && i <= 8; i++) {
                targetItems = targetItems.concat(upgradeCostsMap[i] || []);
            }
            return MWI_Toolkit_Calculator.batchCalculateRequiredItems(targetItems);
        }
        // 计算等效材料
        static calculateEquivalentItems(requiredItems) {
            const ownedItems = new Array();
            const ownedItemsNG = new Array();
            for (const requiredItem of requiredItems) {
                const ownedCount = MWI_Toolkit_ItemsMap.getCount(requiredItem.itemHrid);
                // 负目标数量用于手动标记已有的等效物品
                const targetItemNG = MWI_Toolkit_Calculator.targetItemsMap.get(requiredItem.itemHrid);
                const targetCountNG = Math.min((targetItemNG?.needCalc && targetItemNG?.count) ? targetItemNG.count : 0, 0);
                // 这里count取required和owned-equivalent中的较小值,用于抵消需求
                ownedItems.push({ itemHrid: requiredItem.itemHrid, count: Math.min(requiredItem.count, ownedCount - targetCountNG) });
                ownedItemsNG.push({ itemHrid: requiredItem.itemHrid, count: Math.min(requiredItem.count, ownedCount) * -1 });
            }
            // 减掉原值得到等效值
            return MWI_Toolkit_Calculator.mergeItemArrays(MWI_Toolkit_Calculator.batchCalculateRequiredItems(ownedItems), ownedItemsNG);
        }
        // 合并材料数组并按排序顺序返回
        static mergeItemArrays(arr1, arr2) {
            const map = new Map();
            for (const item of arr1.concat(arr2)) {
                if (map.has(item.itemHrid)) {
                    if (item.itemHrid.includes('/items/')) {
                        map.get(item.itemHrid).count += item.count;
                    }
                    if (item.itemHrid.includes('/house_rooms/')) {
                        map.get(item.itemHrid).count = Math.max(map.get(item.itemHrid).count, item.count);
                    }
                }
                else {
                    map.set(item.itemHrid, { itemHrid: item.itemHrid, count: item.count });
                }
            }
            // 排序
            return Array.from(map.values()).sort((a, b) => MWI_Toolkit_Utils.getSortIndexByItemHrid(a.itemHrid) - MWI_Toolkit_Utils.getSortIndexByItemHrid(b.itemHrid));
        }
        static initialize() {
            MWI_Toolkit_ItemsMap.itemsUpdatedCallbacks.push((enditemsMap) => {
                MWI_Toolkit_Calculator.scheduleRender();
            });
        }
        static initializeCalculatorUI() {
            MWI_Toolkit.waitForElement('[class^="CharacterManagement_tabsComponentContainer"] [class*="TabsComponent_tabsContainer"]', () => {
                MWI_Toolkit_Calculator.createCalculatorUI();
            });
        }
        // 初始化UI
        static createCalculatorUI() {
            // 已有标签页则不重复初始化
            if (document.querySelector('[class^="Toolkit_Calculator_Container"]')) {
                return;
            }
            // 获取容器
            const tabsContainer = document.querySelector('[class^="CharacterManagement_tabsComponentContainer"] [class*="TabsComponent_tabsContainer"]');
            const tabPanelsContainer = document.querySelector('[class^="CharacterManagement_tabsComponentContainer"] [class*="TabsComponent_tabPanelsContainer"]');
            if (!tabsContainer || !tabPanelsContainer) {
                console.error('[MWI_Toolkit_Calculator] 无法找到标签页容器');
                return;
            }
            MWI_Toolkit_Calculator.createCalculatorTab(tabsContainer, tabPanelsContainer);
            MWI_Toolkit_Calculator.targetItemsMap = new Map();
            MWI_Toolkit_Calculator.requiredItemsMap = new Map();
            // 加载保存数据
            MWI_Toolkit_Calculator.loadTargetItems();
            console.log('[MWI_Toolkit_Calculator] UI初始化完成');
        }
        // 创建MWI计算器标签页
        static createCalculatorTab(tabsContainer, tabPanelsContainer) {
            // 新增"MWI计算器"按钮
            const oldTabButtons = tabsContainer.querySelectorAll("button");
            MWI_Toolkit_Calculator.tabButton = oldTabButtons[1].cloneNode(true);
            MWI_Toolkit_Calculator.tabButton.children[0].textContent = (MWI_Toolkit.getGameLanguage() === 'zh') ? 'MWI计算器' : 'MWI_Calculator';
            oldTabButtons[0].parentElement.appendChild(MWI_Toolkit_Calculator.tabButton);
            // 新增MWI计算器tabPanel
            const oldTabPanels = tabPanelsContainer.querySelectorAll('[class*="TabPanel_tabPanel"]');
            MWI_Toolkit_Calculator.tabPanel = oldTabPanels[1].cloneNode(false);
            oldTabPanels[0].parentElement.appendChild(MWI_Toolkit_Calculator.tabPanel);
            MWI_Toolkit_Calculator.bindCalculatorTabEvents(oldTabButtons, oldTabPanels);
            // 创建计算器面板
            const calculatorPanel = MWI_Toolkit_Calculator.createCalculatorPanel();
            MWI_Toolkit_Calculator.tabPanel.appendChild(calculatorPanel);
        }
        // 绑定标签页事件
        static bindCalculatorTabEvents(oldTabButtons, oldTabPanels) {
            for (let i = 0; i < oldTabButtons.length; i++) {
                oldTabButtons[i].addEventListener('click', () => {
                    MWI_Toolkit_Calculator.tabPanel.hidden = true; // 强制隐藏
                    MWI_Toolkit_Calculator.tabPanel.classList.add('TabPanel_hidden__26UM3');
                    MWI_Toolkit_Calculator.tabButton.classList.remove('Mui-selected');
                    MWI_Toolkit_Calculator.tabButton.setAttribute('aria-selected', 'false');
                    MWI_Toolkit_Calculator.tabButton.tabIndex = -1;
                    oldTabButtons[i].classList.add('Mui-selected');
                    oldTabButtons[i].setAttribute('aria-selected', 'true');
                    oldTabButtons[i].tabIndex = 0;
                    oldTabPanels[i].classList.remove('TabPanel_hidden__26UM3');
                    oldTabPanels[i].hidden = false; // 显示目标
                }, true);
            }
            MWI_Toolkit_Calculator.tabButton.addEventListener('click', () => {
                oldTabButtons.forEach(btn => {
                    btn.classList.remove('Mui-selected');
                    btn.setAttribute('aria-selected', 'false');
                    btn.tabIndex = -1;
                });
                oldTabPanels.forEach(panel => {
                    panel.hidden = true; // 强制隐藏
                    panel.classList.add('TabPanel_hidden__26UM3');
                });
                MWI_Toolkit_Calculator.tabButton.classList.add('Mui-selected');
                MWI_Toolkit_Calculator.tabButton.setAttribute('aria-selected', 'true');
                MWI_Toolkit_Calculator.tabButton.tabIndex = 0;
                MWI_Toolkit_Calculator.tabPanel.classList.remove('TabPanel_hidden__26UM3');
                MWI_Toolkit_Calculator.tabPanel.hidden = false; // 显示目标
            }, true);
        }
        // 创建计算器面板
        static createCalculatorPanel() {
            const calculatorPanel = document.createElement('div');
            calculatorPanel.className = 'Toolkit_Calculator_Container';
            // 创建物品搜索区域
            const addItemSection = MWI_Toolkit_Calculator.createAddItemSection();
            calculatorPanel.appendChild(addItemSection);
            // 左侧区域
            const leftDiv = document.createElement('div');
            leftDiv.style.display = 'inline-block';
            leftDiv.style.verticalAlign = 'top';
            leftDiv.style.width = '60%';
            leftDiv.style.padding = '0px 2px';
            MWI_Toolkit_Calculator.createItemDetailsMap(leftDiv, MWI_Toolkit_Calculator.targetItemDetailsMap);
            calculatorPanel.appendChild(leftDiv);
            MWI_Toolkit_Calculator.targetItemDetailsMap.forEach((details, categoryHrid) => {
                const summary = details.querySelector('summary');
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.style.verticalAlign = 'middle';
                if (!MWI_Toolkit_Calculator.targetItemCategoryMap.has(categoryHrid)) {
                    MWI_Toolkit_Calculator.targetItemCategoryMap.set(categoryHrid, new TargetItemCategory(categoryHrid));
                }
                MWI_Toolkit_Calculator.targetItemCategoryMap.get(categoryHrid).categoryDetailsElement = details;
                MWI_Toolkit_Calculator.targetItemCategoryMap.get(categoryHrid).categorySummaryElement = summary;
                MWI_Toolkit_Calculator.targetItemCategoryMap.get(categoryHrid).needCalcCheckbox = checkbox;
                checkbox.checked = MWI_Toolkit_Calculator.targetItemCategoryMap.get(categoryHrid).needCalc;
                checkbox.addEventListener('change', () => {
                    MWI_Toolkit_Calculator.targetItemCategoryMap.get(categoryHrid).needCalc = checkbox.checked;
                    MWI_Toolkit_Calculator.saveAndScheduleRender();
                });
                summary.prepend(checkbox);
            });
            // 右侧区域
            const rightDiv = document.createElement('div');
            rightDiv.style.display = 'inline-block';
            rightDiv.style.verticalAlign = 'top';
            rightDiv.style.width = '40%';
            rightDiv.style.padding = '0px 2px';
            const shortageItemDetails = document.createElement('details');
            shortageItemDetails.style.background = '#902f10';
            shortageItemDetails.style.borderRadius = '4px';
            shortageItemDetails.style.padding = '2px';
            shortageItemDetails.open = true;
            const shortageSummary = document.createElement('summary');
            shortageSummary.textContent = MWI_Toolkit.getGameLanguage() === 'zh' ? '缺口' : 'Shortages';
            shortageSummary.style.background = '#af3914';
            shortageSummary.style.borderRadius = '4px';
            shortageSummary.style.fontSize = '14px';
            shortageSummary.style.padding = '2px 6px';
            shortageSummary.style.textAlign = 'left';
            shortageSummary.style.cursor = 'pointer';
            shortageItemDetails.appendChild(shortageSummary);
            MWI_Toolkit_Calculator.createItemDetailsMap(shortageItemDetails, MWI_Toolkit_Calculator.shortageItemDetailsMap);
            rightDiv.appendChild(shortageItemDetails);
            const requiredItemDetails = document.createElement('details');
            requiredItemDetails.style.background = '#0c385a';
            requiredItemDetails.style.borderRadius = '4px';
            requiredItemDetails.style.padding = '2px';
            const requiredSummary = document.createElement('summary');
            requiredSummary.textContent = MWI_Toolkit.getGameLanguage() === 'zh' ? '详情(等效+库存/需求)' : 'Status(Equivalent+Owned/Required)';
            requiredSummary.style.background = '#1770b3';
            requiredSummary.style.borderRadius = '4px';
            requiredSummary.style.fontSize = '14px';
            requiredSummary.style.padding = '2px 6px';
            requiredSummary.style.textAlign = 'left';
            requiredSummary.style.cursor = 'pointer';
            requiredItemDetails.appendChild(requiredSummary);
            MWI_Toolkit_Calculator.createItemDetailsMap(requiredItemDetails, MWI_Toolkit_Calculator.requiredItemDetailsMap);
            rightDiv.appendChild(requiredItemDetails);
            calculatorPanel.appendChild(rightDiv);
            return calculatorPanel;
        }
        // 创建物品分类区域
        static createItemDetailsMap(container, ItemDetailsMap) {
            MWI_Toolkit_Calculator.itemCategoryList.forEach(categoryHrid => {
                const details = document.createElement('details');
                details.style.background = '#2c2e45';
                details.style.borderRadius = '4px';
                details.style.margin = '2px 0px';
                details.open = true;
                const summary = document.createElement('summary');
                summary.textContent = MWI_Toolkit_I18n.getName(categoryHrid, 'itemCategoryNames');
                summary.style.background = '#393a5b';
                summary.style.borderRadius = '4px';
                summary.style.fontSize = '14px';
                summary.style.padding = '2px 6px';
                summary.style.textAlign = 'left';
                summary.style.cursor = 'pointer';
                details.appendChild(summary);
                container.appendChild(details);
                ItemDetailsMap.set(categoryHrid, details);
            });
        }
        // 创建添加物品区域
        static createAddItemSection() {
            const addItemSection = document.createElement('div');
            // 左侧60%:物品搜索区域
            const leftSection = document.createElement('div');
            leftSection.style.display = 'inline-block';
            leftSection.style.verticalAlign = 'top';
            leftSection.style.width = '60%';
            const searchContainer = MWI_Toolkit_Calculator.createItemSearchComponent();
            leftSection.appendChild(searchContainer);
            // 右侧40%:房屋选择区域
            const rightSection = document.createElement('div');
            rightSection.style.display = 'inline-block';
            rightSection.style.verticalAlign = 'top';
            rightSection.style.width = '40%';
            const houseContainer = MWI_Toolkit_Calculator.createHouseRoomSelectionComponent();
            rightSection.appendChild(houseContainer);
            addItemSection.appendChild(leftSection);
            addItemSection.appendChild(rightSection);
            return addItemSection;
        }
        // 创建物品搜索组件
        static createItemSearchComponent() {
            const itemSearchComponent = document.createElement('div');
            itemSearchComponent.style.background = '#2c2e45';
            itemSearchComponent.style.border = 'none';
            itemSearchComponent.style.borderRadius = '4px';
            itemSearchComponent.style.padding = '4px';
            itemSearchComponent.style.margin = '2px';
            itemSearchComponent.style.display = 'flex';
            itemSearchComponent.style.position = 'relative';
            // 物品搜索输入框
            const itemSearchInput = document.createElement('input');
            itemSearchInput.type = 'text';
            itemSearchInput.placeholder = (MWI_Toolkit.getGameLanguage() === 'zh') ? '搜索物品名称...' : 'Search item name...';
            itemSearchInput.style.background = '#dde2f8';
            itemSearchInput.style.color = '#000000';
            itemSearchInput.style.border = 'none';
            itemSearchInput.style.borderRadius = '4px';
            itemSearchInput.style.padding = '4px';
            itemSearchInput.style.margin = '2px';
            itemSearchInput.style.minWidth = '40px';
            itemSearchInput.style.flex = '1';
            // 搜索结果下拉列表
            const searchResults = document.createElement('div');
            searchResults.style.background = '#2c2e45';
            searchResults.style.border = 'none';
            searchResults.style.borderRadius = '4px';
            searchResults.style.padding = '4px';
            searchResults.style.margin = '2px';
            searchResults.style.width = '200px';
            searchResults.style.maxHeight = '335px';
            searchResults.style.overflowY = 'auto';
            searchResults.style.zIndex = '1000';
            searchResults.style.display = 'none';
            searchResults.style.position = 'absolute';
            searchResults.style.left = '4px';
            searchResults.style.top = '32px';
            // 数量输入框
            const countInput = document.createElement('input');
            countInput.type = 'text';
            countInput.value = '1';
            countInput.placeholder = (MWI_Toolkit.getGameLanguage() === 'zh') ? '数量' : 'Count';
            countInput.style.background = '#dde2f8';
            countInput.style.color = '#000000';
            countInput.style.border = 'none';
            countInput.style.borderRadius = '4px';
            countInput.style.padding = '4px';
            countInput.style.margin = '2px';
            countInput.style.width = '60px';
            // 添加按钮
            const addButton = document.createElement('button');
            addButton.textContent = (MWI_Toolkit.getGameLanguage() === 'zh') ? '添加' : 'Add';
            addButton.style.background = '#4CAF50';
            addButton.style.color = '#FFFFFF';
            addButton.style.border = 'none';
            addButton.style.borderRadius = '4px';
            addButton.style.padding = '4px';
            addButton.style.margin = '2px';
            addButton.style.cursor = 'pointer';
            // 清空按钮
            const clearAllButton = document.createElement('button');
            clearAllButton.textContent = (MWI_Toolkit.getGameLanguage() === 'zh') ? '清空' : 'Clear';
            clearAllButton.style.background = '#f44336';
            clearAllButton.style.color = '#FFFFFF';
            clearAllButton.style.border = 'none';
            clearAllButton.style.borderRadius = '4px';
            clearAllButton.style.padding = '4px';
            clearAllButton.style.margin = '2px';
            clearAllButton.style.cursor = 'pointer';
            // 绑定搜索事件
            MWI_Toolkit_Calculator.bindItemSearchComponentEvents(itemSearchInput, countInput, searchResults, addButton, clearAllButton);
            itemSearchComponent.appendChild(itemSearchInput);
            itemSearchComponent.appendChild(countInput);
            itemSearchComponent.appendChild(addButton);
            itemSearchComponent.appendChild(clearAllButton);
            itemSearchComponent.appendChild(searchResults);
            return itemSearchComponent;
        }
        // 绑定搜索相关事件
        static bindItemSearchComponentEvents(itemSearchInput, countInput, searchResults, addButton, clearAllButton) {
            // 输入框获得焦点时全选内容
            itemSearchInput.addEventListener('focus', () => {
                setTimeout(() => {
                    itemSearchInput.select();
                }, 0);
            });
            // 搜索功能
            itemSearchInput.addEventListener('input', () => {
                const searchTerm = itemSearchInput.value.toLowerCase().trim();
                if (searchTerm.length < 2) {
                    searchResults.style.display = 'none';
                    return;
                }
                // 获取并过滤物品
                const itemDetailMap = MWI_Toolkit?.initClientData?.itemDetailMap;
                if (!itemDetailMap)
                    return;
                const filteredItems = Object.keys(itemDetailMap)
                    .filter(itemHrid => {
                    return MWI_Toolkit_I18n.getItemName(itemHrid).toLowerCase().includes(searchTerm);
                })
                    .sort((a, b) => {
                    const sortIndexA = MWI_Toolkit_Utils.getSortIndexByItemHrid(a);
                    const sortIndexB = MWI_Toolkit_Utils.getSortIndexByItemHrid(b);
                    return sortIndexA - sortIndexB;
                });
                if (filteredItems.length === 0) {
                    searchResults.style.display = 'none';
                    return;
                }
                MWI_Toolkit_Calculator.populateSearchResults(searchResults, filteredItems, (itemHrid) => {
                    itemSearchInput.value = MWI_Toolkit_I18n.getItemName(itemHrid);
                    searchResults.style.display = 'none';
                });
                searchResults.style.display = 'block';
            });
            // 键盘操作
            itemSearchInput.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    MWI_Toolkit_Calculator.addItemAndResetItemSearchComponent(itemSearchInput, countInput, searchResults);
                }
                else if (e.key === 'Escape') {
                    searchResults.style.display = 'none';
                }
            });
            // 输入框获得焦点时全选内容
            countInput.addEventListener('focus', () => {
                setTimeout(() => {
                    countInput.select();
                }, 0);
            });
            // 仅允许输入数字
            countInput.addEventListener('input', () => {
                // 只允许负号在首位,其余为数字
                countInput.value = countInput.value.replace(/(?!^)-|[^\d-]/g, '');
            });
            // 键盘操作
            countInput.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    MWI_Toolkit_Calculator.addItemAndResetItemSearchComponent(itemSearchInput, countInput, searchResults);
                }
                else if (e.key === 'Escape') {
                    searchResults.style.display = 'none';
                }
            });
            // 添加按钮事件
            addButton.addEventListener('click', () => {
                MWI_Toolkit_Calculator.addItemAndResetItemSearchComponent(itemSearchInput, countInput, searchResults);
            });
            // 清空按钮事件
            clearAllButton.addEventListener('click', () => {
                if (confirm((MWI_Toolkit.getGameLanguage() === 'zh') ? '确定要清空所有目标物品吗?' : 'Are you sure you want to clear all target items?')) {
                    // 通过事件处理器清空
                    MWI_Toolkit_Calculator.clearAllTargetItems();
                }
            });
            // 点击其他地方隐藏搜索结果
            document.addEventListener('click', () => {
                searchResults.style.display = 'none';
            });
        }
        // 填充搜索结果
        static populateSearchResults(searchResults, filteredItems, onItemSelect) {
            searchResults.innerHTML = '';
            filteredItems.forEach((itemHrid, index) => {
                const resultItem = document.createElement('div');
                resultItem.style.borderBottom = '1px solid #98a7e9';
                resultItem.style.borderRadius = '4px';
                resultItem.style.padding = '4px';
                resultItem.style.alignItems = 'center';
                resultItem.style.display = 'flex';
                resultItem.style.cursor = 'pointer';
                if (index === 0) {
                    resultItem.style.background = '#4a4c6a';
                }
                // 物品图标
                const itemIcon = document.createElement('div');
                const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                svg.setAttribute('width', '16px');
                svg.setAttribute('height', '16px');
                svg.style.display = 'block';
                const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
                use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', MWI_Toolkit_Utils.getIconHrefByItemHrid(itemHrid));
                svg.appendChild(use);
                itemIcon.appendChild(svg);
                // 物品名称
                const itemName = document.createElement('span');
                itemName.textContent = MWI_Toolkit_I18n.getItemName(itemHrid);
                itemName.style.marginLeft = '2px';
                resultItem.appendChild(itemIcon);
                resultItem.appendChild(itemName);
                // 悬停高亮
                resultItem.addEventListener('mouseenter', () => {
                    resultItem.style.background = '#4a4c6a';
                });
                resultItem.addEventListener('mouseleave', () => {
                    resultItem.style.background = 'transparent';
                });
                resultItem.addEventListener('click', () => onItemSelect(itemHrid));
                searchResults.appendChild(resultItem);
            });
        }
        // 添加物品并重置搜索组件(包含itemHrid获取和判空)
        static addItemAndResetItemSearchComponent(itemSearchInput, countInput, searchResults) {
            const InputValue = itemSearchInput.value.trim();
            // 如果InputValue是纯数字,则视为从特定角色加载数据
            if (/^\d+$/.test(InputValue)) {
                const characterID = parseInt(InputValue, 10);
                MWI_Toolkit_Calculator.loadTargetItems(characterID);
                return;
            }
            const itemHrid = MWI_Toolkit_I18n.getItemHridByName(InputValue);
            if (!itemHrid)
                return;
            const count = parseInt(countInput.value, 10) || 1;
            MWI_Toolkit_Calculator.updateTargetItem(itemHrid, count);
            itemSearchInput.value = '';
            countInput.value = '1';
            searchResults.style.display = 'none';
        }
        // 创建房屋选择区域
        static createHouseRoomSelectionComponent() {
            const HouseRoomSelectionComponent = document.createElement('div');
            HouseRoomSelectionComponent.style.background = '#2c2e45';
            HouseRoomSelectionComponent.style.border = 'none';
            HouseRoomSelectionComponent.style.borderRadius = '4px';
            HouseRoomSelectionComponent.style.padding = '4px';
            HouseRoomSelectionComponent.style.margin = '2px';
            HouseRoomSelectionComponent.style.display = 'flex';
            // 下拉菜单
            const dropdown = MWI_Toolkit_Calculator.createHouseRoomTypeDropdown();
            // 等级输入框
            const levelInput = document.createElement('input');
            levelInput.type = 'number';
            levelInput.min = '1';
            levelInput.max = '8';
            levelInput.step = '1';
            levelInput.value = '1';
            levelInput.placeholder = (MWI_Toolkit.getGameLanguage() === 'zh') ? '等级' : 'Level';
            levelInput.style.background = '#dde2f8';
            levelInput.style.color = '#000000';
            levelInput.style.border = 'none';
            levelInput.style.borderRadius = '4px';
            levelInput.style.padding = '4px';
            levelInput.style.margin = '2px';
            levelInput.style.width = '35px';
            // 添加按钮
            const addListButton = document.createElement('button');
            addListButton.textContent = (MWI_Toolkit.getGameLanguage() === 'zh') ? '添加' : 'Add';
            addListButton.style.background = '#4CAF50';
            addListButton.style.color = '#FFFFFF';
            addListButton.style.border = 'none';
            addListButton.style.borderRadius = '4px';
            addListButton.style.padding = '4px';
            addListButton.style.margin = '2px';
            addListButton.style.width = '35px';
            addListButton.style.cursor = 'pointer';
            // 绑定事件
            MWI_Toolkit_Calculator.bindHouseRoomSelectionComponentEvents(dropdown, levelInput, addListButton);
            HouseRoomSelectionComponent.appendChild(dropdown);
            HouseRoomSelectionComponent.appendChild(levelInput);
            HouseRoomSelectionComponent.appendChild(addListButton);
            return HouseRoomSelectionComponent;
        }
        // 创建房屋类型下拉菜单
        static createHouseRoomTypeDropdown() {
            // 创建容器
            const dropdown = document.createElement('div');
            dropdown.style.display = 'flex';
            dropdown.style.minWidth = '20px';
            dropdown.style.flex = '1';
            dropdown.style.position = 'relative';
            // 选中项显示区
            const selected = document.createElement('div');
            selected.style.background = '#393a5b';
            selected.style.color = '#000000';
            selected.style.border = 'none';
            selected.style.borderRadius = '4px';
            selected.style.paddingLeft = '4px';
            selected.style.margin = '2px';
            selected.style.minWidth = '40px';
            selected.style.flex = '1';
            selected.style.cursor = 'pointer';
            selected.style.display = 'flex';
            selected.style.alignItems = 'center';
            // 下拉菜单列表
            const list = document.createElement('div');
            list.style.background = '#2c2e45';
            list.style.border = 'none';
            list.style.borderRadius = '4px';
            list.style.padding = '4px';
            list.style.margin = '2px';
            list.style.width = '150px';
            list.style.maxHeight = '335px';
            list.style.overflowY = 'auto';
            list.style.zIndex = '1000';
            list.style.display = 'none';
            list.style.position = 'absolute';
            list.style.left = '0px';
            list.style.top = '32px';
            const HouseRoomTypeOptions = MWI_Toolkit_Calculator.createHouseRoomTypeOptions(selected, dropdown);
            HouseRoomTypeOptions.forEach(optionItem => { list.appendChild(optionItem); });
            HouseRoomTypeOptions[0] && HouseRoomTypeOptions[0].click(); // 默认选中第一个
            dropdown.appendChild(selected);
            dropdown.appendChild(list);
            // 点击展开/收起
            selected.addEventListener('click', (e) => {
                e.stopPropagation();
                list.style.display = list.style.display === 'block' ? 'none' : 'block';
            });
            // 点击外部关闭
            document.addEventListener('click', () => {
                list.style.display = 'none';
            });
            return dropdown;
        }
        // 创建房屋类型选项
        static createHouseRoomTypeOptions(selected, dropdown) {
            const houseRoomDetailMap = MWI_Toolkit.initClientData?.houseRoomDetailMap;
            if (!houseRoomDetailMap) {
                return [];
            }
            return Object.values(houseRoomDetailMap)
                .sort((a, b) => (a.sortIndex ?? 9999) - (b.sortIndex ?? 9999))
                .map(houseRoomDetail => {
                const optionItem = document.createElement('div');
                optionItem.style.borderBottom = '1px solid #98a7e9';
                optionItem.style.borderRadius = '4px';
                optionItem.style.padding = '4px';
                optionItem.style.alignItems = 'center';
                optionItem.style.display = 'flex';
                optionItem.style.cursor = 'pointer';
                // 房屋房间图标
                const houseRoomIcon = document.createElement('div');
                const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                svg.setAttribute('width', '16px');
                svg.setAttribute('height', '16px');
                svg.style.display = 'block';
                const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
                use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', MWI_Toolkit_Utils.getIconHrefBySkillHrid(houseRoomDetail.skillHrid));
                svg.appendChild(use);
                houseRoomIcon.appendChild(svg);
                // 房屋房间名称
                const houseRoomName = document.createElement('span');
                houseRoomName.textContent = MWI_Toolkit_I18n?.getName(houseRoomDetail.hrid, "houseRoomNames") || houseRoomDetail.hrid;
                houseRoomName.style.marginLeft = '2px';
                houseRoomName.style.whiteSpace = 'nowrap';
                houseRoomName.style.overflow = 'hidden';
                optionItem.appendChild(houseRoomIcon);
                optionItem.appendChild(houseRoomName);
                optionItem.addEventListener('click', () => {
                    selected.innerHTML = '';
                    const selectedIcon = houseRoomIcon.cloneNode(true);
                    selected.appendChild(selectedIcon);
                    const selectedName = houseRoomName.cloneNode(true);
                    selectedName.style.color = '#FFFFFF';
                    selected.appendChild(selectedName);
                    dropdown.dataset.houseRoomHrid = houseRoomDetail.hrid;
                    optionItem.parentElement.style.display = 'none';
                });
                // 悬停高亮
                optionItem.addEventListener('mouseenter', () => {
                    optionItem.style.background = '#4a4c6a';
                });
                optionItem.addEventListener('mouseleave', () => {
                    optionItem.style.background = 'transparent';
                });
                optionItem.dataset.houseRoomHrid = houseRoomDetail.hrid;
                return optionItem;
            });
        }
        // 绑定房屋选择相关事件
        static bindHouseRoomSelectionComponentEvents(dropdown, levelInput, addListButton) {
            // 输入框获得焦点时全选内容
            levelInput.addEventListener('focus', function () {
                setTimeout(() => {
                    levelInput.select();
                }, 0);
            });
            // 添加按钮事件
            addListButton.addEventListener('click', () => {
                const houseRoomHrid = dropdown.dataset.houseRoomHrid;
                const level = parseInt(levelInput.value) || 1;
                MWI_Toolkit_Calculator.updateTargetItem(houseRoomHrid, level);
            });
        }
        // 渲染物品列表
        static renderItemsDisplay() {
            MWI_Toolkit_Calculator.targetItemCategoryMap.forEach((category) => {
                category.updateDisplayElement();
            });
            // 这里只需要新增或更新,删除在targetItems变动时进行处理
            MWI_Toolkit_Calculator.itemCategoryList.forEach(categoryHrid => {
                const details = MWI_Toolkit_Calculator.targetItemDetailsMap.get(categoryHrid);
                let lastElement = details.querySelector('summary');
                let itemCount = 0;
                [...MWI_Toolkit_Calculator.targetItemsMap.values()]
                    .sort((a, b) => a.sortIndex - b.sortIndex)
                    .forEach(targetItem => {
                    if (targetItem.categoryHrid !== categoryHrid) {
                        return;
                    }
                    if (!targetItem.displayElement) {
                        MWI_Toolkit_Calculator.createTargetItemDisplayElement(targetItem);
                        lastElement.insertAdjacentElement('afterend', targetItem.displayElement);
                    }
                    targetItem.updateDisplayElement();
                    lastElement = targetItem.displayElement;
                    itemCount++;
                });
                details.hidden = itemCount === 0;
            });
            const targetItemsToCalc = [...MWI_Toolkit_Calculator.targetItemsMap.values()]
                .sort((a, b) => a.sortIndex - b.sortIndex)
                .filter(item => item.needCalc && item.count > 0 && (MWI_Toolkit_Calculator.targetItemCategoryMap.get(item.categoryHrid)?.needCalc ?? true))
                .map(item => ({ itemHrid: item.itemHrid, count: item.count }));
            // 计算需求物品显示数据
            // batchCalculateRequiredItems返回的requiredItems已经是有序的
            const requiredItems = MWI_Toolkit_Calculator.batchCalculateRequiredItems(targetItemsToCalc);
            const equivalentItems = MWI_Toolkit_Calculator.calculateEquivalentItems(requiredItems);
            // 移除不存在的物品
            [...MWI_Toolkit_Calculator.requiredItemsMap.keys()].forEach(itemHrid => {
                if (!requiredItems.find(ri => ri.itemHrid === itemHrid)) {
                    MWI_Toolkit_Calculator.requiredItemsMap.get(itemHrid)?.removeDisplayElement();
                    MWI_Toolkit_Calculator.requiredItemsMap.delete(itemHrid);
                }
            });
            requiredItems.forEach(requiredItem => {
                const equivalentCount = equivalentItems.find(ei => ei.itemHrid === requiredItem.itemHrid)?.count || 0;
                const item = MWI_Toolkit_Calculator.requiredItemsMap.get(requiredItem.itemHrid);
                if (item) {
                    item.count = requiredItem.count;
                    item.equivalentCount = equivalentCount;
                }
                else {
                    MWI_Toolkit_Calculator.requiredItemsMap.set(requiredItem.itemHrid, new RequiredItem(requiredItem.itemHrid, requiredItem.count, equivalentCount));
                }
            });
            MWI_Toolkit_Calculator.itemCategoryList.forEach(categoryHrid => {
                const shortageDetails = MWI_Toolkit_Calculator.shortageItemDetailsMap.get(categoryHrid);
                const requiredDetails = MWI_Toolkit_Calculator.requiredItemDetailsMap.get(categoryHrid);
                let lastShortageElement = shortageDetails.querySelector('summary');
                let lastRequiredElement = requiredDetails.querySelector('summary');
                let shortageItemCount = 0;
                let requiredItemCount = 0;
                [...MWI_Toolkit_Calculator.requiredItemsMap.values()]
                    .sort((a, b) => a.sortIndex - b.sortIndex)
                    .forEach(requiredItem => {
                    if (requiredItem.categoryHrid !== categoryHrid) {
                        return;
                    }
                    if (!requiredItem.shortageDisplayElement) {
                        MWI_Toolkit_Calculator.createShortageItemDisplayElement(requiredItem);
                        lastShortageElement.insertAdjacentElement('afterend', requiredItem.shortageDisplayElement);
                    }
                    if (!requiredItem.requiredDisplayElement) {
                        MWI_Toolkit_Calculator.createRequiredItemDisplayElement(requiredItem);
                        lastRequiredElement.insertAdjacentElement('afterend', requiredItem.requiredDisplayElement);
                    }
                    requiredItem.updateDisplayElement();
                    lastShortageElement = requiredItem.shortageDisplayElement;
                    lastRequiredElement = requiredItem.requiredDisplayElement;
                    shortageItemCount += requiredItem.getShortageCount() > 0 ? 1 : 0;
                    requiredItemCount++;
                });
                shortageDetails.hidden = shortageItemCount === 0;
                requiredDetails.hidden = requiredItemCount === 0;
            });
        }
        // 创建物品容器(图标+名称)
        static createItemContainer(displayItem) {
            const container = document.createElement('div');
            // container.style.background = '#393a5b';
            // container.style.border = '1px solid';
            // container.style.borderRadius = '4px';
            // container.style.height = '21px';
            container.style.minWidth = '40px';
            container.style.alignItems = 'center';
            container.style.display = 'flex';
            // 物品图标
            const iconContainer = document.createElement('div');
            iconContainer.style.marginLeft = '2px';
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('width', '18px');
            svg.setAttribute('height', '18px');
            svg.style.display = 'block';
            const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
            use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', displayItem.iconHref);
            svg.appendChild(use);
            iconContainer.appendChild(svg);
            // 物品名称
            const displayNameDiv = document.createElement('div');
            displayNameDiv.textContent = displayItem.displayName;
            displayNameDiv.style.padding = "4px 1px";
            displayNameDiv.style.marginLeft = '2px';
            displayNameDiv.style.whiteSpace = 'nowrap';
            displayNameDiv.style.overflow = 'hidden';
            container.appendChild(iconContainer);
            container.appendChild(displayNameDiv);
            return container;
        }
        // 创建目标物品元素
        static createTargetItemDisplayElement(targetItem) {
            const { container, itemContainer, rightDiv } = MWI_Toolkit_Calculator.createBaseItemDisplayItem(targetItem);
            const needCalcCheckbox = document.createElement('input');
            needCalcCheckbox.type = 'checkbox';
            container.prepend(needCalcCheckbox);
            needCalcCheckbox.addEventListener('change', () => {
                targetItem.needCalc = needCalcCheckbox.checked;
                MWI_Toolkit_Calculator.saveAndScheduleRender();
            });
            // 拥有数量
            const ownedSpan = document.createElement('span');
            ownedSpan.style.padding = '4px 1px';
            ownedSpan.style.marginLeft = '4px';
            // 斜杠分隔符
            const slash = document.createElement('span');
            slash.textContent = "/";
            slash.style.padding = '4px 1px';
            // 可编辑的需求数量输入框
            const targetInput = document.createElement('input');
            targetInput.type = 'text';
            targetInput.placeholder = '需求';
            targetInput.style.background = '#dde2f8';
            targetInput.style.color = '#000000';
            targetInput.style.border = 'none';
            targetInput.style.borderRadius = '4px';
            targetInput.style.padding = '4px';
            targetInput.style.margin = '2px';
            targetInput.style.width = '60px';
            // 绑定输入事件
            targetInput.addEventListener('input', function () {
                // 清理非数字字符
                this.value = this.value.replace(/(?!^)-|[^\d-]/g, '');
                const newCount = parseInt(this.value) || 0;
                MWI_Toolkit_Calculator.updateTargetItem(targetItem.itemHrid, newCount);
            });
            // 输入框获得焦点时全选内容
            targetInput.addEventListener('focus', function () {
                setTimeout(() => {
                    targetInput.select();
                }, 0);
            });
            // 删除按钮
            const removeButton = document.createElement('button');
            removeButton.style.background = '#f44336';
            removeButton.style.border = 'none';
            removeButton.style.borderRadius = '4px';
            removeButton.style.padding = '4px';
            removeButton.style.margin = '2px';
            removeButton.style.cursor = 'pointer';
            const removeSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            removeSvg.setAttribute('width', '18px');
            removeSvg.setAttribute('height', '18px');
            removeSvg.style.display = 'block';
            const removeUse = document.createElementNS('http://www.w3.org/2000/svg', 'use');
            removeUse.setAttributeNS('http://www.w3.org/1999/xlink', 'href', MWI_Toolkit_Utils.getIconHrefByMiscHrid('remove'));
            removeSvg.appendChild(removeUse);
            removeButton.appendChild(removeSvg);
            removeButton.addEventListener('click', () => {
                MWI_Toolkit_Calculator.removeTargetItem(targetItem.itemHrid);
            });
            rightDiv.appendChild(ownedSpan);
            rightDiv.appendChild(slash);
            rightDiv.appendChild(targetInput);
            rightDiv.appendChild(removeButton);
            targetItem.displayElement = container;
            targetItem.needCalcCheckbox = needCalcCheckbox;
            targetItem.ownedSpan = ownedSpan;
            targetItem.targetInput = targetInput;
        }
        // 创建缺口物品元素
        static createShortageItemDisplayElement(requiredItem) {
            const { container, itemContainer, rightDiv } = MWI_Toolkit_Calculator.createBaseItemDisplayItem(requiredItem);
            const shortageSpan = document.createElement('span');
            shortageSpan.style.background = '#393a5b';
            shortageSpan.style.borderRadius = '4px';
            shortageSpan.style.padding = '2px 6px';
            shortageSpan.style.marginLeft = '4px';
            shortageSpan.style.cursor = 'pointer';
            shortageSpan.addEventListener('click', (e) => {
                if (e.ctrlKey) {
                    MWI_Toolkit_Calculator.TryGotoActionDetailByRequiredItem(requiredItem);
                }
            });
            rightDiv.appendChild(shortageSpan);
            requiredItem.shortageDisplayElement = container;
            requiredItem.shortageSpan = shortageSpan;
        }
        // 创建需求物品元素
        static createRequiredItemDisplayElement(requiredItem) {
            const { container, itemContainer, rightDiv } = MWI_Toolkit_Calculator.createBaseItemDisplayItem(requiredItem);
            const RequiredCountDiv = document.createElement('div');
            RequiredCountDiv.style.padding = '4px 1px';
            RequiredCountDiv.style.marginLeft = '4px';
            const ownedSpan = document.createElement('span');
            const equivalentSpan = document.createElement('span');
            const requiredSpan = document.createElement('span');
            RequiredCountDiv.appendChild(equivalentSpan);
            RequiredCountDiv.appendChild(ownedSpan);
            RequiredCountDiv.appendChild(requiredSpan);
            rightDiv.appendChild(RequiredCountDiv);
            requiredItem.requiredDisplayElement = container;
            requiredItem.equivalentSpan = equivalentSpan;
            requiredItem.ownedSpan = ownedSpan;
            requiredItem.requiredSpan = requiredSpan;
            requiredItem.requiredDiv = RequiredCountDiv;
        }
        static createBaseItemDisplayItem(displayItem) {
            const container = document.createElement('div');
            container.className = 'Toolkit_Calculator_Container';
            container.style.border = 'none';
            container.style.borderRadius = '4px';
            container.style.padding = '1px 4px';
            container.style.margin = '2px';
            container.style.display = 'flex';
            container.style.alignItems = 'center';
            const itemContainer = MWI_Toolkit_Calculator.createItemContainer(displayItem);
            container.appendChild(itemContainer);
            const leftDiv = document.createElement('div');
            leftDiv.style.flex = '1';
            container.appendChild(leftDiv);
            // 右侧内容
            const rightDiv = document.createElement('div');
            rightDiv.style.display = 'flex';
            container.appendChild(rightDiv);
            return { container, itemContainer, rightDiv };
        }
        // 尝试打开动作面板
        static TryGotoActionDetailByRequiredItem(requiredItem) {
            const actionHrid = MWI_Toolkit_ActionDetailPlus.getActionHrid(requiredItem.displayName)
                ?? MWI_Toolkit_ActionDetailPlus.processableActionList[requiredItem.itemHrid]
                ?? null;
            if (!actionHrid) {
                return;
            }
            const { upgradeItemHrid, inputItems, outputItems } = MWI_Toolkit_ActionDetailPlus.calculateActionDetail(actionHrid, true);
            const outputCount = outputItems.find(oi => oi.itemHrid === requiredItem.itemHrid)?.count || 1;
            if (outputCount === 1 || outputCount === 15) {
                const actionCount = Math.ceil(requiredItem.getShortageCount() / outputCount);
                MWI_Toolkit.gameObject.handleGoToAction(actionHrid, actionCount);
            }
            else {
                const actionCount = MWI_Toolkit_Calculator.getRequiredTrials99(outputCount, requiredItem.getShortageCount());
                MWI_Toolkit.gameObject.handleGoToAction(actionHrid, actionCount);
            }
        }
        static getRequiredTrials99(mu, target) {
            // 用拟合公式简化标准差
            // sigma ≈ 0.2912 * mu^1.032
            const sigma = 0.2912 * Math.pow(mu, 1.032);
            const z = 2.326; // 99%置信度
            // 解一元二次方程 n*mu - z*sigma*sqrt(n) - target = 0
            // x = sqrt(n) = (z*sigma + sqrt(z^2*sigma^2 + 4*mu*target)) / (2*mu)
            const x = (z * sigma + Math.sqrt(z * z * sigma * sigma + 4 * mu * target)) / (2 * mu);
            return Math.ceil(x * x);
        }
    }
    MWI_Toolkit_Calculator.targetItemCategoryMap = new Map();
    MWI_Toolkit_Calculator.targetItemsMap = new Map();
    MWI_Toolkit_Calculator.requiredItemsMap = new Map();
    MWI_Toolkit_Calculator.tabButton = null;
    MWI_Toolkit_Calculator.tabPanel = null;
    MWI_Toolkit_Calculator.targetItemDetailsMap = new Map();
    MWI_Toolkit_Calculator.shortageItemDetailsMap = new Map();
    MWI_Toolkit_Calculator.requiredItemDetailsMap = new Map();
    MWI_Toolkit_Calculator.itemCategoryList = [
        '/item_categories/house_rooms',
        '/item_categories/currency',
        '/item_categories/loot',
        '/item_categories/key',
        '/item_categories/food',
        '/item_categories/drink',
        '/item_categories/ability_book',
        '/item_categories/equipment',
        '/item_categories/materials',
        '/item_categories/resource',
    ];
    MWI_Toolkit_Calculator.renderTimeout = null;
    //#endregion
    //#region ActionDetailPlus
    class ItemCountComponent {
    }
    class MWI_Toolkit_ActionDetailPlus {
        /**
         * 监听页面变化
         */
        static initialize() {
            let lastPanel = null;
            const observer = new MutationObserver(() => {
                const panel = document.querySelector('[class^="SkillActionDetail_regularComponent"]');
                if (panel && panel !== lastPanel) {
                    lastPanel = panel;
                    setTimeout(() => {
                        MWI_Toolkit_ActionDetailPlus.enhanceSkillActionDetail();
                    }, 50);
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
        }
        /**
         * 增强技能行动详情面板
         */
        static enhanceSkillActionDetail() {
            const actionName = MWI_Toolkit_ActionDetailPlus.getActionName();
            const actionHrid = MWI_Toolkit_ActionDetailPlus.getActionHrid(actionName);
            const { upgradeItemHrid, inputItems, outputItems } = MWI_Toolkit_ActionDetailPlus.calculateActionDetail(actionHrid);
            const upgradeItemComponent = { itemHrid: '', count: 0 };
            if (upgradeItemHrid) {
                const shortageCountContainer = document.querySelector('[class^="SkillActionDetail_upgradeItemSelectorInput"]')?.parentElement?.previousElementSibling;
                if (shortageCountContainer) {
                    const newTextSpan = document.createElement('span');
                    newTextSpan.textContent = shortageCountContainer.textContent;
                    newTextSpan.style.height = window.getComputedStyle(document.querySelector('[class*="SkillActionDetail_levelRequirement"]')).height;
                    shortageCountContainer.innerHTML = '';
                    shortageCountContainer.appendChild(newTextSpan);
                    const shortageCountComponent = document.createElement('div');
                    shortageCountComponent.style.display = 'flex';
                    shortageCountComponent.style.alignItems = 'flex-end';
                    shortageCountComponent.style.flexDirection = 'column';
                    const shortageCountSpan = document.createElement('span');
                    shortageCountSpan.style.display = 'flex';
                    shortageCountSpan.style.alignItems = 'center';
                    shortageCountSpan.style.color = '#faa21e';
                    shortageCountComponent.appendChild(shortageCountSpan);
                    upgradeItemComponent.itemHrid = upgradeItemHrid;
                    upgradeItemComponent.shortageCountSpan = shortageCountSpan;
                    upgradeItemComponent.count = 1; // 升级物品固定需求1个
                    shortageCountContainer.appendChild(shortageCountComponent);
                }
            }
            // [{itemHrid, shortageCountSpan, inventoryCountSpan, inputCountSpan, count}]
            const inputItemComponents = Array();
            if (inputItems) {
                const inputItemComponentContainer = document.querySelector('[class^="SkillActionDetail_itemRequirements"]');
                const shortageCountContainer = inputItemComponentContainer?.parentElement?.previousElementSibling;
                if (shortageCountContainer) {
                    const newTextSpan = document.createElement('span');
                    newTextSpan.textContent = shortageCountContainer.textContent;
                    newTextSpan.style.height = window.getComputedStyle(document.querySelector('[class*="SkillActionDetail_levelRequirement"]')).height;
                    shortageCountContainer.innerHTML = '';
                    shortageCountContainer.appendChild(newTextSpan);
                    const shortageCountComponent = document.createElement('div');
                    shortageCountComponent.style.display = 'flex';
                    shortageCountComponent.style.alignItems = 'flex-end';
                    shortageCountComponent.style.flexDirection = 'column';
                    const inventoryCountSpans = inputItemComponentContainer?.querySelectorAll('[class*="SkillActionDetail_inventoryCount"]');
                    const inputCountSpans = inputItemComponentContainer?.querySelectorAll('[class*="SkillActionDetail_inputCount"]');
                    const itemContainers = inputItemComponentContainer?.querySelectorAll('[class*="Item_itemContainer"]');
                    for (let i = 0; i < itemContainers.length; i++) {
                        inputCountSpans[i].style.color = '#E7E7E7';
                        const inputItemHrid = '/items/' + itemContainers[i].querySelector('svg use').getAttribute('href').split('#').pop();
                        const inputItemCount = inputItems.find(item => item.itemHrid === inputItemHrid)?.count || 0;
                        const shortageCountSpan = document.createElement('span');
                        shortageCountSpan.style.height = window.getComputedStyle(itemContainers[i]).height;
                        shortageCountSpan.style.display = 'flex';
                        shortageCountSpan.style.alignItems = 'center';
                        shortageCountSpan.style.color = '#faa21e';
                        shortageCountComponent.appendChild(shortageCountSpan);
                        inputItemComponents.push({ itemHrid: inputItemHrid, shortageCountSpan: shortageCountSpan, inventoryCountSpan: inventoryCountSpans[i], inputCountSpan: inputCountSpans[i], count: inputItemCount });
                    }
                    shortageCountContainer.appendChild(shortageCountComponent);
                }
            }
            // [{itemHrid, input, count}]
            const outputItemComponents = Array();
            let lastOutputItemComponent = document.querySelector('[class^="SkillActionDetail_maxActionCountInput"]');
            const outputItemComponentContainer = lastOutputItemComponent.parentElement;
            const skillActionTimeInput = lastOutputItemComponent.querySelector('input');
            const skillActionTimeButtons = lastOutputItemComponent.querySelectorAll('button');
            for (const outputItem of outputItems) {
                if (outputItem.count === 1 && outputItems.length === 1)
                    break; // 仅有一个产出且数量为1时不创建额外输入框
                const { component, input } = MWI_Toolkit_ActionDetailPlus.createOutputItemComponent(outputItem.itemHrid);
                if (component && input) {
                    outputItemComponentContainer.insertBefore(component, lastOutputItemComponent.nextSibling);
                    outputItemComponents.push({ itemHrid: outputItem.itemHrid, outputItemInput: input, count: outputItem.count });
                    lastOutputItemComponent = component;
                }
            }
            // 联动
            let linking = false;
            function updateSkillActionDetail(e) {
                if (linking)
                    return;
                linking = true;
                const target = e.target;
                const index = outputItemComponents.findIndex(component => component.outputItemInput === target);
                const targetValue = parseInt(target.value, 10);
                if (index !== -1) {
                    skillActionTimeInput.value = (isNaN(targetValue)) ? '∞' : Math.ceil(targetValue / outputItemComponents[index].count).toString();
                    MWI_Toolkit_Utils.reactInputTriggerHack(skillActionTimeInput);
                }
                const skillActionTimes = parseInt(skillActionTimeInput.value, 10);
                outputItemComponents.forEach(component => {
                    if (component.outputItemInput !== target) {
                        component.outputItemInput.value = (isNaN(skillActionTimes)) ? '∞' : Math.ceil(skillActionTimes * component.count).toString();
                    }
                });
                inputItemComponents.forEach(component => {
                    const inventoryCount = MWI_Toolkit_ItemsMap.getCount(component.itemHrid);
                    const requiredCount = component.count * skillActionTimes;
                    if (isNaN(skillActionTimes)) {
                        component.shortageCountSpan.textContent = '';
                        component.inventoryCountSpan.style.color = '';
                    }
                    else {
                        if (requiredCount > inventoryCount) {
                            component.shortageCountSpan.textContent = MWI_Toolkit_Utils.formatNumber(requiredCount - inventoryCount);
                            component.inventoryCountSpan.style.color = '#f44336';
                        }
                        else {
                            component.shortageCountSpan.textContent = ' ';
                            component.inventoryCountSpan.style.color = '#E7E7E7';
                        }
                    }
                    component.inputCountSpan.textContent = '\u00A0/ ' + MWI_Toolkit_Utils.formatNumber(component.count * ((isNaN(skillActionTimes) ? 1 : skillActionTimes))) + '\u00A0';
                });
                if (upgradeItemComponent.shortageCountSpan) {
                    if (isNaN(skillActionTimes)) {
                        upgradeItemComponent.shortageCountSpan.textContent = '';
                    }
                    else {
                        const requiredCount = upgradeItemComponent.count * skillActionTimes;
                        const inventoryCount = MWI_Toolkit_ItemsMap.getCount(upgradeItemComponent.itemHrid);
                        if (requiredCount > inventoryCount) {
                            upgradeItemComponent.shortageCountSpan.textContent = MWI_Toolkit_Utils.formatNumber(requiredCount - inventoryCount);
                        }
                        else {
                            upgradeItemComponent.shortageCountSpan.textContent = ' ';
                        }
                    }
                }
                linking = false;
            }
            skillActionTimeInput.addEventListener('input', updateSkillActionDetail);
            outputItemComponents.forEach(component => {
                component.outputItemInput.addEventListener('input', updateSkillActionDetail);
            });
            skillActionTimeButtons.forEach(btn => {
                btn.addEventListener('click', () => {
                    setTimeout(() => {
                        skillActionTimeInput.dispatchEvent(new Event('input', { bubbles: false }));
                    }, 20);
                });
            });
            // 初次填充
            setTimeout(() => {
                skillActionTimeInput.dispatchEvent(new Event('input', { bubbles: false }));
            }, 20);
        }
        static calculateActionDetail(actionHrid, ignoreProcessingTea = false) {
            const actionDetail = MWI_Toolkit_ActionDetailPlus.getActionDetail(actionHrid);
            const actionType = actionDetail?.type?.split('/').pop() || '';
            // 仅支持八种常规类型
            if (!actionDetail || !actionType || !['milking', 'foraging', 'woodcutting', 'cheesesmithing', 'crafting', 'tailoring', 'cooking', 'brewing'].includes(actionType)) {
                console.warn('[MWI_Toolkit] 无法获取动作详情' + MWI_Toolkit_ActionDetailPlus.getActionName());
                return { upgradeItemHrid: null, inputItems: null, outputItems: null };
            }
            // console.log('MWI_Toolkit_ActionDetailPlus: 获取到动作详情', actionDetail);
            const upgradeItemHrid = actionDetail.upgradeItemHrid;
            const inputItems = actionDetail.inputItems ? JSON.parse(JSON.stringify(actionDetail.inputItems)) : null;
            const outputItems = actionDetail.outputItems ? JSON.parse(JSON.stringify(actionDetail.outputItems)) : Array();
            const drinkSlots = MWI_Toolkit_ActionDetailPlus.getActionTypeDrinkSlots(actionType);
            const drinkConcentration = MWI_Toolkit_ActionDetailPlus.getDrinkConcentration();
            // console.log('MWI_Toolkit_ActionDetailPlus: 获取到茶列表', drinkSlots, drinkConcentration);
            // 检查采集数量加成
            const gatheringBuff = (drinkSlots?.some(itemHrid => itemHrid === '/items/gathering_tea') ? 0.15 * drinkConcentration : 0)
                + MWI_Toolkit_ActionDetailPlus.getEquipmentGatheringBuff() + MWI_Toolkit_ActionDetailPlus.getCommunityGatheringBuff();
            // 检查加工茶加成
            const processingBuff = (drinkSlots?.some(itemHrid => itemHrid === '/items/processing_tea') ? 0.15 * drinkConcentration : 0);
            // 检查美食茶加成
            const gourmetBuff = (drinkSlots?.some(itemHrid => itemHrid === '/items/gourmet_tea') ? 0.12 * drinkConcentration : 0);
            // 检查工匠茶加成
            const artisanBuff = (drinkSlots?.some(itemHrid => itemHrid === '/items/artisan_tea') ? 0.1 * drinkConcentration : 0);
            if (['milking', 'foraging', 'woodcutting', /*'cheesesmithing', 'crafting', 'tailoring', 'cooking', 'brewing'*/].includes(actionType)) {
                const dropTable = actionDetail.dropTable;
                for (const dropItem of dropTable) {
                    const averageCount = dropItem.dropRate * (dropItem.minCount + dropItem.maxCount) / 2 * (1 + gatheringBuff);
                    const processedItemHrid = MWI_Toolkit_ActionDetailPlus.processableItemList[dropItem.itemHrid];
                    if (processedItemHrid && !ignoreProcessingTea) {
                        outputItems.push({ itemHrid: dropItem.itemHrid, count: averageCount * (1 - processingBuff), });
                        outputItems.push({ itemHrid: processedItemHrid, count: averageCount * (1 - processingBuff) / 2 / (1 - artisanBuff) + averageCount * processingBuff / 2, });
                    }
                    else {
                        outputItems.push({ itemHrid: dropItem.itemHrid, count: averageCount, });
                    }
                }
            }
            if ([/*'milking', 'foraging', 'woodcutting', 'cheesesmithing', 'crafting', 'tailoring',*/ 'cooking', 'brewing'].includes(actionType)) {
                for (const outputItem of outputItems) {
                    outputItem.count = outputItem.count * (1 + gourmetBuff);
                }
            }
            if ([/*'milking', 'foraging', 'woodcutting',*/ 'cheesesmithing', 'crafting', 'tailoring', 'cooking', 'brewing'].includes(actionType)) {
                for (const inputItem of inputItems) {
                    inputItem.count = inputItem.count * (1 - artisanBuff);
                }
            }
            return { upgradeItemHrid, inputItems, outputItems };
        }
        /**
         * 创建output数量栏,返回 [{component, input}]
         * @param itemHrid 物品的唯一标识符
         * @returns { component: HTMLDivElement; input: HTMLInputElement } | null
         */
        static createOutputItemComponent(itemHrid) {
            const origComponent = document.querySelector('[class^="SkillActionDetail_maxActionCountInput"]');
            if (!origComponent)
                return null;
            // 克隆外层div(不带子内容)
            const component = origComponent.cloneNode(false);
            const originalActionLabel = document.querySelector('[class^="SkillActionDetail_actionContainer"] [class^="SkillActionDetail_label"]');
            if (Object.values(MWI_Toolkit_ActionDetailPlus.processableItemList).includes(itemHrid)) {
                const tab = originalActionLabel.cloneNode(false);
                tab.style.width = window.getComputedStyle(originalActionLabel).width;
                tab.className = 'SkillActionDetail_tab';
                tab.textContent = '┗';
                component.appendChild(tab);
            }
            // 物品图标
            const itemIcon = document.createElement('div');
            itemIcon.style.width = window.getComputedStyle(originalActionLabel).width;
            itemIcon.style.height = window.getComputedStyle(originalActionLabel).height;
            itemIcon.style.marginRight = '2px';
            itemIcon.style.display = 'flex';
            itemIcon.style.alignItems = 'center';
            itemIcon.style.justifyContent = 'center';
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('width', '20px');
            svg.setAttribute('height', '20px');
            svg.style.display = 'block';
            const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
            use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', MWI_Toolkit_Utils.getIconHrefByItemHrid(itemHrid));
            svg.appendChild(use);
            itemIcon.appendChild(svg);
            component.appendChild(itemIcon);
            // 输入框
            const origInputWrap = origComponent.querySelector('[class^="SkillActionDetail_input"]');
            const inputWrap = origInputWrap.cloneNode(true);
            const origInput = origInputWrap.querySelector('input');
            const input = inputWrap.querySelector('input');
            input.addEventListener('focus', () => {
                setTimeout(() => {
                    input.select();
                }, 0);
            });
            input.addEventListener('keydown', (event) => {
                if (event.key === 'Enter') {
                    if (origInput) {
                        origInput.dispatchEvent(event);
                    }
                }
            });
            component.appendChild(inputWrap);
            if (!Object.values(MWI_Toolkit_ActionDetailPlus.processableItemList).includes(itemHrid)) {
                // 快捷填充按钮
                const btns = [
                    { val: 1000, txt: '1k' },
                    { val: 2000, txt: '2k' },
                    { val: 5000, txt: '5k' }
                ];
                const origButtons = origComponent.querySelectorAll('button');
                const buttonClass = origButtons.length > 0 ? origButtons[0].className : '';
                btns.forEach(({ val, txt }) => {
                    const btn = document.createElement('button');
                    btn.className = buttonClass;
                    btn.textContent = txt;
                    btn.addEventListener('click', () => {
                        input.value = val.toString();
                        input.dispatchEvent(new Event('input', { bubbles: true }));
                    });
                    component.appendChild(btn);
                });
            }
            return { component, input };
        }
        static getActionName() {
            const actionNameDiv = document.querySelector('[class^="SkillActionDetail_name"]');
            return actionNameDiv ? actionNameDiv.textContent : '';
        }
        static getActionHrid(actionName) {
            return MWI_Toolkit_I18n.getHridByName(actionName, 'actionNames');
        }
        static getActionDetail(actionHrid) {
            return MWI_Toolkit.initClientData?.actionDetailMap?.[`${actionHrid}`];
        }
        static getActionTypeDrinkSlots(actionType) {
            if (!actionType) {
                return [];
            }
            const drinkSlots = [];
            MWI_Toolkit.gameObject?.state?.actionTypeDrinkSlotsDict?.[`/action_types/${actionType}`].forEach(drink => {
                if (drink && drink.itemHrid) {
                    drinkSlots.push(drink.itemHrid);
                }
            });
            // 对三采添加对应的工匠茶数据用于计算加工数量
            const processActionType = { milking: 'cheesesmithing', foraging: 'tailoring', woodcutting: 'crafting' }[actionType] || null;
            if (processActionType) {
                const processDrinkSlots = MWI_Toolkit.gameObject?.state?.actionTypeDrinkSlotsDict?.[`/action_types/${processActionType}`];
                processDrinkSlots.forEach(drink => {
                    if (drink && drink.itemHrid == '/items/artisan_tea') {
                        drinkSlots.push(drink.itemHrid);
                    }
                });
            }
            return drinkSlots;
        }
        static getDrinkConcentration() {
            const enhancementLevel = MWI_Toolkit_ItemsMap.getMaxEnhancementLevel("/items/guzzling_pouch");
            if (enhancementLevel != -1) {
                return 1
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/guzzling_pouch`].equipmentDetail.noncombatStats.drinkConcentration
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/guzzling_pouch`].equipmentDetail.noncombatEnhancementBonuses.drinkConcentration
                        * MWI_Toolkit.initClientData?.enhancementLevelTotalBonusMultiplierTable[enhancementLevel];
            }
            return 1;
        }
        static getEquipmentGatheringBuff() {
            let equipmentGatheringBuff = 0;
            const philosophers_earrings_enhancementLevel = MWI_Toolkit_ItemsMap.getMaxEnhancementLevel("/items/philosophers_earrings");
            const earrings_of_gathering_enhancementLevel = MWI_Toolkit_ItemsMap.getMaxEnhancementLevel("/items/earrings_of_gathering");
            const philosophers_ring_enhancementLevel = MWI_Toolkit_ItemsMap.getMaxEnhancementLevel("/items/philosophers_ring");
            const ring_of_gathering_enhancementLevel = MWI_Toolkit_ItemsMap.getMaxEnhancementLevel("/items/ring_of_gathering");
            if (philosophers_earrings_enhancementLevel != -1) {
                equipmentGatheringBuff = equipmentGatheringBuff
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/philosophers_earrings`].equipmentDetail.noncombatStats.gatheringQuantity
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/philosophers_earrings`].equipmentDetail.noncombatEnhancementBonuses.gatheringQuantity
                        * MWI_Toolkit.initClientData?.enhancementLevelTotalBonusMultiplierTable[philosophers_earrings_enhancementLevel];
            }
            else if (earrings_of_gathering_enhancementLevel != -1) {
                equipmentGatheringBuff = equipmentGatheringBuff
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/earrings_of_gathering`].equipmentDetail.noncombatStats.gatheringQuantity
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/earrings_of_gathering`].equipmentDetail.noncombatEnhancementBonuses.gatheringQuantity
                        * MWI_Toolkit.initClientData?.enhancementLevelTotalBonusMultiplierTable[earrings_of_gathering_enhancementLevel];
            }
            if (philosophers_ring_enhancementLevel != -1) {
                equipmentGatheringBuff = equipmentGatheringBuff
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/philosophers_ring`].equipmentDetail.noncombatStats.gatheringQuantity
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/philosophers_ring`].equipmentDetail.noncombatEnhancementBonuses.gatheringQuantity
                        * MWI_Toolkit.initClientData?.enhancementLevelTotalBonusMultiplierTable[philosophers_ring_enhancementLevel];
            }
            else if (ring_of_gathering_enhancementLevel != -1) {
                equipmentGatheringBuff = equipmentGatheringBuff
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/ring_of_gathering`].equipmentDetail.noncombatStats.gatheringQuantity
                    + MWI_Toolkit.initClientData?.itemDetailMap?.[`/items/ring_of_gathering`].equipmentDetail.noncombatEnhancementBonuses.gatheringQuantity
                        * MWI_Toolkit.initClientData?.enhancementLevelTotalBonusMultiplierTable[ring_of_gathering_enhancementLevel];
            }
            return equipmentGatheringBuff;
        }
        static getCommunityGatheringBuff() {
            const communityBuffs = MWI_Toolkit.gameObject?.state?.communityBuffs || [];
            for (const buff of communityBuffs) {
                if (buff.hrid === "/community_buff_types/gathering_quantity" && !buff.isDone) {
                    return buff.level * 0.005 + 0.195;
                }
            }
            return 0;
        }
    }
    /**
     * 可加工的动作映射
     */
    MWI_Toolkit_ActionDetailPlus.processableActionList = {
        "/items/milk": "/actions/milking/cow",
        "/items/verdant_milk": "/actions/milking/verdant_cow",
        "/items/azure_milk": "/actions/milking/azure_cow",
        "/items/burble_milk": "/actions/milking/burble_cow",
        "/items/crimson_milk": "/actions/milking/crimson_cow",
        "/items/rainbow_milk": "/actions/milking/unicow",
        "/items/holy_milk": "/actions/milking/holy_cow",
        "/items/log": "/actions/woodcutting/tree",
        "/items/birch_log": "/actions/woodcutting/birch_tree",
        "/items/cedar_log": "/actions/woodcutting/cedar_tree",
        "/items/purpleheart_log": "/actions/woodcutting/purpleheart_tree",
        "/items/ginkgo_log": "/actions/woodcutting/ginkgo_tree",
        "/items/redwood_log": "/actions/woodcutting/redwood_tree",
        "/items/arcane_log": "/actions/woodcutting/arcane_tree",
        "/items/cotton": "/actions/foraging/cotton",
        "/items/flax": "/actions/foraging/flax",
        "/items/bamboo_branch": "/actions/foraging/bamboo_branch",
        "/items/cocoon": "/actions/foraging/cocoon",
        "/items/radiant_fiber": "/actions/foraging/radiant_fiber"
    };
    /**
     * 可加工的物品映射
     */
    MWI_Toolkit_ActionDetailPlus.processableItemList = {
        "/items/milk": "/items/cheese",
        "/items/verdant_milk": "/items/verdant_cheese",
        "/items/azure_milk": "/items/azure_cheese",
        "/items/burble_milk": "/items/burble_cheese",
        "/items/crimson_milk": "/items/crimson_cheese",
        "/items/rainbow_milk": "/items/rainbow_cheese",
        "/items/holy_milk": "/items/holy_cheese",
        "/items/log": "/items/lumber",
        "/items/birch_log": "/items/birch_lumber",
        "/items/cedar_log": "/items/cedar_lumber",
        "/items/purpleheart_log": "/items/purpleheart_lumber",
        "/items/ginkgo_log": "/items/ginkgo_lumber",
        "/items/redwood_log": "/items/redwood_lumber",
        "/items/arcane_log": "/items/arcane_lumber",
        "/items/cotton": "/items/cotton_fabric",
        "/items/flax": "/items/linen_fabric",
        "/items/bamboo_branch": "/items/bamboo_fabric",
        "/items/cocoon": "/items/silk_fabric",
        "/items/radiant_fiber": "/items/radiant_fabric"
    };
    //#endregion
    //#region Utils
    /**
     * 静态工具类
     */
    class MWI_Toolkit_Utils {
        /**
         * 格式化数字为字符串
         * @param num 要格式化的数字
         * @returns 格式化后的字符串
         */
        static formatNumber(num) {
            // 类型和有效性检查
            if (!Number.isFinite(num)) {
                return '0';
            }
            // 确保非负数
            const normalizedNum = Math.max(0, num);
            // 小于1000:保留1位小数,但如果小数为0则只显示整数
            if (normalizedNum <= 999) {
                const fixed = normalizedNum.toFixed(1);
                return fixed.endsWith('.0') ? Math.round(normalizedNum).toString() : fixed;
            }
            // 小于100,000:向上取整
            if (normalizedNum <= 99999) {
                return Math.ceil(normalizedNum).toString();
            }
            // 小于10,000,000:显示xxxK (100K~9999K)
            if (normalizedNum <= 9999999) {
                return `${Math.floor(normalizedNum / 1000)}K`;
            }
            // 小于10,000,000,000:显示xxxM (100M~9999M)
            if (normalizedNum <= 9999999999) {
                return `${Math.floor(normalizedNum / 1000000)}M`;
            }
            // 小于10,000,000,000,000:显示xxxB (100B~9999B)
            if (normalizedNum <= 9999999999999) {
                return `${Math.floor(normalizedNum / 1000000000)}B`;
            }
            // 更大的数值显示NaN
            return 'NaN';
        }
        /**
         * 获取物品排序索引
         * @param hrid 物品的唯一标识符
         * @returns 物品的排序索引
         */
        static getSortIndexByItemHrid(hrid) {
            return (MWI_Toolkit.initClientData?.itemDetailMap?.[hrid]?.sortIndex || 9999);
        }
        /**
         * 获取物品排序索引
         * @param hrid 物品的唯一标识符
         * @returns 物品的排序索引
         */
        static getSortIndexByHouseRoomHrid(hrid) {
            return (MWI_Toolkit.initClientData?.houseRoomDetailMap?.[hrid]?.sortIndex || 0) - 9999;
        }
        /**
         * 获取物品图标的链接
         * @param itemHrid 物品的唯一标识符
         * @returns 物品图标的链接
         */
        static getIconHrefByItemHrid(itemHrid) {
            return '/static/media/items_sprite.d4d08849.svg#' + (itemHrid.split('/').pop() || '');
        }
        /**
         * 获取技能图标的链接
         * @param skillHrid 技能的唯一标识符
         * @returns 技能图标的链接
         */
        static getIconHrefBySkillHrid(skillHrid) {
            return '/static/media/skills_sprite.3bb4d936.svg#' + (skillHrid.split('/').pop() || '');
        }
        /**
         * 获取房屋图标的链接
         * @param houseRoomHrid 房屋的唯一标识符
         * @returns 房屋图标的链接
         */
        static getIconHrefByHouseRoomHrid(houseRoomHrid) {
            return MWI_Toolkit_Utils.getIconHrefBySkillHrid(MWI_Toolkit.initClientData?.houseRoomDetailMap?.[houseRoomHrid]?.skillHrid || houseRoomHrid);
        }
        /**
         * 获取杂项图标的链接
         * @param hrid 杂项的唯一标识符
         * @returns 杂项图标的链接
         */
        static getIconHrefByMiscHrid(hrid) {
            return '/static/media/misc_sprite.6fa5e97c.svg#' + (hrid.split('/').pop() || '');
        }
        /**
         * 触发React输入框的change事件
         * 通过操作React内部的_valueTracker来触发React的事件系统
         * @param inputElem HTML输入元素
         */
        static reactInputTriggerHack(inputElem) {
            const lastValue = inputElem.value;
            const event = new Event("input", { bubbles: true });
            // 添加自定义标记
            event.simulated = true;
            // 访问React内部的value tracker
            const tracker = inputElem._valueTracker;
            if (tracker) {
                // 触发变更:设置为不同的值以触发React的change检测
                tracker.setValue(lastValue === '' ? ' ' : '');
            }
            inputElem.dispatchEvent(event);
        }
    }
    //#endregion
    //#region I18n
    /**
     * 国际化静态工具类实现
     * 提供游戏内物品和其他资源的多语言名称查询功能
     */
    class MWI_Toolkit_I18n {
        /**
         * 获取物品的本地化名称
         * @param itemHrid 物品的唯一标识符
         * @returns 本地化后的物品名称,如果找不到则返回原始HRID
         */
        static getItemName(itemHrid) {
            return MWI_Toolkit_I18n.getName(itemHrid, "itemNames");
        }
        /**
         * 获取资源的本地化名称(通用方法)
         * @param hrid 资源的唯一标识符
         * @param category 资源分类(houseRoomNames, actionNames, itemNames)
         * @returns 本地化后的名称,如果找不到则返回原始HRID
         */
        static getName(hrid, category) {
            if (!hrid || !category) {
                return hrid;
            }
            // 特例自定义itemCategory名称
            if (hrid === '/item_categories/house_rooms') {
                return MWI_Toolkit?.getGameLanguage() === 'zh' ? '房屋' : 'House';
            }
            if (hrid === '/item_categories/materials') {
                return MWI_Toolkit?.getGameLanguage() === 'zh' ? '材料' : 'Materials';
            }
            return MWI_Toolkit.gameObject?.props?.i18n?.options?.resources?.[MWI_Toolkit?.getGameLanguage()]?.translation?.[category]?.[hrid] || hrid;
        }
        /**
         * 根据物品名称反查HRID
         * @param itemName 物品的本地化名称
         * @returns 对应的物品HRID,如果找不到则返回null
         */
        static getItemHridByName(itemName) {
            return MWI_Toolkit_I18n.getHridByName(itemName, "itemNames");
        }
        /**
         * 根据名称反查HRID(通用方法)
         * @param name 资源的本地化名称
         * @param category 资源分类(houseRoomNames, actionNames, itemNames)
         * @returns 对应的HRID,如果找不到则返回null
         */
        static getHridByName(name, category) {
            if (!name || !category) {
                return null;
            }
            return Object.entries(MWI_Toolkit.gameObject?.props?.i18n?.options?.resources?.[MWI_Toolkit?.getGameLanguage()]?.translation?.[category] || {})
                .find(([, v]) => (v || '').toLowerCase() === name.toLowerCase().trim())?.[0] ?? null;
        }
    }
    //#endregion
    //#region ItemsMap
    /**
     * 物品映射管理类实现
     * 使用二级Map结构存储物品数据:itemHrid -> enhancementLevel -> count
     * 提供物品查询和事件监听功能
     */
    class MWI_Toolkit_ItemsMap {
        /**
         * 查询指定物品和强化等级的数量
         * @param itemHrid 物品的唯一标识符
         * @param enhancementLevel 强化等级,默认为0
         * @returns 物品数量,如果不存在则返回0
         */
        static getCount(itemHrid, enhancementLevel = 0) {
            return MWI_Toolkit_ItemsMap.map.get(itemHrid)?.get(enhancementLevel) ?? 0;
        }
        /**
         * 查询指定物品的最大强化等级
         * @param itemHrid 物品的唯一标识符
         * @returns 最大强化等级,如果物品不存在或所有数量为0则返回-1
         */
        static getMaxEnhancementLevel(itemHrid) {
            const m = MWI_Toolkit_ItemsMap.map.get(itemHrid);
            if (!m) {
                return -1;
            }
            let max = -1;
            for (const [level, count] of m) {
                if (count > 0 && level > max) {
                    max = level;
                }
            }
            return max;
        }
        /**
         * 更新物品数据
         * @param endCharacterItems 要更新的物品列表
         */
        static update(endCharacterItems) {
            if (!endCharacterItems) {
                return;
            }
            for (const item of endCharacterItems) {
                if (!MWI_Toolkit_ItemsMap.map.has(item.itemHrid)) {
                    MWI_Toolkit_ItemsMap.map.set(item.itemHrid, new Map());
                }
                MWI_Toolkit_ItemsMap.map.get(item.itemHrid).set(item.enhancementLevel, item.count);
            }
            MWI_Toolkit_ItemsMap.itemsUpdatedCallbacks.forEach(cb => {
                try {
                    cb(endCharacterItems);
                }
                catch (e) {
                    console.error('[MWI_Toolkit] Error in item updated callback:', e);
                }
            });
        }
        /**
         * 清空所有物品数据
         */
        static clear() {
            MWI_Toolkit_ItemsMap.map.clear();
        }
    }
    /** 物品数据映射表:itemHrid -> (enhancementLevel -> count) */
    MWI_Toolkit_ItemsMap.map = new Map();
    /** 物品更新事件的回调函数列表 */
    MWI_Toolkit_ItemsMap.itemsUpdatedCallbacks = [];
    //#endregion
    //#region MWI_Toolkit
    /**
     * MWI工具包主类
     * 提供游戏数据抓取、国际化、物品管理等核心功能
     * 使用单例模式确保全局只有一个实例
     */
    class MWI_Toolkit {
        static getGameLanguage() {
            return MWI_Toolkit.gameObject?.language || 'zh';
        }
        /**
         * 启动工具包
         * 等待游戏页面加载完成后进行初始化
         */
        static start() {
            MWI_Toolkit.setupWebSocketInterceptor();
            MWI_Toolkit.waitForElement('[class^="GamePage"]', () => {
                MWI_Toolkit.initialize();
            });
        }
        /**
         * 设置 WebSocket 消息拦截器
         * 通过劫持 MessageEvent.prototype.data 来拦截所有 WebSocket 消息
         */
        static setupWebSocketInterceptor() {
            const oriGet = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data")?.get;
            if (!oriGet) {
                return;
            }
            Object.defineProperty(MessageEvent.prototype, "data", {
                get: function () {
                    const socket = this.currentTarget;
                    // 只拦截游戏服务器的 WebSocket 消息
                    if (!(socket instanceof WebSocket) ||
                        (socket.url.indexOf("api.milkywayidle.com/ws") === -1 && socket.url.indexOf("api-test.milkywayidle.com/ws") === -1)) {
                        return oriGet.call(this);
                    }
                    const message = oriGet.call(this);
                    Object.defineProperty(this, "data", { value: message }); // 防止循环调用
                    MWI_Toolkit?.handleWebSocketMessage(message);
                    return message;
                }
            });
        }
        /**
         * 处理 WebSocket 消息
         * 解析消息并根据类型进行相应处理
         * @param message WebSocket 消息内容(JSON字符串)
         */
        static handleWebSocketMessage(message) {
            try {
                const obj = JSON.parse(message);
                // 类型守卫:检查是否为对象
                if (!obj || typeof obj !== 'object')
                    return;
                const msgObj = obj;
                // 处理角色初始化消息(使用双重断言)
                if (msgObj.type === "init_character_data" && Array.isArray(msgObj.characterItems)) {
                    MWI_Toolkit.handleInitCharacterData(obj);
                }
                // 处理物品变更消息(使用双重断言)
                else if (Array.isArray(msgObj.endCharacterItems)) {
                    MWI_Toolkit.handleEndCharacterItems(obj);
                }
            }
            catch {
                // 忽略解析错误(非JSON消息或其他错误)
            }
        }
        /**
         * 处理角色初始化数据
         * 当切换角色或刷新页面时会收到此消息
         * @param data 角色初始化数据
         */
        static handleInitCharacterData(data) {
            // 清空并初始化物品映射表
            MWI_Toolkit_ItemsMap.clear();
            MWI_Toolkit_ItemsMap.update(data.characterItems);
            if (!MWI_Toolkit.initialized) {
                return;
            }
            console.log("[MWI_Toolkit] 界面刷新");
            MWI_Toolkit_Calculator.initializeCalculatorUI();
            MWI_Toolkit.waitForElement('[class^="GamePage"]', () => {
                MWI_Toolkit.gameObject = MWI_Toolkit.getGameObject();
            });
        }
        /**
         * 处理物品变更数据
         * 当物品数量、强化等级等发生变化时会收到此消息
         * @param data 包含变更后物品数据的消息
         */
        static handleEndCharacterItems(data) {
            // 更新物品映射表
            MWI_Toolkit_ItemsMap.update(data.endCharacterItems);
        }
        /**
         * 等待指定的DOM元素出现
         * 使用 MutationObserver 监听DOM变化
         * @param callback 元素出现后执行的回调函数
         */
        static waitForElement(selector, callback) {
            const el = document.querySelector(selector);
            if (el) {
                // 元素已存在,直接执行回调
                callback();
                return;
            }
            // 元素不存在,监听DOM变化
            const observer = new MutationObserver(() => {
                const el = document.querySelector(selector);
                if (el) {
                    observer.disconnect();
                    callback();
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
        }
        /**
         * 初始化工具包
         * 获取游戏对象实例并设置初始化标志
         */
        static initialize() {
            MWI_Toolkit.gameObject = MWI_Toolkit.getGameObject();
            MWI_Toolkit.initClientData = MWI_Toolkit.getInitClientData();
            if (!MWI_Toolkit.gameObject || !MWI_Toolkit.initClientData) {
                console.error("[MWI_Toolkit] 初始化失败");
                return;
            }
            MWI_Toolkit.initialized = true;
            MWI_Toolkit_ActionDetailPlus.initialize();
            MWI_Toolkit_Calculator.initialize();
            console.log("[MWI_Toolkit] 已初始化");
            console.log(MWI_Toolkit.gameObject, MWI_Toolkit.initClientData);
        }
        /**
         * 从DOM元素获取React组件实例
         * 通过访问React内部的Fiber节点来获取组件实例
         * @returns React组件实例,如果未找到则返回null
         */
        static getGameObject() {
            // (e => e?.[Object.keys(e).find(k => k.startsWith('__reactFiber$'))]?.return?.stateNode)(document.querySelector('[class^="GamePage"]'))
            const gamePageElement = document.querySelector('[class^="GamePage"]');
            if (!gamePageElement)
                return null;
            // 查找React Fiber的key(格式:__reactFiber$xxx)
            const reactKey = Object.keys(gamePageElement).find(k => k.startsWith('__reactFiber$'));
            if (!reactKey)
                return null;
            // 通过Fiber节点获取组件实例
            const fiber = gamePageElement[reactKey];
            return fiber?.return?.stateNode || null;
        }
        /**
         * 从localStorage获取初始化客户端数据
         * 数据以压缩的UTF-16字符串形式存储
         * @returns 初始化客户端数据对象,如果未找到则返回null
         */
        static getInitClientData() {
            const compressedData = localStorage.getItem("initClientData");
            if (compressedData) {
                const decompressedData = LZString.decompressFromUTF16(compressedData);
                return JSON.parse(decompressedData);
            }
            return null;
        }
    }
    /** 初始化客户端数据(从localStorage获取) */
    MWI_Toolkit.initClientData = null;
    /** 游戏对象实例(从React组件获取) */
    MWI_Toolkit.gameObject = null;
    /** 是否已初始化 */
    MWI_Toolkit.initialized = false;
    //#endregion
    // 防止重复加载
    if (window.MWI_Toolkit_Started) {
        return;
    }
    window.MWI_Toolkit_Started = true;
    // 启动工具包
    MWI_Toolkit.start();
})();