9战

9战1

  1. // ==UserScript==
  2. // @name 9战
  3. // @namespace http://tampermonkey.net/
  4. // @version 2025-03-30
  5. // @description 9战1
  6. // @author You
  7. // @match https://www.milkywayidle.com/game*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16.  
  17.  
  18. class AutoFramework {
  19. static #isPaused = true;
  20. static #controlBar;
  21. static #func = null;
  22.  
  23. // 设置自动化函数
  24. static setFunc(f) {
  25. this.#func = f;
  26. }
  27.  
  28. // 初始化控制栏
  29. static initControlBar() {
  30. this.#controlBar = document.createElement('div');
  31. this.#controlBar.id = 'autoFrameworkControlBar';
  32. this.#controlBar.style = `
  33. position: fixed;
  34. top: 0;
  35. left: 50%;
  36. transform: translateX(-50%);
  37. padding: 10px 20px; /* 增加横向内边距 */
  38. background: rgba(0,0,0,0.7);
  39. color: white;
  40. border-radius: 8px; /* 添加圆角 */
  41. box-shadow: 0 2px 6px rgba(0,0,0,0.3); /* 添加阴影 */
  42. z-index: 99999;
  43. `;
  44.  
  45. const input = document.createElement('input');
  46. input.id = 'input-9-name'
  47. input.value = '沼泽星球'
  48.  
  49. const btn = document.createElement('button');
  50. btn.textContent = '开启9战';
  51. btn.style = `
  52. padding: 8px 16px;
  53. font-size: 16px;
  54. background: #f44336;
  55. color: white;
  56. border: none;
  57. cursor: pointer;
  58. border-radius: 4px;
  59. `;
  60. btn.addEventListener('click', () => this.togglePause());
  61. this.#controlBar.appendChild(input);
  62. this.#controlBar.appendChild(btn);
  63. document.body.appendChild(this.#controlBar);
  64. }
  65.  
  66. static togglePause() {
  67. this.#isPaused = !this.#isPaused;
  68. const btn = this.#controlBar.querySelector('button');
  69. btn.textContent = this.#isPaused ? '开启' : '暂停';
  70. btn.style.backgroundColor = this.#isPaused ? '#f44336' : '#4CAF50';
  71. }
  72.  
  73. static isPaused() {
  74. return this.#isPaused;
  75. }
  76.  
  77. static async run() {
  78. while (true) {
  79. if (!this.#isPaused && this.#func) {
  80. try {
  81. await this.#func();
  82. } catch (error) {
  83. console.error('执行出错:', error);
  84. }
  85. }
  86. await new Promise(resolve => setTimeout(resolve, 100));
  87. }
  88. }
  89.  
  90. static findElementsByText(text, options = {}) {
  91. const {
  92. exact = false, // 是否精确匹配
  93. selector = '*', // 初始选择器(缩小搜索范围)
  94. visible = true // 是否仅可见元素
  95. } = options;
  96.  
  97. const elements = document.querySelectorAll(selector);
  98. return Array.from(elements).filter(element => {
  99. if (visible && !this.isVisible(element)) return false;
  100. const content = element.textContent.trim();
  101. if (exact) return content === text;
  102. else return content.includes(text);
  103. });
  104. }
  105.  
  106. static findElementByText(text, options) {
  107. const elements = this.findElementsByText(text, options);
  108. return elements.length > 0 ? elements[0] : null;
  109. }
  110.  
  111. static clickElement(element) {
  112. if (element) {
  113. const event = new MouseEvent('click', {
  114. view: window,
  115. bubbles: true,
  116. cancelable: true
  117. });
  118. element.dispatchEvent(event);
  119. }
  120. }
  121.  
  122. static async waitForElement(selector, timeout = 5000) {
  123. return new Promise((resolve, reject) => {
  124. const interval = setInterval(() => {
  125. const element = document.querySelector(selector);
  126. if (element) {
  127. clearInterval(interval);
  128. resolve(element);
  129. } else if (timeout <= 0) {
  130. clearInterval(interval);
  131. reject('元素未找到');
  132. }
  133. timeout -= 100;
  134. }, 100);
  135. });
  136. }
  137.  
  138. static async waitForText(text, options = {}) {
  139. if (this.isPaused()) return Promise.reject('脚本已暂停');
  140. const { timeout = 5000, ...findOptions } = options;
  141. let timeout1 = timeout
  142. return new Promise((resolve, reject) => {
  143. const interval = setInterval(() => {
  144. const element = this.findElementByText(text, findOptions);
  145. if (element) {
  146. clearInterval(interval);
  147. resolve(element);
  148. } else if (timeout1 <= 0) {
  149. clearInterval(interval);
  150. reject(`文本 "${text}" 未找到`);
  151. }
  152. timeout1 -= 100;
  153. }, 100);
  154. });
  155. }
  156.  
  157. static isVisible(element) {
  158. return element.offsetWidth > 0 && element.offsetHeight > 0;
  159. }
  160.  
  161. static async clickByText(text, options = {}) {
  162. if (this.isPaused()) return;
  163. try {
  164. const element = await this.waitForText(text, options);
  165. this.clickElement(element);
  166. } catch (error) {
  167. console.error(`点击失败: ${error}`);
  168. }
  169. }
  170.  
  171. static async getTextByText(text, options = {}) {
  172. try {
  173. const element = await this.waitForText(text, options);
  174. return element.textContent.trim();
  175. } catch (error) {
  176. console.error(`获取文本失败: ${error}`);
  177. return null;
  178. }
  179. }
  180.  
  181. static findElementsByAttr(attrName, attrValue, options = {}) {
  182. const {
  183. exact = true, // 是否精确匹配(false为包含匹配)
  184. selector = '*', // 初始选择器
  185. visible = true // 是否仅可见元素
  186. } = options;
  187. const elements = document.querySelectorAll(selector);
  188.  
  189. return Array.from(elements).filter(element => {
  190. if (visible && !this.isVisible(element)) return false;
  191. const attr = element.getAttribute(attrName);
  192. if (!attr) return false;
  193.  
  194. if (exact) {
  195. return attr === attrValue;
  196. } else {
  197. return attr.includes(attrValue);
  198. }
  199. });
  200. }
  201.  
  202. static findElementByAttr(attrName, attrValue, options) {
  203. const elements = this.findElementsByAttr(attrName, attrValue, options);
  204. return elements.length > 0 ? elements[0] : null;
  205. }
  206.  
  207. static async waitForAttr(attrName, attrValue, options = {}) {
  208. if (this.isPaused()) return Promise.reject('脚本已暂停');
  209. const { timeout = 5000, ...findOptions } = options;
  210. let timeout1 = timeout
  211. return new Promise((resolve, reject) => {
  212. const interval = setInterval(() => {
  213. const element = this.findElementByAttr(attrName, attrValue, findOptions);
  214. if (element) {
  215. clearInterval(interval);
  216. resolve(element);
  217. } else if (timeout1 <= 0) {
  218. clearInterval(interval);
  219. reject(`属性匹配失败: ${attrName}=${attrValue}`);
  220. }
  221. timeout1 -= 100;
  222. }, 100);
  223. });
  224. }
  225.  
  226. static async clickByAttr(attrName, attrValue, options = {}) {
  227. if (this.isPaused()) return;
  228. try {
  229. const element = await this.waitForAttr(attrName, attrValue, options);
  230. this.clickElement(element);
  231. } catch (error) {
  232. console.error(`属性点击失败: ${error}`);
  233. }
  234. }
  235.  
  236.  
  237. static reactInputTriggerHack(inputElem, value) {
  238. let lastValue = inputElem.value;
  239. inputElem.value = value;
  240. let event = new Event("input", { bubbles: true });
  241. event.simulated = true;
  242. let tracker = inputElem._valueTracker;
  243. if (tracker) {
  244. tracker.setValue(lastValue);
  245. }
  246. inputElem.dispatchEvent(event);
  247. }
  248.  
  249. // 新增:根据class设置输入框值(支持React)
  250. static async setInputValueByClass(className, value, options = {}) {
  251. if (this.isPaused()) return;
  252. try {
  253. const element = await this.waitForAttr('class', className, {
  254. selector: 'input', // 仅限input元素
  255. exact: false,
  256. // 包含匹配
  257. ...options
  258. });
  259. if (!element) throw new Error(`未找到class${className}的input元素`);
  260.  
  261. this.reactInputTriggerHack(element, value);
  262. console.log(`设置输入值成功: ${className} -> ${value}`);
  263. } catch (error) {
  264. console.error('设置输入值失败:', error);
  265. }
  266. }
  267. }
  268.  
  269. async function actions() {
  270. const input = document.querySelector('#input-9-name').value
  271. if(!input){
  272. return
  273. }
  274. try {
  275. await AutoFramework.clickByText('战斗区域', {
  276. selector: 'button',
  277. timeout: 3000,
  278. exact: false //模糊 true 精确
  279. });
  280.  
  281. await AutoFramework.clickByText(input, {
  282. selector: 'button',
  283. timeout: 3000,
  284. exact: false
  285. });
  286.  
  287. await AutoFramework.clickByAttr('href', 'swamp_planet', {
  288. selector: 'use',
  289. exact: false,
  290. timeout: 3000,
  291. visible:false
  292. });
  293.  
  294. await AutoFramework.setInputValueByClass('Input_input__2-t98', 9, {
  295. timeout: 3000
  296. });
  297. await AutoFramework.clickByText('添加到队列', {
  298. selector: 'button',
  299. timeout: 3000,
  300. exact: false
  301. });
  302.  
  303. } catch (error) {
  304. console.error('自动化失败:', error);
  305. }
  306. }
  307.  
  308. // 启动脚本
  309. (async () => {
  310. AutoFramework.initControlBar();
  311. AutoFramework.setFunc(actions);
  312. AutoFramework.run();
  313. })();
  314. })();