// ==UserScript== // @name 牛牛战斗助手 // @namespace http://tampermonkey.net/ // @version 0.0.4 // @description 牛牛 // @icon https://www.milkywayidle.com/favicon.svg // @author xiaoshui // @match https://www.milkywayidle.com/* // @grant GM_xmlhttpRequest // @connect niuniu.0xa2c2a.shop // @license MIT // @downloadURL none // ==/UserScript== (function() { if (document.URL.includes("test.milkywayidle.com"))return; const host = "https://niuniu.0xa2c2a.shop" let config={ sikll_upload: host + "/api/player", party_upload:host + "/api/party", api_version:"0.0.1" } // 拦截WS function hookWebSocket() { 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 }); return handleMessage(message); } } hookWebSocket(); // WS拦截后处理,主进程 function handleMessage(message,debug=false) { let obj = JSON.parse(message); if (obj && obj.type === "init_character_data") { // 组队情况 addPartyButton(); addPlayerButton(); // 上传初始化登录数据 uploadInitCharacterData(obj); }else if (obj && obj.type === "profile_shared"){ // 上传玩家面板数据 uploadProfileShared(obj); } //other return message; } // 上传玩家面板数据 function uploadProfileShared(obj){ let data={}; let profile = obj.profile; data.name=profile.sharableCharacter.name if(profile.sharableCharacter.gameMode !== "standard")return; data.weapon = profile.wearableItemMap === null ?null:getWeapon(profile?.wearableItemMap); let ranged,attack,power,magic = ""; for( const item of profile.characterSkills){ if(item.skillHrid === "/skills/ranged"){ ranged = item.experience.toFixed(); data.id=item.characterID; }else if(item.skillHrid === "/skills/attack"){ attack = item.experience.toFixed(); } else if(item.skillHrid === "/skills/power"){ power = item.experience.toFixed(); }else if(item.skillHrid === "/skills/magic"){ magic = item.experience.toFixed(); } } data.skill=ranged+","+attack+","+power+","+magic; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'POST', url: config.sikll_upload, headers: { "Content-Type": "application/json", "reporter":data.id, "apiVersion":config.api_version }, data:JSON.stringify(data), onload: function (response) { resolve(); }, onerror: function (error) { reject(error); } }); }); } function getWeapon(wearableItemMap){ if(!wearableItemMap) return null; let hand = wearableItemMap['/item_locations/main_hand']?.itemHrid if(!hand){ hand = wearableItemMap['/item_locations/two_hand']?.itemHrid } return hand?.substr(7) } // 上传初始化登录数据 function uploadInitCharacterData(obj){ const fake_profile_shared={} fake_profile_shared.type="profile_shared"; fake_profile_shared.profile={}; fake_profile_shared.profile.characterSkills=obj.characterSkills; fake_profile_shared.profile.combatLevel=obj.combatUnit.combatDetails.combatLevel; if(obj.guild){ fake_profile_shared.profile.guildName=obj.guild.name; fake_profile_shared.profile.guildRole=obj.guildCharacterMap[obj.character.id].role; }else{ fake_profile_shared.profile.guildName=""; fake_profile_shared.profile.guildRole=""; } fake_profile_shared.profile.sharableCharacter=obj.character; fake_profile_shared.profile.wearableItemMap={} obj.characterItems.forEach(item=>{ if(item.itemLocationHrid!='/item_locations/inventory'){ fake_profile_shared.profile.wearableItemMap[item.itemLocationHrid]=item; } }) uploadProfileShared(fake_profile_shared); uploadPartyInfo(obj); } // 上传组队数据 function uploadPartyInfo(obj){ let data={}; const partyInfo = obj?.partyInfo if((!partyInfo) || (partyInfo?.party?.status !== "battling")) return; data.id=partyInfo.party.id; data.map=partyInfo.party.actionHrid.substr(16); data.players=""; for(let k in partyInfo.sharableCharacterMap){ if(data.players) data.players += "," data.players += partyInfo.sharableCharacterMap[k].name } let reporter = obj.user.id; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'POST', url: config.party_upload, headers: { "Content-Type": "application/json", "reporter":reporter, "apiVersion":config.api_version }, data:JSON.stringify(data), onload: function (response) { resolve(); }, onerror: function (error) { reject(error); } }); }); } //组队情况 function addPartyButton() { const waitForNavi = () => { const targetNode = document.querySelector("div.NavigationBar_minorNavigationLinks__dbxh7"); // 确认这个选择器是否适合你的环境 const navigationLinks = document.querySelectorAll('div.NavigationBar_minorNavigationLink__31K7Y'); let toolLink; for (let link of navigationLinks) { if (link.textContent.includes('插件设置')||link.textContent.includes('Script settings')) { toolLink = link; break; } } if (targetNode&&toolLink) { let statsButton = document.createElement("div"); statsButton.setAttribute("class", "NavigationBar_minorNavigationLink__31K7Y"); statsButton.style.color = toolLink.style.color; statsButton.innerHTML = "国人组队情况"; statsButton.addEventListener("click", () => { window.open("https://niuniu.0xa2c2a.shop/party.html", "_blank"); }); // 将按钮添加到目标节点 targetNode.insertBefore(statsButton, toolLink.nextSibling); } else { setTimeout(addPartyButton, 200); } }; waitForNavi(); // 开始等待目标节点出现 } //组队情况 function addPlayerButton() { const waitForNavi = () => { const targetNode = document.querySelector("div.NavigationBar_minorNavigationLinks__dbxh7"); // 确认这个选择器是否适合你的环境 const navigationLinks = document.querySelectorAll('div.NavigationBar_minorNavigationLink__31K7Y'); let toolLink; for (let link of navigationLinks) { if (link.textContent.includes('插件设置')||link.textContent.includes('Script settings')) { toolLink = link; break; } } if (targetNode&&toolLink) { let statsButton = document.createElement("div"); statsButton.setAttribute("class", "NavigationBar_minorNavigationLink__31K7Y"); statsButton.style.color = toolLink.style.color; statsButton.innerHTML = "战斗排行榜"; statsButton.addEventListener("click", () => { window.open("https://niuniu.0xa2c2a.shop/player.html", "_blank"); }); // 将按钮添加到目标节点 targetNode.insertBefore(statsButton, toolLink.nextSibling); } else { setTimeout(addPlayerButton, 200); } }; waitForNavi(); // 开始等待目标节点出现 } })();