替换API返回坐标(支持上传TXT坐标文件并持久化)

拦截接口返回数据,并将其中的 x,y 坐标替换为自定义坐标。支持上传 TXT 坐标文件并保存到 localStorage,刷新页面后依然有效

  1. // ==UserScript==
  2. // @name 替换API返回坐标(支持上传TXT坐标文件并持久化)
  3. // @namespace https://ff14risingstones.web.sdo.com/
  4. // @version 0.0.1
  5. // @description 拦截接口返回数据,并将其中的 x,y 坐标替换为自定义坐标。支持上传 TXT 坐标文件并保存到 localStorage,刷新页面后依然有效
  6. // @author Cindy-Master
  7. // @match https://ff14risingstones.web.sdo.com/*
  8. // @grant none
  9. // @run-at document-start
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. let customCoords = [];
  16. const STORAGE_KEY = "customCoords";
  17. function loadCoordsFromStorage() {
  18. const stored = localStorage.getItem(STORAGE_KEY);
  19. if (stored) {
  20. try {
  21. customCoords = JSON.parse(stored);
  22. } catch (e) {
  23. console.error("读取持久化坐标失败:", e);
  24. customCoords = [];
  25. }
  26. }
  27. }
  28. loadCoordsFromStorage();
  29.  
  30. function createUI() {
  31. const container = document.createElement("div");
  32. container.style.position = "fixed";
  33. container.style.top = "10px";
  34. container.style.right = "10px";
  35. container.style.zIndex = "9999";
  36. container.style.background = "rgba(255,255,255,0.9)";
  37. container.style.padding = "10px";
  38. container.style.border = "1px solid #ccc";
  39. container.style.fontSize = "12px";
  40. container.style.color = "#333";
  41. container.style.fontFamily = "Arial, sans-serif";
  42.  
  43. container.innerHTML = `
  44. <div style="margin-bottom:5px;">上传坐标文件(TXT):</div>
  45. <input type="file" id="coordsFile" accept=".txt">
  46. <div id="coordsStatus" style="margin-top:5px;color:#006600;"></div>
  47. <div style="margin-top:5px;">
  48. 格式示例:<br>
  49. Contour 1:<br>
  50. (110, 182)<br>
  51. <br>
  52. Contour 2:<br>
  53. (108, 181)
  54. </div>
  55. <br>
  56. GitHub:https://github.com/Cindy-Master/FFXIV-StoneDeathPos
  57. `;
  58. document.body.appendChild(container);
  59. updateStatus();
  60.  
  61. document.getElementById("coordsFile").addEventListener("change", handleFileSelect);
  62. }
  63.  
  64. function updateStatus() {
  65. const statusEl = document.getElementById("coordsStatus");
  66. if (statusEl) {
  67. statusEl.innerText = `当前加载坐标:${customCoords.length}个`;
  68. }
  69. }
  70.  
  71. function handleFileSelect(event) {
  72. const file = event.target.files[0];
  73. if (!file) return;
  74. const reader = new FileReader();
  75. reader.onload = function(e) {
  76. const text = e.target.result;
  77. parseCoords(text);
  78. };
  79. reader.readAsText(file);
  80. }
  81.  
  82. function parseCoords(text) {
  83. const lines = text.split(/\r?\n/);
  84. const coords = [];
  85. const regex = /^\(\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/;
  86. for (let line of lines) {
  87. line = line.trim();
  88. const match = line.match(regex);
  89. if (match) {
  90. coords.push({
  91. point_x: match[1],
  92. point_y: match[2]
  93. });
  94. }
  95. }
  96. customCoords = coords;
  97. // 保存到 localStorage
  98. localStorage.setItem(STORAGE_KEY, JSON.stringify(customCoords));
  99. updateStatus();
  100. console.log("上传并保存的坐标数据:", customCoords);
  101. }
  102.  
  103. window.addEventListener("DOMContentLoaded", createUI);
  104. const originalOpen = XMLHttpRequest.prototype.open;
  105. const originalSend = XMLHttpRequest.prototype.send;
  106.  
  107. XMLHttpRequest.prototype.open = function(method, url) {
  108. this._url = url;
  109. return originalOpen.apply(this, arguments);
  110. };
  111.  
  112. XMLHttpRequest.prototype.send = function() {
  113. if (this._url && this._url.includes("gaoNanDeadPoint5")) {
  114. this.addEventListener("readystatechange", function() {
  115. if (this.readyState === 4 && this.status === 200) {
  116. try {
  117. let dataObj = JSON.parse(this.responseText);
  118. if (customCoords.length > 0 && dataObj && Array.isArray(dataObj.data)) {
  119. dataObj.data = customCoords.map((coord, index) => {
  120. const origItem = dataObj.data[index] || {};
  121. return Object.assign({}, origItem, {
  122. point_x: coord.point_x,
  123. point_y: coord.point_y
  124. });
  125. });
  126. }
  127. Object.defineProperty(this, "response", {
  128. get: function() {
  129. return JSON.stringify(dataObj);
  130. }
  131. });
  132. Object.defineProperty(this, "responseText", {
  133. get: function() {
  134. return JSON.stringify(dataObj);
  135. }
  136. });
  137. } catch (err) {
  138. console.error("修改 API 返回数据失败:", err);
  139. }
  140. }
  141. });
  142. }
  143. return originalSend.apply(this, arguments);
  144. };
  145. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址