-
-
Save logan-mcgee/83c0effe25741607ccfc73ca83335c59 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name RC TTools | |
// @namespace RC TTools | |
// @match https://www.rockwelltransport.com/home/ttools/biz* | |
// @grant GM_xmlhttpRequest | |
// @version 1.0 | |
// @author logan | |
// @downloadURL https://gist.github.com/sadboilogan/83c0effe25741607ccfc73ca83335c59/raw/ttools.user.js | |
// @description Extends TTools site | |
// ==/UserScript== | |
(async () => { | |
async function request(url) { | |
return new Promise(resolve => { | |
GM_xmlhttpRequest({ url: url, responseType: 'json', onload: (data) => resolve(data.response), onerror: () => resolve(false), ontimeout: () => resolve(false) }); | |
}); | |
} | |
async function runCommand(command, data) { | |
const res = await sendData('Runtime.evaluate', { | |
expression: `new Promise((resolve) => fetch("https://remote_connector/recvData", {method: "POST", body: '{"type": "${command}", "data": ${data ? JSON.stringify(data) : '""'} }' }).then((res) => res.text()).then((res) => resolve(res)))`, | |
contextId: mainScriptCtx, | |
awaitPromise: true | |
}); | |
return res; | |
} | |
let sendData; | |
let cdpId = 0; | |
let mainScriptCtx = null; | |
let isConnected = false; | |
//! MAIN CODE | |
const navbar = document.querySelector('div.navbar-nav'); | |
if (!navbar) return; | |
// ? hook the getJSON jQuery function so we can intercept the business request, saves us making our own request after | |
const jqueryJSON = $.getJSON; | |
$.getJSON = (url, cb) => { | |
if (url === './businesses.json') { | |
const oldCb = cb; | |
cb = (data) => { | |
console.log('[tt-remote] biz fetched, stored data'); | |
mainCode(data); | |
oldCb(data); | |
}; | |
} | |
return jqueryJSON(url, cb); | |
}; | |
const navbarInner = document.createElement('a'); | |
navbarInner.className = 'nav-link'; | |
navbar.appendChild(navbarInner); | |
const nuiState = await request('http://localhost:13172/json/list'); | |
if (!nuiState) { | |
navbarInner.innerHTML = 'TT-Remote: No response'; | |
return; | |
} | |
let wsUrl = nuiState.find((data) => data.title === 'CitizenFX root UI' && data.url === 'nui://game/ui/root.html').webSocketDebuggerUrl; | |
if (!wsUrl) { | |
navbarInner.innerHTML = 'TT-Remote: WS not found'; | |
return; | |
} | |
async function onScriptCtxSet() { | |
navbarInner.innerHTML = 'TT-Remote: Connected'; | |
isConnected = true; | |
} | |
const ws = new WebSocket(wsUrl); | |
await new Promise(resolve => ws.addEventListener('open', resolve, { once: true })); | |
sendData = (type, params) => { | |
const id = cdpId++; | |
ws.send(JSON.stringify({ | |
id, | |
method: type, | |
params: params ?? {} | |
})); | |
return new Promise(resolve => { | |
ws.addEventListener('message', ({ data }) => { | |
const response = JSON.parse(data); | |
if (response?.id === id) { | |
ws.removeEventListener('message', arguments.callee); | |
resolve(response); | |
} | |
}); | |
}); | |
}; | |
ws.addEventListener('message', ({ data: msgData }) => { | |
const response = JSON.parse(msgData); | |
if (response?.id) return; | |
if (response.method === 'Debugger.scriptParsed') { | |
if (response.params.url === 'nui://remote_connector/nui/main.js') { | |
mainScriptCtx = response.params.executionContextId; | |
onScriptCtxSet(); | |
} | |
} | |
}); | |
await sendData('Runtime.enable'); | |
await sendData('Debugger.enable'); | |
async function mainCode(businesses) { | |
// ? wait for the business timer to be "in the range" of what RC wants, that way we know exactly when the table is being populated | |
await new Promise(resolve => { | |
let timer = setInterval(() => { | |
if (localStorage.getItem('biz-time') && parseInt(localStorage.getItem('biz-time')) > Date.now() - (1 * 60000)) { | |
clearInterval(timer); | |
resolve(); | |
} | |
}, 200); | |
}); | |
await new Promise(resolve => setTimeout(resolve, 100)); | |
const table = $('#business-table').DataTable(); | |
table.rows().every(function (rowIdx, tableLoop, rowLoop) { | |
const data = this.data(); | |
const bizId = /href=".*biz=(.*?)"/g.exec(data[8])[1]; | |
const bizData = businesses.find((biz) => biz.id === bizId); | |
data[8] += `<button type="button" class="btn btn-primary" id="waypointButton" xPos="${bizData.position.x}" yPos="${bizData.position.y}" >Waypoint</button>`; | |
this.data(data); | |
}); | |
document.addEventListener('click', async (e) => { | |
if (e.target.id !== 'waypointButton') return; | |
const xPos = e.target.getAttribute('xPos'); | |
const yPos = e.target.getAttribute('yPos'); | |
await runCommand('setWaypoint', { x: parseFloat(xPos), y: parseFloat(yPos) }); | |
}); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment