- // ==UserScript==
- // @name 9战
- // @namespace http://tampermonkey.net/
- // @version 2025-03-30
- // @description 9战1
- // @author You
- // @match https://www.milkywayidle.com/game*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com
- // @grant none
- // @license MIT
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
-
-
- class AutoFramework {
- static #isPaused = true;
- static #controlBar;
- static #func = null;
-
- // 设置自动化函数
- static setFunc(f) {
- this.#func = f;
- }
-
- // 初始化控制栏
- static initControlBar() {
- this.#controlBar = document.createElement('div');
- this.#controlBar.id = 'autoFrameworkControlBar';
- this.#controlBar.style = `
- position: fixed;
- top: 0;
- left: 50%;
- transform: translateX(-50%);
- padding: 10px 20px; /* 增加横向内边距 */
- background: rgba(0,0,0,0.7);
- color: white;
- border-radius: 8px; /* 添加圆角 */
- box-shadow: 0 2px 6px rgba(0,0,0,0.3); /* 添加阴影 */
- z-index: 99999;
- `;
-
- const input = document.createElement('input');
- input.id = 'input-9-name'
- input.value = '沼泽星球'
-
- const btn = document.createElement('button');
- btn.textContent = '开启9战';
- btn.style = `
- padding: 8px 16px;
- font-size: 16px;
- background: #f44336;
- color: white;
- border: none;
- cursor: pointer;
- border-radius: 4px;
- `;
- btn.addEventListener('click', () => this.togglePause());
- this.#controlBar.appendChild(input);
- this.#controlBar.appendChild(btn);
- document.body.appendChild(this.#controlBar);
- }
-
- static togglePause() {
- this.#isPaused = !this.#isPaused;
- const btn = this.#controlBar.querySelector('button');
- btn.textContent = this.#isPaused ? '开启' : '暂停';
- btn.style.backgroundColor = this.#isPaused ? '#f44336' : '#4CAF50';
- }
-
- static isPaused() {
- return this.#isPaused;
- }
-
- static async run() {
- while (true) {
- if (!this.#isPaused && this.#func) {
- try {
- await this.#func();
- } catch (error) {
- console.error('执行出错:', error);
- }
- }
- await new Promise(resolve => setTimeout(resolve, 100));
- }
- }
-
- static findElementsByText(text, options = {}) {
- const {
- exact = false, // 是否精确匹配
- selector = '*', // 初始选择器(缩小搜索范围)
- visible = true // 是否仅可见元素
- } = options;
-
- const elements = document.querySelectorAll(selector);
- return Array.from(elements).filter(element => {
- if (visible && !this.isVisible(element)) return false;
- const content = element.textContent.trim();
- if (exact) return content === text;
- else return content.includes(text);
- });
- }
-
- static findElementByText(text, options) {
- const elements = this.findElementsByText(text, options);
- return elements.length > 0 ? elements[0] : null;
- }
-
- static clickElement(element) {
- if (element) {
- const event = new MouseEvent('click', {
- view: window,
- bubbles: true,
- cancelable: true
- });
- element.dispatchEvent(event);
- }
- }
-
- static async waitForElement(selector, timeout = 5000) {
- return new Promise((resolve, reject) => {
- const interval = setInterval(() => {
- const element = document.querySelector(selector);
- if (element) {
- clearInterval(interval);
- resolve(element);
- } else if (timeout <= 0) {
- clearInterval(interval);
- reject('元素未找到');
- }
- timeout -= 100;
- }, 100);
- });
- }
-
- static async waitForText(text, options = {}) {
- if (this.isPaused()) return Promise.reject('脚本已暂停');
- const { timeout = 5000, ...findOptions } = options;
- let timeout1 = timeout
- return new Promise((resolve, reject) => {
- const interval = setInterval(() => {
- const element = this.findElementByText(text, findOptions);
- if (element) {
- clearInterval(interval);
- resolve(element);
- } else if (timeout1 <= 0) {
- clearInterval(interval);
- reject(`文本 "${text}" 未找到`);
- }
- timeout1 -= 100;
- }, 100);
- });
- }
-
- static isVisible(element) {
- return element.offsetWidth > 0 && element.offsetHeight > 0;
- }
-
- static async clickByText(text, options = {}) {
- if (this.isPaused()) return;
- try {
- const element = await this.waitForText(text, options);
- this.clickElement(element);
- } catch (error) {
- console.error(`点击失败: ${error}`);
- }
- }
-
- static async getTextByText(text, options = {}) {
- try {
- const element = await this.waitForText(text, options);
- return element.textContent.trim();
- } catch (error) {
- console.error(`获取文本失败: ${error}`);
- return null;
- }
- }
-
- static findElementsByAttr(attrName, attrValue, options = {}) {
- const {
- exact = true, // 是否精确匹配(false为包含匹配)
- selector = '*', // 初始选择器
- visible = true // 是否仅可见元素
- } = options;
- const elements = document.querySelectorAll(selector);
-
- return Array.from(elements).filter(element => {
- if (visible && !this.isVisible(element)) return false;
- const attr = element.getAttribute(attrName);
- if (!attr) return false;
-
- if (exact) {
- return attr === attrValue;
- } else {
- return attr.includes(attrValue);
- }
- });
- }
-
- static findElementByAttr(attrName, attrValue, options) {
- const elements = this.findElementsByAttr(attrName, attrValue, options);
- return elements.length > 0 ? elements[0] : null;
- }
-
- static async waitForAttr(attrName, attrValue, options = {}) {
- if (this.isPaused()) return Promise.reject('脚本已暂停');
- const { timeout = 5000, ...findOptions } = options;
- let timeout1 = timeout
- return new Promise((resolve, reject) => {
- const interval = setInterval(() => {
- const element = this.findElementByAttr(attrName, attrValue, findOptions);
- if (element) {
- clearInterval(interval);
- resolve(element);
- } else if (timeout1 <= 0) {
- clearInterval(interval);
- reject(`属性匹配失败: ${attrName}=${attrValue}`);
- }
- timeout1 -= 100;
- }, 100);
- });
- }
-
- static async clickByAttr(attrName, attrValue, options = {}) {
- if (this.isPaused()) return;
- try {
- const element = await this.waitForAttr(attrName, attrValue, options);
- this.clickElement(element);
- } catch (error) {
- console.error(`属性点击失败: ${error}`);
- }
- }
-
-
- static reactInputTriggerHack(inputElem, value) {
- let lastValue = inputElem.value;
- inputElem.value = value;
- let event = new Event("input", { bubbles: true });
- event.simulated = true;
- let tracker = inputElem._valueTracker;
- if (tracker) {
- tracker.setValue(lastValue);
- }
- inputElem.dispatchEvent(event);
- }
-
- // 新增:根据class设置输入框值(支持React)
- static async setInputValueByClass(className, value, options = {}) {
- if (this.isPaused()) return;
- try {
- const element = await this.waitForAttr('class', className, {
- selector: 'input', // 仅限input元素
- exact: false,
- // 包含匹配
- ...options
- });
- if (!element) throw new Error(`未找到class为${className}的input元素`);
-
- this.reactInputTriggerHack(element, value);
- console.log(`设置输入值成功: ${className} -> ${value}`);
- } catch (error) {
- console.error('设置输入值失败:', error);
- }
- }
- }
-
- async function actions() {
- const input = document.querySelector('#input-9-name').value
- if(!input){
- return
- }
- try {
- await AutoFramework.clickByText('战斗区域', {
- selector: 'button',
- timeout: 3000,
- exact: false //模糊 true 精确
- });
-
- await AutoFramework.clickByText(input, {
- selector: 'button',
- timeout: 3000,
- exact: false
- });
-
- await AutoFramework.clickByAttr('href', 'swamp_planet', {
- selector: 'use',
- exact: false,
- timeout: 3000,
- visible:false
- });
-
- await AutoFramework.setInputValueByClass('Input_input__2-t98', 9, {
- timeout: 3000
- });
- await AutoFramework.clickByText('添加到队列', {
- selector: 'button',
- timeout: 3000,
- exact: false
- });
-
- } catch (error) {
- console.error('自动化失败:', error);
- }
- }
-
- // 启动脚本
- (async () => {
- AutoFramework.initControlBar();
- AutoFramework.setFunc(actions);
- AutoFramework.run();
- })();
- })();