// ==UserScript==
// @name ZcxJames's hornex wave script
// @namespace tampermonkey.net/
// @version 2.4
// @description Fetch and display JSON data from zcxjames.top/data.json on the right side of the screen with grid lines, text color change based on time value, lighter font weight, and toggle visibility with Tab key
// @author ZcxJames
// @match https://hornex.pro/*
// @grant GM_xmlhttpRequest
// @connect zcxjames.top
// @connect 103.193.151.90
// @license GPL
// ==/UserScript==
(function() {
'use strict';
const scriptVersion = '2.4';
const regions = ['as1', 'as2', 'eu1', 'eu2', 'us1', 'us2'];
let tableVisible = true;
let previousServer = '';
let previousZone = '';
let currentServer = '';
let currentZone = '';
let progress = '';
const servers = {
'eu1': 'rgb(166, 56, 237)', 'eu2': 'rgb(81, 121, 251)', 'as1': 'rgb(237, 61, 234)', 'us1': 'rgb(219, 130, 41)', 'us2': 'rgb(237, 236, 61)', 'as2': 'rgb(61, 179, 203)'
};
const zones = {
'Ultra': 'rgb(255, 43, 117)', 'Super': 'rgb(43, 255, 163)', 'Hyper': 'rgb(92, 116, 176)', 'Waveroom': 'rgb(126, 239, 109)'
};
function createTable(jsonData) {
const existingTable = document.getElementById('jsonDataTable');
if (existingTable) existingTable.remove();
const table = document.createElement('table');
table.id = 'jsonDataTable';
table.style.cssText = `
position: fixed; top: 50%; right: 0; transform: translateY(-50%);
border: 1px solid black; background-color: transparent;
z-index: 1000; width: 200px; border-collapse: collapse; font-weight: lighter;
`;
table.innerHTML = `
<thead>
<tr><th style="border: 1px solid black;"> </th>
<th style="border: 1px solid black;">Super</th>
<th style="border: 1px solid black;">Hyper</th>
</tr>
</thead>
<tbody>
${regions.map(region => `
<tr>
<td style="border: 1px solid black;">${region}</td>
${['Super', 'Hyper'].map(type => {
const key = `${region}_${type}`;
const data = jsonData[key] || {};
const timeValue = data.time;
const progress = data.progress || 'N/A';
return `<td style="border: 1px solid black; color: ${timeValue ? 'orange' : 'black'};">${progress}</td>`;
}).join('')}
</tr>`).join('')}
</tbody>`;
document.body.appendChild(table);
table.style.display = tableVisible ? 'table' : 'none';
}
function fetchAndUpdateTable() {
GM_xmlhttpRequest({
method: 'GET',
url: 'https://zcxjames.top/data.json',
onload: response => createTable(JSON.parse(response.responseText))
});
}
function toggleTableVisibility(event) {
if (event.key === 'Tab') {
event.preventDefault();
tableVisible = !tableVisible;
const table = document.getElementById('jsonDataTable');
if (table) table.style.display = tableVisible ? 'table' : 'none';
}
}
function updateIndicator() {
currentServer = Object.keys(servers).find(server =>
document.querySelector(`div.btn.active[style="background-color: ${servers[server]};"]`)) || '';
currentZone = Object.keys(zones).find(zone =>
document.querySelector(`div.zone-name[stroke="${zone}"]`)) || '';
if (document.querySelector('div.zone-name[stroke="Waveroom"]')) currentZone = 'waveroom';
const waveSpan = document.querySelector('body > div.hud > div.zone > div.progress > span[stroke]');
const waveText = waveSpan ? waveSpan.getAttribute('stroke') : '';
const waveMatch = waveText.match(/Wave (\d+)/i);
progress = waveMatch ? 'Wave ' + waveMatch[1] : '0%';
document.querySelectorAll('div.bar').forEach(bar => {
const matches = bar.style.transform.match(/translate\(calc\(-(\d+(\.\d+)?)% \+ \d+(\.\d+)?em\), 0px\)/);
if (matches && matches[1]) {
const tempProgress = (100 - parseFloat(matches[1])).toFixed(4);
if (parseFloat(tempProgress) > parseFloat(progress)) progress = tempProgress + '%';
}
});
document.getElementById('indicator').textContent = `${currentServer || 'Server not detected'} - ${currentZone || 'Zone not detected'} - Progress: ${progress}`;
}
function sendPost() {
if (document.hidden) {
return;
}
if (currentServer !== previousServer || currentZone !== previousZone) {
previousServer = currentServer;
previousZone = currentZone;
return;
}
const data = { server: currentServer, zone: currentZone, progress: progress };
GM_xmlhttpRequest({
method: "POST",
url: "http://103.193.151.90:5000",
data: JSON.stringify(data),
headers: { "Content-Type": "application/json" }
});
}
function setupIndicator() {
const indicator = document.createElement('div');
indicator.id = 'indicator';
indicator.style.cssText = 'position: fixed; bottom: 20px; right: 0; background-color: transparent; padding: 10px; z-index: 10000;';
document.body.appendChild(indicator);
}
function checkVersion() {
GM_xmlhttpRequest({
method: 'GET',
url: 'https://zcxjames.top/version.json',
onload: response => {
const remoteVersion = JSON.parse(response.responseText).version;
if (remoteVersion !== scriptVersion) {
displayVersionWarning();
}
}
});
}
function displayVersionWarning() {
const warningDiv = document.createElement('div');
warningDiv.id = 'versionWarning';
warningDiv.style.cssText = 'position: fixed; bottom: 0; right: 0; background-color: red; color: white; padding: 10px; z-index: 10000; font-weight: bold; text-align: center;';
warningDiv.innerHTML = 'The script has a new version.<br>Please update your script at<br><a href="https://github.com/ZcxJames/hornex-wave-script/releases" style="color: white;">https://github.com/ZcxJames/hornex-wave-script/releases</a>';
document.body.appendChild(warningDiv);
}
document.addEventListener('keydown', toggleTableVisibility);
setInterval(fetchAndUpdateTable, 1000);
setInterval(sendPost, 1000);
setupIndicator();
checkVersion();
const observerConfig = { attributes: true, subtree: true, attributeFilter: ['style', 'class'] };
const observer = new MutationObserver(updateIndicator);
const hudZone = document.querySelector('body > div.hud > div.zone');
if (hudZone) {
observer.observe(hudZone.querySelector('div.zone-name'), observerConfig);
observer.observe(hudZone.querySelector('div.progress > div'), observerConfig);
observer.observe(hudZone.querySelector('div.progress > span'), observerConfig);
}
observer.observe(document.querySelector('body > div.menu'), observerConfig);
(function animate() {
updateIndicator();
requestAnimationFrame(animate);
})();
})();