您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Find the fastest path in DFProfiler
当前为
// ==UserScript== // @name DFProfiler Path Finder // @namespace http://tampermonkey.net/ // @version 0.3 // @description Find the fastest path in DFProfiler // @author Runonstof // @match https://*.dfprofiler.com/bossmap // @match https://*.dfprofiler.com/profile/view/* // @icon https://www.google.com/s2/favicons?sz=64&domain=dfprofiler.com // @grant unsafeWindow // @license MIT // ==/UserScript== (function() { 'use strict'; // === Utility functions === function GM_addStyle(css) { var style = document.getElementById("GM_addStyleBy8626") || (function() { var style = document.createElement('style'); style.type = 'text/css'; style.id = "GM_addStyleBy8626"; document.head.appendChild(style); return style; })(); var sheet = style.sheet; sheet.insertRule(css, (sheet.rules || sheet.cssRules || []).length); } function GM_addStyle_object(selector, styles) { var css = selector + "{"; for (var key in styles) { css += key + ":" + styles[key] + ";"; } css += "}"; GM_addStyle(css); } function ready(fn) { if (document.readyState != 'loading'){ fn(); } else { document.addEventListener('DOMContentLoaded', fn); } } function AStar(emptyCells) { this.emptyCells == emptyCells || []; this.Node = function Node(x, y) { this.x = parseInt(x); this.y = parseInt(y); this.g = 0; // cost from start node this.h = 0; // heuristic (estimated cost to target) this.f = 0; // total cost (g + h) this.parent = null; this.withoutParent = function () { var node = new Node(this.x, this.y); node.g = this.g; node.h = this.h; node.f = this.f; return node; } } this.isInsideMap = function(x, y) { return x >= 1000 && x <= 1058 && y >= 981 && y <= 1035; }; this.isCellEmpty = function(x, y) { return emptyCells.some(function(cell) { return cell.x == x && cell.y == y; }); }; this.heuristic = function(node, target) { var dx = Math.abs(node.x - target.x); var dy = Math.abs(node.y - target.y); var diagonalSteps = Math.min(dx, dy); var straightSteps = Math.abs(dx - dy); return (1.2 * diagonalSteps) + straightSteps; } this.find = function(startPos, endPos) { var openList = []; var closedList = []; var startNode = new this.Node(startPos.x, startPos.y); var endNode = new this.Node(endPos.x, endPos.y); var diagonalCost = 1.2; var neighbors = [ { x: 1, y: 0 }, // Right { x: -1, y: 0 }, // Left { x: 0, y: 1 }, // Down { x: 0, y: -1 }, // Up { x: 1, y: 1 }, // Diagonal down-right { x: -1, y: -1 },// Diagonal up-left { x: 1, y: -1 }, // Diagonal up-right { x: -1, y: 1 }, // Diagonal down-left ]; openList.push(startNode); while (openList.length > 0) { var currentNode = openList[0]; var currentIndex = 0; for (var i = 1; i < openList.length; i++) { if (openList[i].f < currentNode.f) { currentNode = openList[i]; currentIndex = i; } } openList.splice(currentIndex, 1); closedList.push(currentNode); if (currentNode.x === endNode.x && currentNode.y === endNode.y) { var path = []; var current = currentNode; while (current !== null) { path.push(current.withoutParent()); current = current.parent; } return path.reverse(); } for (var neighbourIndex in neighbors) { var neighborDelta = neighbors[neighbourIndex]; var neighborX = currentNode.x + neighborDelta.x; var neighborY = currentNode.y + neighborDelta.y; if (!this.isInsideMap(neighborX, neighborY) || this.isCellEmpty(neighborX, neighborY)) { // console.log('cell is empty or outside map:', neighborX, neighborY); continue; } var neighborNode = new this.Node(neighborX, neighborY); var checkNeighbor = function(node) { return node.x === neighborX && node.y === neighborY; }; if (closedList.some(checkNeighbor)) { continue; } var movementCost = 1; if (neighborDelta.x != 0 && neighborDelta.y != 0) { movementCost = diagonalCost; } // movementCost = diagonalCost; // // // console.log('diagonal'); // // // movementCost = diagonalCost;= // // // This is a diagonal movement // // if (this.isCellEmpty(currentNode.x + neighborDelta.x, currentNode.y) || // // this.isCellEmpty(currentNode.x, currentNode.y + neighborDelta.y)) { // // // Increase diagonal cost if there is an adjacent empty cell // // movementCost = 1.50; // You can adjust this value based on your preference // // } else { // // movementCost = 1; // // } // } var tentativeG = currentNode.g + movementCost; // Assuming each step costs 1 if (!openList.some(checkNeighbor) || tentativeG < neighborNode.g) { neighborNode.g = tentativeG; neighborNode.h = this.heuristic(neighborNode, endNode); neighborNode.f = neighborNode.g + neighborNode.h; neighborNode.parent = currentNode; if (!openList.some(checkNeighbor)) { openList.push(neighborNode); } } } } // console.log(closedList); return null; // No path found } } // === CSS styles === GM_addStyle_object('#boss-data-section #mission-info, #bossmap-page #mission-info', { 'border-radius': '25px 25px 0 0', }); GM_addStyle_object('#boss-data-section #mission-info-distance-viewer, #bossmap-page #mission-info-distance-viewer', { 'position': 'absolute !important', 'background-color': 'hsla(0,0%,5%,.8)', 'border-radius': '0 0 25px 25px', 'padding': '5px', 'top': '770px', 'left': 'calc(50% - 16pt * 20)', 'right': 'calc(50% - 16pt * 20)', }); GM_addStyle_object('#boss-data-section #mission-info-buttons-title, #bossmap-page #mission-info-buttons-title', { 'color': 'white', 'font-size': '20px', }); // GM_addStyle_object('#boss-data-section #mission-info-buttons-subtitle, #bossmap-page #mission-info-buttons-subtitle', { // 'color': 'white', // 'font-size': '14px', // }); GM_addStyle_object('#boss-data-section button.mission-info-button, #bossmap-page button.mission-info-button', { 'background-color': 'gray', 'color': 'black', 'padding': '0.25em 0.5em', }); GM_addStyle_object('#boss-data-section button.mission-info-button:hover, #bossmap-page button.mission-info-button:hover', { 'color': 'white', }); GM_addStyle_object('#boss-data-section .dist-buttons, #bossmap-page .dist-buttons', { 'display': 'flex', 'gap': '10px', 'justify-content': 'center', 'margin-bottom': '10px', 'align-items': 'center', }); GM_addStyle_object('#boss-data-section td.coord.path, #bossmap-page td.coord.path', { 'background-color': 'yellow !important', 'color': 'black !important', }); // GM_addStyle_object('#coord-hover-tooltip', { // 'position': 'absolute', // 'background-color': 'hsla(0,0%,5%,.8)', // 'border-radius': '5px', // 'padding': '5px', // }); ready(function () { // === Create Elements === var missionHolder = document.getElementById('mission-holder'); var container = document.createElement('div'); container.id = 'mission-info-distance-viewer'; container.innerHTML = '<div id="mission-info-buttons-title">Path finder</div>'; container.innerHTML += '<div class="dist-buttons"><button id="dist-clear" style="display: none;" class="mission-info-button">Clear path</button></div>'; container.innerHTML += '<div class="dist-buttons"><button id="dist-set-start" class="mission-info-button">Set path start</button><button id="dist-set-end" class="mission-info-button">Set path end</button></div>'; container.innerHTML += '<div class="dist-buttons" style="display:none;">Player navigation: <button id="dist-set-goal" class="mission-info-button">Set path goal</button></div>'; missionHolder.appendChild(container); var mapTopInfo = document.createElement('div'); mapTopInfo.id = 'map-top-info'; mapTopInfo.innerHTML = '<div id="mission-info-buttons-subtitle">No path selected</div>'; var bossTable = document.querySelector('#boss-table'); if (bossTable.previousElementSibling) { bossTable.previousElementSibling.insertAdjacentElement('afterend', mapTopInfo); } else { bossTable.insertAdjacentElement('beforebegin', mapTopInfo); } // var tooltip = document.createElement('div'); // tooltip.id = 'coord-hover-tooltip'; // tooltip.style.display = 'none'; // unsafeWindow.document.body.appendChild(tooltip); // function showTooltip(event, info) { // tooltip.style.display = 'block'; // tooltip.style.position = 'absolute'; // // muose position // tooltip.style.top = event.pageY + 10 + 'px'; // tooltip.style.left = event.pageX + 10 + 'px'; // tooltip.innerHTML = info; // } // function hideTooltip() { // tooltip.style.display = 'none'; // } unsafeWindow.closeMissionHolder = function (event) { if (event.target.closest('#mission-info-distance-viewer')) return; missionHolder.style.display = 'none'; }; missionHolder.setAttribute('onclick', 'closeMissionHolder(event)'); var startCellButton = document.getElementById('dist-set-start'); var endCellButton = document.getElementById('dist-set-end'); var clearPathButton = document.getElementById('dist-clear'); var setGoalButton = document.getElementById('dist-set-goal'); var subtitle = document.getElementById('mission-info-buttons-subtitle'); // === Scan empty cells var emptyCells = Array.from(document.querySelectorAll('td.coord')) .filter(function (el) { return el.computedStyleMap().get('opacity').toString() == '0'; }) .map(function (el) { return { x: el.classList[1].replace('x', ''), y: el.classList[2].replace('y', ''), }; }); var startCell = null; var endCell = null; var trackingGps = false; var pathFinder = new AStar(emptyCells); function maybeUpdatePath() { if (!startCell || !endCell) return; var path = pathFinder.find(startCell, endCell); // Clear existing path cells var pathCells = unsafeWindow.document.querySelectorAll('td.coord.path'); for (var i = 0; i < pathCells.length; i++) { pathCells[i].classList.remove('path'); delete pathCells[i].dataset.distanceDebug; delete pathCells[i].dataset.distanceIndex; // pathCells[i].onmouseover = null; } // console.log(path); if (!path) return; for(var i = 0; i < path.length; i++) { var cellCoord = path[i]; // console.log(cellCoord); var cell = unsafeWindow.document.querySelector('td.coord.x' + cellCoord.x + '.y' + cellCoord.y); cell.classList.add('path'); cell.dataset.distanceDebug = JSON.stringify(cellCoord); cell.dataset.distanceIndex = i; // cell.onmouseover = function(event) { // if (!event.target.dataset.distanceDebug) return; // var info = JSON.parse(event.target.dataset.distanceDebug); // var index = parseInt(event.target.dataset.distanceIndex) + 1; // showTooltip(event, 'Index: ' + index + '<br>Cell: ' + info.x + 'x' + info.y + '<br>Total cost: ' + info.g + '<br>Heuristic: ' + info.h + '<br>Total: ' + info.f); // }; } clearPathButton.style.display = 'initial'; subtitle.innerHTML = 'Path length: ' + path.length + ' cells'; } var playerCoords = null; var playerCell = unsafeWindow.document.querySelector('td.playerlocation'); if (playerCell) { playerCoords = [ playerCell.classList[1].replace('x', ''), playerCell.classList[2].replace('y', ''), ]; } startCellButton.onclick = function () { // current pos var img = unsafeWindow.document.querySelector('#mission-info img'); var matches = img.src.match(/Fairview_(\d+)x(\d+)/); var x = matches[1]; var y = matches[2]; trackingGps = false; startCell = { x: x, y: y }; unsafeWindow.document.querySelector('td.coord.x' + x + '.y' + y).classList.add('path'); missionHolder.style.display = 'none'; maybeUpdatePath(); }; endCellButton.onclick = function () { // current pos var img = document.querySelector('#mission-info img'); var matches = img.src.match(/Fairview_(\d+)x(\d+)/); var x = matches[1]; var y = matches[2]; endCell = { x: x, y: y }; unsafeWindow.document.querySelector('td.coord.x' + x + '.y' + y).classList.add('path'); missionHolder.style.display = 'none'; maybeUpdatePath(); }; clearPathButton.onclick = function () { startCell = null; endCell = null; clearPathButton.style.display = 'none'; // Clear existing path cells var pathCells = unsafeWindow.document.querySelectorAll('td.coord.path'); for (var i = 0; i < pathCells.length; i++) { pathCells[i].classList.remove('path'); } subtitle.innerHTML = 'No path selected'; missionHolder.style.display = 'none'; }; var updatePlayerTrackPath = function () { if (!trackingGps) return; var playerCell = unsafeWindow.document.querySelector('td.playerlocation'); if (!playerCell) { setTimeout(updatePlayerTrackPath, 30000); return; }; playerCoords = [ playerCell.classList[1].replace('x', ''), playerCell.classList[2].replace('y', ''), ]; startCell = { x: playerCoords[0], y: playerCoords[1] }; maybeUpdatePath(); setTimeout(updatePlayerTrackPath, 30000); }; setGoalButton.onclick = function () { trackingGps = true; missionHolder.style.display = 'none'; // current pos var img = document.querySelector('#mission-info img'); var matches = img.src.match(/Fairview_(\d+)x(\d+)/); var x = matches[1]; var y = matches[2]; endCell = { x: x, y: y }; if (playerCoords) { startCell = { x: playerCoords[0], y: playerCoords[1] }; } unsafeWindow.document.querySelector('td.coord.x' + x + '.y' + y).classList.add('path'); maybeUpdatePath(); updatePlayerTrackPath(); }; $(unsafeWindow.document).ajaxComplete(function(event, jqXHR, ajaxOptions) { console.log('ajaxComplete', ajaxOptions.url) if (ajaxOptions.url.indexOf('/profile/json/') == -1) return; setGoalButton.parentElement.style.display = 'initial'; playerCoords = jqXHR.responseJSON.gpscoords; // if (!trackingGps) return; // startCell = { x: coords[0], y: coords[1] }; // maybeUpdatePath(); }); }); })();