[MWI] Realtime Import Of Battle Simulation

Battle simulation imports the realtime configuration of the current character.

Устаревшая версия за 18.06.2025. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         [MWI] Realtime Import Of Battle Simulation
// @name:zh-CN   [银河奶牛]战斗模拟实时导入
// @namespace    http://tampermonkey.net/
// @version      0.0.1
// @description  Battle simulation imports the realtime configuration of the current character.
// @description:zh-CN  战斗模拟导入当前角色实时配置
// @icon         https://www.milkywayidle.com/favicon.svg
// @author       Yannis
// @license      CC-BY-NC-SA-4.0
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @match        https://shykai.github.io/mwisim.github.io/*
// @match        https://shykai.github.io/MWICombatSimulatorTest/dist/*
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==


(function () {
    'use strict';

    let playerId;
    let clientData = {};

    // 监听WebSocket
    function hookWS() {
        const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
        const oriGet = dataProperty.get;

        dataProperty.get = hookedGet;
        Object.defineProperty(MessageEvent.prototype, "data", dataProperty);

        function hookedGet() {
            const socket = this.currentTarget;
            if (!(socket instanceof WebSocket)) {
                return oriGet.call(this);
            }
            if (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 }); // Anti-loop

            try {
                handleMessage(message);
            } catch (e) {
                console.log(`处理聊天消息时出错: ${e}`)
            }
            return message;
        }
    }

    // 获取客户端初始化数据
    function getInitClientData() {
        return JSON.parse(GM_getValue("init_client_data", ""));
    }

    // 获取当前角色数据
    function getCurrentPlayerData() {
        let playersDataStr = GM_getValue("init_character_data", "");
        if (playersDataStr) {
            let playerData = JSON.parse(playersDataStr);
            return getPlayerData(playerData.character.id);
        } else {
            return;
        }
    }

    // 获取角色数据
    function getPlayerData(id) {
        let playersDataStr = GM_getValue("mwi_players_data", null) || JSON.stringify(new Array());
        let playersData = JSON.parse(playersDataStr);
        const pIndex = playersData.findIndex(obj => obj.character.id === id);
        if (pIndex !== -1) {
            return playersData[pIndex];
        } else {
            return;
        }
    }

    // 保存角色数据
    function saveCharacterData(obj) {
        let playersDataStr = GM_getValue("mwi_players_data", null) || JSON.stringify(new Array());
        let playersData = JSON.parse(playersDataStr);
        playersData = playersData.filter(e => e.character.id !== obj.character.id);
        playersData.unshift(obj);
        if (playersData.length > 5) {
            playersData.pop();
        }
        GM_setValue("mwi_players_data", JSON.stringify(playersData));
    }

    // 消息处理
    function handleMessage(message) {
        let obj = JSON.parse(message);
        if (!obj) {
            return;
        }
        switch (obj.type) {
            case 'pong': {
                // ping-pong
                break;
            }
            case 'active_player_count_updated': {
                // 活跃人数更新
                break;
            }
            case 'init_client_data': {
                // 客户端数据
                GM_setValue("init_client_data", message);
                clientData.actionDetailMap = obj.actionDetailMap;
                clientData.levelExperienceTable = obj.levelExperienceTable;
                clientData.itemDetailMap = obj.itemDetailMap;
                clientData.actionCategoryDetailMap = obj.actionCategoryDetailMap;
                clientData.abilityDetailMap = obj.abilityDetailMap;
                break;
            }
            case 'init_character_data': {
                // 初始化信息
                GM_setValue("init_character_data", message);
                playerId = obj.character.id;
                obj.battleObj = buildBattleObjFromPlayer(obj);
                saveCharacterData(obj);
                break;
            }
            case 'profile_shared': {
                // 角色详情
                let player = getPlayerData(obj.profile.characterSkills[0].characterID)
                let battleObj = buildBattleObjFromProfileShared(player, obj);
                if (!player) {
                    player = {}
                    player.character = {}
                    player.character.id = battleObj.character.id
                    player.character.name = battleObj.character.name
                }
                player.battleObj = battleObj;
                saveCharacterData(player);
                break;
            }
            case 'items_updated': {
                // 物品更新
                let player = getPlayerData(playerId);
                if (obj.endCharacterItems) {
                    for (const item of Object.values(obj.endCharacterItems)) {
                        if (item.itemLocationHrid !== "/item_locations/inventory") {
                            // 装备更新
                            let equipment = player.battleObj.player.equipment;
                            equipment = equipment.filter(e => e.itemLocationHrid !== item.itemLocationHrid);
                            equipment.push({
                                itemLocationHrid: item.itemLocationHrid,
                                itemHrid: item.itemHrid,
                                enhancementLevel: item.enhancementLevel,
                            })
                            player.battleObj.player.equipment = equipment;
                            saveCharacterData(player);
                        }
                    }
                }
                break;
            }
            case 'action_type_consumable_slots_updated': {
                // 消耗栏更新
                let player = getPlayerData(playerId);
                player.actionTypeDrinkSlotsMap = obj.actionTypeDrinkSlotsMap;
                player.actionTypeFoodSlotsMap = obj.actionTypeFoodSlotsMap;
                player.battleObj = buildBattleObjFromPlayer(player);
                saveCharacterData(player);
                break;
            }
            case 'abilities_updated': {
                // 技能更新
                let player = getPlayerData(playerId);
                for (const ability of obj.endCharacterAbilities) {
                    if (ability.slotNumber === 0) {
                        player.combatUnit.combatAbilities = player.combatUnit.combatAbilities.filter(a => a.abilityHrid !== ability.abilityHrid)
                    } else {
                        player.combatUnit.combatAbilities.splice(ability.slotNumber - 1, 0, {
                            abilityHrid: ability.abilityHrid,
                            level: ability.level,
                            experience: ability.experience,
                            availableTime: ability.updatedAt
                        });
                    }
                }
                player.battleObj = buildBattleObjFromPlayer(player);
                saveCharacterData(player);
                break;
            }
            case 'combat_triggers_updated': {
                let player = getPlayerData(playerId);
                if (obj.combatTriggerTypeHrid === '/combat_trigger_types/ability') {
                    // 技能栏 Trigger 更新
                    player.abilityCombatTriggersMap[obj.abilityHrid] = obj.combatTriggers;
                } else if (obj.combatTriggerTypeHrid === '/combat_trigger_types/consumable') {
                    // 消耗栏 Trigger 更新
                    player.consumableCombatTriggersMap[obj.itemHrid] = obj.combatTriggers;
                } else {
                    break;
                }
                player.battleObj = buildBattleObjFromPlayer(player);
                saveCharacterData(player);
                break;
            }
            case 'all_combat_triggers_updated': {
                // 所有 Triggers 更新
                let player = getPlayerData(playerId);
                player.abilityCombatTriggersMap = obj.abilityCombatTriggersMap;
                player.consumableCombatTriggersMap = obj.consumableCombatTriggersMap;
                player.battleObj = buildBattleObjFromPlayer(player);
                saveCharacterData(player);
                break;
            }
            case 'party_update': {
                // 队伍更新
                let player = getPlayerData(playerId);
                player.partyInfo = obj.partyInfo;
                saveCharacterData(player);
                break;
            }
            case 'chat_message_received': {
                // 聊天消息
                break;
            }
            case 'action_completed': {
                // 行动完成
                break;
            }
            default: {
                // console.log(obj)
            }
        }
    }

    // 添加实时导入按钮
    function addImportButtonForMWICombatSimulate() {
        const checkElem = () => {
            const btnEquipSets = document.querySelector(`button#buttonEquipmentSets`);
            if (btnEquipSets) {
                clearInterval(timer);

                let divRow = document.createElement("div");
                divRow.className = "row";
                btnEquipSets.parentElement.parentElement.prepend(divRow);

                // 导入按钮
                let div1 = document.createElement("div");
                div1.className = "col-md-auto mb-2 pt-3";
                divRow.append(div1);
                let button = document.createElement("button");
                div1.append(button);
                button.textContent = "实时导入数据";
                button.className = "btn btn-warning";
                button.onclick = function () {
                    const btnGetPrice = document.querySelector(`button#buttonGetPrices`);
                    if (btnGetPrice) {
                        btnGetPrice.click();
                    }
                    importDataForMWICombatSimulate(button);
                    return false;
                };
            }
        };
        let timer = setInterval(checkElem, 200);
    }

    // 导入数据
    async function importDataForMWICombatSimulate(button) {
        clientData = getInitClientData();
        let player = getCurrentPlayerData();

        const BLANK_PLAYER_JSON_STR = `{\"player\":{\"attackLevel\":1,\"magicLevel\":1,\"powerLevel\":1,\"rangedLevel\":1,\"defenseLevel\":1,\"staminaLevel\":1,\"intelligenceLevel\":1,\"equipment\":[]},\"food\":{\"/action_types/combat\":[{\"itemHrid\":\"\"},{\"itemHrid\":\"\"},{\"itemHrid\":\"\"}]},\"drinks\":{\"/action_types/combat\":[{\"itemHrid\":\"\"},{\"itemHrid\":\"\"},{\"itemHrid\":\"\"}]},\"abilities\":[{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"}],\"triggerMap\":{},\"zone\":\"/actions/combat/fly\",\"simulationTime\":\"100\",\"houseRooms\":{\"/house_rooms/dairy_barn\":0,\"/house_rooms/garden\":0,\"/house_rooms/log_shed\":0,\"/house_rooms/forge\":0,\"/house_rooms/workshop\":0,\"/house_rooms/sewing_parlor\":0,\"/house_rooms/kitchen\":0,\"/house_rooms/brewery\":0,\"/house_rooms/laboratory\":0,\"/house_rooms/observatory\":0,\"/house_rooms/dining_room\":0,\"/house_rooms/library\":0,\"/house_rooms/dojo\":0,\"/house_rooms/gym\":0,\"/house_rooms/armory\":0,\"/house_rooms/archery_range\":0,\"/house_rooms/mystical_study\":0}}`;

        const playerNames = {};
        const imported = {};
        const battleData = {};
        let isParty = false;
        let zone = "/actions/combat/fly";
        let isZoneDungeon = false;

        if (!player?.partyInfo?.partySlotMap) {
            // 个人
            playerNames[0] = player.character.name;
            imported[0] = true;
            battleData[0] = player.battleObj;
            // Zone
            for (const action of player.characterActions) {
                if (action && action.actionHrid.includes("/actions/combat/")) {
                    zone = action.actionHrid;
                    isZoneDungeon = clientData.actionDetailMap[action.actionHrid]?.combatZoneInfo?.isDungeon;
                    break;
                }
            }
        } else {
            // 队伍
            isParty = true;
            let i = 0;
            for (const member of Object.values(player.partyInfo.partySlotMap)) {
                i++;
                if (member.characterID) {
                    if (member.characterID === player.character.id) {
                        playerNames[i] = player.character.name;
                        imported[i] = true;
                        battleData[i] = JSON.stringify(player.battleObj);
                        continue;
                    } else {
                        let memberData = getPlayerData(member.characterID);
                        if (memberData) {
                            playerNames[i] = memberData.character.name;
                            imported[i] = true;
                            battleData[i] = JSON.stringify(memberData.battleObj);
                            continue;
                        } else {
                            playerNames[i] = "需要点开资料";
                            imported[i] = true;
                            battleData[i] = BLANK_PLAYER_JSON_STR;
                        }
                    }
                }
            }
            // Zone
            zone = player.partyInfo?.party?.actionHrid;
            isZoneDungeon = clientData.actionDetailMap[zone]?.combatZoneInfo?.isDungeon;
        }

        // Select zone or dungeon
        if (zone) {
            if (isZoneDungeon) {
                document.querySelector(`input#simDungeonToggle`).checked = true;
                document.querySelector(`input#simDungeonToggle`).dispatchEvent(new Event("change"));
                const selectDungeon = document.querySelector(`select#selectDungeon`);
                for (let i = 0; i < selectDungeon.options.length; i++) {
                    if (selectDungeon.options[i].value === zone) {
                        selectDungeon.options[i].selected = true;
                        break;
                    }
                }
            } else {
                document.querySelector(`input#simDungeonToggle`).checked = false;
                document.querySelector(`input#simDungeonToggle`).dispatchEvent(new Event("change"));
                const selectZone = document.querySelector(`select#selectZone`);
                for (let i = 0; i < selectZone.options.length; i++) {
                    if (selectZone.options[i].value === zone) {
                        selectZone.options[i].selected = true;
                        break;
                    }
                }
            }
        }

        for (let i = 1; i <= 5; i++) {
            if (!battleData[i]) {
                battleData[i] = BLANK_PLAYER_JSON_STR;
                playerNames[i] = `Player ${i}`;
                imported[i] = false;
            }
            document.querySelector(`a#player${i}-tab`).textContent = playerNames[i];
            if (document.querySelector(`input#player${i}.form-check-input.player-checkbox`)) {
                document.querySelector(`input#player${i}.form-check-input.player-checkbox`).checked = imported[i];
                document.querySelector(`input#player${i}.form-check-input.player-checkbox`).dispatchEvent(new Event("change"));
            }
        }

        document.querySelector(`a#group-combat-tab`).click();
        const editImport = document.querySelector(`input#inputSetGroupCombatAll`);
        editImport.value = JSON.stringify(battleData);
        document.querySelector(`button#buttonImportSet`).click();

        // 模拟时长
        document.querySelector(`input#inputSimulationTime`).value = 24;

        button.textContent = "成功导入数据";
        button.className = "btn btn-success";
        setTimeout(() => {
            button.textContent = "实时导入数据";
            button.className = "btn btn-warning";
        }, 1000);

        if (!isParty) {
            setTimeout(() => {
                document.querySelector(`button#buttonStartSimulation`).click();
            }, 500);
        }
    }

    // 监听模拟结果
    async function observeResultsForMWICombatSimulate() {
        let resultDiv = document.querySelector(`div.row`)?.querySelectorAll(`div.col-md-5`)?.[2]?.querySelector(`div.row > div.col-md-5`);
        while (!resultDiv) {
            await new Promise((resolve) => setTimeout(resolve, 100));
            resultDiv = document.querySelector(`div.row`)?.querySelectorAll(`div.col-md-5`)?.[2]?.querySelector(`div.row > div.col-md-5`);
        }

        const deathDiv = document.querySelector(`div#simulationResultPlayerDeaths`);
        const expDiv = document.querySelector(`div#simulationResultExperienceGain`);
        const consumeDiv = document.querySelector(`div#simulationResultConsumablesUsed`);
        deathDiv.style.backgroundColor = "#FFEAE9";
        deathDiv.style.color = "black";
        expDiv.style.backgroundColor = "#CDFFDD";
        expDiv.style.color = "black";
        consumeDiv.style.backgroundColor = "#F0F8FF";
        consumeDiv.style.color = "black";

        let div = document.createElement("div");
        div.id = "tillLevel";
        div.style.backgroundColor = "#FFFFE0";
        div.style.color = "black";
        div.textContent = "";
        resultDiv.append(div);
    }

    // 构建战斗模拟信息(InitData)
    function buildBattleObjFromPlayer(obj) {
        let battleObj = {};
        // Base
        battleObj.character = {}
        battleObj.character.id = obj.character.id;
        battleObj.character.name = obj.character.name;
        battleObj.character.gameMode = obj.character.gameMode;
        battleObj.timestamp = Date.now();
        // Levels
        battleObj.player = {}
        for (const skill of obj.characterSkills) {
            if (skill.skillHrid.includes("stamina")) {
                battleObj.player.staminaLevel = skill.level;
            } else if (skill.skillHrid.includes("intelligence")) {
                battleObj.player.intelligenceLevel = skill.level;
            } else if (skill.skillHrid.includes("attack")) {
                battleObj.player.attackLevel = skill.level;
            } else if (skill.skillHrid.includes("power")) {
                battleObj.player.powerLevel = skill.level;
            } else if (skill.skillHrid.includes("defense")) {
                battleObj.player.defenseLevel = skill.level;
            } else if (skill.skillHrid.includes("ranged")) {
                battleObj.player.rangedLevel = skill.level;
            } else if (skill.skillHrid.includes("magic")) {
                battleObj.player.magicLevel = skill.level;
            }
        }
        // Equipments
        battleObj.player.equipment = [];
        if (obj.characterItems) {
            for (const item of obj.characterItems) {
                if (!item.itemLocationHrid.includes("/item_locations/inventory")) {
                    battleObj.player.equipment.push({
                        itemLocationHrid: item.itemLocationHrid,
                        itemHrid: item.itemHrid,
                        enhancementLevel: item.enhancementLevel,
                    });
                }
            }
        }
        // Food
        battleObj.food = {}
        battleObj.food["/action_types/combat"] = [];
        if (obj.actionTypeFoodSlotsMap["/action_types/combat"]) {
            for (const food of obj.actionTypeFoodSlotsMap["/action_types/combat"]) {
                if (food) {
                    battleObj.food["/action_types/combat"].push({
                        itemHrid: food.itemHrid,
                    });
                } else {
                    battleObj.food["/action_types/combat"].push({
                        itemHrid: "",
                    });
                }
            }
        }
        // Drinks
        battleObj.drinks = {}
        battleObj.drinks["/action_types/combat"] = [];
        if (obj.actionTypeDrinkSlotsMap["/action_types/combat"]) {
            for (const drink of obj.actionTypeDrinkSlotsMap["/action_types/combat"]) {
                if (drink) {
                    battleObj.drinks["/action_types/combat"].push({
                        itemHrid: drink.itemHrid,
                    });
                } else {
                    battleObj.drinks["/action_types/combat"].push({
                        itemHrid: "",
                    });
                }
            }
        }
        // Abilities
        battleObj.abilities = [
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
        ];
        if (obj.combatUnit.combatAbilities) {
            let index = 1;
            for (const ability of obj.combatUnit.combatAbilities) {
                if (ability && clientData.abilityDetailMap[ability.abilityHrid].isSpecialAbility) {
                    battleObj.abilities[0] = {
                        abilityHrid: ability.abilityHrid,
                        level: ability.level,
                    };
                } else if (ability) {
                    battleObj.abilities[index++] = {
                        abilityHrid: ability.abilityHrid,
                        level: ability.level,
                    };
                }
            }
        }
        // TriggerMap
        battleObj.triggerMap = { ...obj.abilityCombatTriggersMap, ...obj.consumableCombatTriggersMap };
        // HouseRooms
        battleObj.houseRooms = {};
        if (obj.characterHouseRoomMap) {
            for (const house of Object.values(obj.characterHouseRoomMap)) {
                battleObj.houseRooms[house.houseRoomHrid] = house.level;
            }
        }
        return battleObj;
    }

    // 构建战斗模拟信息(ProfileShared)
    function buildBattleObjFromProfileShared(player, obj) {
        let battleObj = {};
        // Base
        battleObj.character = {}
        battleObj.character.id = player ? player.character.id : obj.profile.characterSkills[0].characterID;
        battleObj.character.name = obj.profile.sharableCharacter.name;
        battleObj.character.gameMode = obj.profile.sharableCharacter.gameMode;
        battleObj.timestamp = Date.now();
        // Levels
        battleObj.player = {}
        for (const skill of obj.profile.characterSkills) {
            if (skill.skillHrid.includes("stamina")) {
                battleObj.player.staminaLevel = skill.level;
            } else if (skill.skillHrid.includes("intelligence")) {
                battleObj.player.intelligenceLevel = skill.level;
            } else if (skill.skillHrid.includes("attack")) {
                battleObj.player.attackLevel = skill.level;
            } else if (skill.skillHrid.includes("power")) {
                battleObj.player.powerLevel = skill.level;
            } else if (skill.skillHrid.includes("defense")) {
                battleObj.player.defenseLevel = skill.level;
            } else if (skill.skillHrid.includes("ranged")) {
                battleObj.player.rangedLevel = skill.level;
            } else if (skill.skillHrid.includes("magic")) {
                battleObj.player.magicLevel = skill.level;
            }
        }
        // Equipments
        battleObj.player.equipment = [];
        if (obj.profile.wearableItemMap) {
            for (const key in obj.profile.wearableItemMap) {
                const item = obj.profile.wearableItemMap[key];
                battleObj.player.equipment.push({
                    itemLocationHrid: item.itemLocationHrid,
                    itemHrid: item.itemHrid,
                    enhancementLevel: item.enhancementLevel,
                });
            }
        }
        // Food and Drinks
        battleObj.food = {}
        battleObj.food["/action_types/combat"] = [];
        battleObj.drinks = {}
        battleObj.drinks["/action_types/combat"] = [];
        let wearableItemMap = obj.profile.wearableItemMap;
        const weapon = wearableItemMap && (
            wearableItemMap["/item_locations/main_hand"]?.itemHrid
            || wearableItemMap["/item_locations/two_hand"]?.itemHrid
        );
        if (player) {
            battleObj.food = player.battleObj.food;
            battleObj.drinks = player.battleObj.drinks;
        } else if (weapon) {
            if (weapon.includes("shooter") || weapon.includes("bow")) {
                // 远程
                battleObj.food["/action_types/combat"] = [
                    // 2红1蓝
                    { itemHrid: "/items/spaceberry_donut" },
                    { itemHrid: "/items/spaceberry_cake" },
                    { itemHrid: "/items/star_fruit_yogurt" }
                ]
                battleObj.drinks["/action_types/combat"] = [
                    // 经验.超远.暴击
                    { itemHrid: "/items/wisdom_coffee" },
                    { itemHrid: "/items/super_ranged_coffee" },
                    { itemHrid: "/items/critical_coffee" }
                ]
            } else if (weapon.includes("boomstick") || weapon.includes("staff")) {
                // 法师
                battleObj.food["/action_types/combat"] = [
                    // 1红2蓝
                    { itemHrid: "/items/spaceberry_cake" },
                    { itemHrid: "/items/star_fruit_gummy" },
                    { itemHrid: "/items/star_fruit_yogurt" }
                ]
                battleObj.drinks["/action_types/combat"] = [
                    // 经验.超魔.吟唱
                    { itemHrid: "/items/wisdom_coffee" },
                    { itemHrid: "/items/super_magic_coffee" },
                    { itemHrid: "/items/channeling_coffee" }
                ]
            } else if (weapon.includes("bulwark")) {
                // 双手盾
                battleObj.food["/action_types/combat"] = [
                    // 2红1蓝
                    { itemHrid: "/items/spaceberry_donut" },
                    { itemHrid: "/items/spaceberry_cake" },
                    { itemHrid: "/items/star_fruit_yogurt" }
                ]
                battleObj.drinks["/action_types/combat"] = [
                    // 经验.超防.超耐
                    { itemHrid: "/items/wisdom_coffee" },
                    { itemHrid: "/items/super_defense_coffee" },
                    { itemHrid: "/items/super_stamina_coffee" }
                ]
            } else {
                // 近战
                battleObj.food["/action_types/combat"] = [
                    // 2红1蓝
                    { itemHrid: "/items/spaceberry_donut" },
                    { itemHrid: "/items/spaceberry_cake" },
                    { itemHrid: "/items/star_fruit_yogurt" }
                ]
                battleObj.drinks["/action_types/combat"] = [
                    // 经验.超力.迅捷
                    { itemHrid: "/items/wisdom_coffee" },
                    { itemHrid: "/items/super_power_coffee" },
                    { itemHrid: "/items/swiftness_coffee" }
                ]
            }
        }

        // Abilities
        battleObj.abilities = [
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
            {
                abilityHrid: "",
                level: "1",
            },
        ];
        if (obj.profile.equippedAbilities) {
            let index = 1;
            for (const ability of obj.profile.equippedAbilities) {
                if (ability && clientData.abilityDetailMap[ability.abilityHrid].isSpecialAbility) {
                    battleObj.abilities[0] = {
                        abilityHrid: ability.abilityHrid,
                        level: ability.level,
                    };
                } else if (ability) {
                    battleObj.abilities[index++] = {
                        abilityHrid: ability.abilityHrid,
                        level: ability.level,
                    };
                }
            }
        }
        // TriggerMap
        if (player) {
            battleObj.triggerMap = player.battleObj.triggerMap;
        }
        // HouseRooms
        battleObj.houseRooms = {};
        for (const house of Object.values(obj.profile.characterHouseRoomMap)) {
            battleObj.houseRooms[house.houseRoomHrid] = house.level;
        }
        return battleObj;
    }

    if (localStorage.getItem("initClientData")) {
        const obj = JSON.parse(localStorage.getItem("initClientData"));
        GM_setValue("init_client_data", localStorage.getItem("initClientData"));

        clientData.actionDetailMap = obj.actionDetailMap;
        clientData.levelExperienceTable = obj.levelExperienceTable;
        clientData.itemDetailMap = obj.itemDetailMap;
        clientData.actionCategoryDetailMap = obj.actionCategoryDetailMap;
        clientData.abilityDetailMap = obj.abilityDetailMap;
    }

    if (document.URL.includes("shykai.github.io/MWICombatSimulatorTest/")) {
        addImportButtonForMWICombatSimulate();
        observeResultsForMWICombatSimulate();
    }

    hookWS();

})();