// ==UserScript==
// @name Glxy Client
// @author Chpsterz
// @description Survev.io multipurpose client
// @version 0.0.6
// @match *://survev.io/*
// @match http://66.179.254.36/*
// @run-at document-start
// @grant none
// @license MIT
// @namespace https://greasyfork.org/users/1411859
// ==/UserScript==
class GameMod {
constructor() {
this.lastFrameTime = performance.now();
this.frameCount = 0;
this.fps = 0;
this.kills = 0;
this.isFpsUncapped = this.getFpsUncappedFromLocalStorage();
this.isFpsVisible = true;
this.isPingVisible = true;
this.isKillsVisible = true;
this.isMenuVisible = true;
this.pingCounter = null;
this.initPingCounter();
this.setAnimationFrameCallback();
this.initFpsCounter();
this.initKillsCounter();
this.initMenu();
this.loadBackgroundFromLocalStorage();
this.loadLocalStorage();
this.startUpdateLoop();
this.setupWeaponBorderHandler();
this.setupKeyListeners();
}
setAnimationFrameCallback() {
this.animationFrameCallback = this.isFpsUncapped
? (callback) => setTimeout(callback, 1)
: window.requestAnimationFrame.bind(window);
}
initFpsCounter() {
this.fpsCounter = document.createElement("div");
this.fpsCounter.id = "fpsCounter";
Object.assign(this.fpsCounter.style, {
color: "white",
backgroundColor: "rgba(0, 0, 0, 0.2)",
padding: "5px 10px",
marginTop: "10px",
borderRadius: "5px",
fontFamily: "Arial, sans-serif",
fontSize: "14px",
zIndex: "10000",
pointerEvents: "none",
});
const uiTopLeft = document.getElementById("ui-top-left");
if (uiTopLeft) {
uiTopLeft.appendChild(this.fpsCounter);
}
this.updateFpsVisibility();
}
initPingCounter() {
this.pingCounter = document.createElement("div");
this.pingCounter.id = "pingCounter";
Object.assign(this.pingCounter.style, {
color: "white",
backgroundColor: "rgba(0, 0, 0, 0.2)",
padding: "5px 10px",
marginTop: "10px",
borderRadius: "5px",
fontFamily: "Arial, sans-serif",
fontSize: "14px",
zIndex: "10000",
pointerEvents: "none",
});
const uiTopLeft = document.getElementById("ui-top-left");
if (uiTopLeft) {
uiTopLeft.appendChild(this.pingCounter);
}
this.updatePingVisibility();
}
initKillsCounter() {
this.killsCounter = document.createElement("div");
this.killsCounter.id = "killsCounter";
Object.assign(this.killsCounter.style, {
color: "white",
backgroundColor: "rgba(0, 0, 0, 0.2)",
padding: "5px 10px",
marginTop: "10px",
borderRadius: "5px",
fontFamily: "Arial, sans-serif",
fontSize: "14px",
zIndex: "10000",
pointerEvents: "none",
});
const uiTopLeft = document.getElementById("ui-top-left");
if (uiTopLeft) {
uiTopLeft.appendChild(this.killsCounter);
}
this.updateKillsVisibility();
}
updateFpsVisibility() {
if (this.fpsCounter) {
this.fpsCounter.style.display = this.isFpsVisible ? "block" : "none";
this.fpsCounter.style.backgroundColor = this.isFpsVisible
? "rgba(0, 0, 0, 0.2)"
: "transparent";
}
}
updatePingVisibility() {
if (this.pingCounter) {
this.pingCounter.style.display = this.isPingVisible ? "block" : "none";
}
}
updateKillsVisibility() {
if (this.killsCounter) {
this.killsCounter.style.display = this.isKillsVisible ? "block" : "none";
this.killsCounter.style.backgroundColor = this.isKillsVisible
? "rgba(0, 0, 0, 0.2)"
: "transparent";
}
}
toggleFpsDisplay() {
this.isFpsVisible = !this.isFpsVisible;
this.updateFpsVisibility();
}
togglePingDisplay() {
this.isPingVisible = !this.isPingVisible;
this.updatePingVisibility();
}
toggleKillsDisplay() {
this.isKillsVisible = !this.isKillsVisible;
this.updateKillsVisibility();
}
getKills() {
const killElement = document.querySelector(
".ui-player-kills.js-ui-player-kills",
);
if (killElement) {
const kills = parseInt(killElement.textContent, 10);
return isNaN(kills) ? 0 : kills;
}
return 0;
}
getRegionFromLocalStorage() {
let config = localStorage.getItem("surviv_config");
if (config) {
let configObject = JSON.parse(config);
return configObject.region;
}
return null;
}
startPingTest() {
const currentUrl = window.location.href;
const isSpecialUrl = /\/#\w+/.test(currentUrl);
const teamSelectElement = document.getElementById("team-server-select");
const mainSelectElement = document.getElementById("server-select-main");
const region =
isSpecialUrl && teamSelectElement
? teamSelectElement.value
: mainSelectElement
? mainSelectElement.value
: null;
if (region && region !== this.currentServer) {
this.currentServer = region;
this.resetPing();
const servers = [
{ region: "NA", url: "usr.mathsiscoolfun.com:8001" },
{ region: "EU", url: "eur.mathsiscoolfun.com:8001" },
{ region: "Asia", url: "asr.mathsiscoolfun.com:8001" },
{ region: "SA", url: "sa.mathsiscoolfun.com:8001" },
];
const selectedServer = servers.find(
(server) => region.toUpperCase() === server.region.toUpperCase(),
);
if (selectedServer) {
this.pingTest = new PingTest(selectedServer);
this.pingTest.startPingTest();
} else {
this.resetPing();
}
}
}
resetPing() {
if (this.pingTest && this.pingTest.test.ws) {
this.pingTest.test.ws.close();
this.pingTest.test.ws = null;
}
this.pingTest = null;
}
getFpsUncappedFromLocalStorage() {
const savedConfig = localStorage.getItem("userSettings");
if (savedConfig) {
const configObject = JSON.parse(savedConfig);
return configObject.isFpsUncapped || false;
}
return false;
}
saveFpsUncappedToLocalStorage() {
let config = JSON.parse(localStorage.getItem("userSettings")) || {};
config.isFpsUncapped = this.isFpsUncapped;
localStorage.setItem("userSettings", JSON.stringify(config));
}
saveBackgroundToLocalStorage(url) {
localStorage.setItem("lastBackgroundUrl", url);
}
saveBackgroundToLocalStorage(image) {
if (typeof image === "string") {
localStorage.setItem("lastBackgroundType", "url");
localStorage.setItem("lastBackgroundValue", image);
} else {
localStorage.setItem("lastBackgroundType", "local");
const reader = new FileReader();
reader.onload = () => {
localStorage.setItem("lastBackgroundValue", reader.result);
};
reader.readAsDataURL(image);
}
}
loadBackgroundFromLocalStorage() {
const backgroundType = localStorage.getItem("lastBackgroundType");
const backgroundValue = localStorage.getItem("lastBackgroundValue");
const backgroundElement = document.getElementById("background");
if (backgroundElement && backgroundType && backgroundValue) {
if (backgroundType === "url") {
backgroundElement.style.backgroundImage = `url(${backgroundValue})`;
} else if (backgroundType === "local") {
backgroundElement.style.backgroundImage = `url(${backgroundValue})`;
}
}
}
toggleFpsUncap() {
this.isFpsUncapped = !this.isFpsUncapped;
this.setAnimationFrameCallback();
this.saveFpsUncappedToLocalStorage();
}
updateHealthBars() {
const healthBars = document.querySelectorAll("#ui-health-container");
healthBars.forEach((container) => {
const bar = container.querySelector("#ui-health-actual");
if (bar) {
const width = Math.round(parseFloat(bar.style.width));
let percentageText = container.querySelector(".health-text");
if (!percentageText) {
percentageText = document.createElement("span");
percentageText.classList.add("health-text");
Object.assign(percentageText.style, {
width: "100%",
textAlign: "center",
marginTop: "5px",
color: "#333",
fontSize: "20px",
fontWeight: "bold",
position: "absolute",
zIndex: "10",
});
container.appendChild(percentageText);
}
percentageText.textContent = `${width}%`;
}
});
}
updateBoostBars() {
const boostCounter = document.querySelector("#ui-boost-counter");
if (boostCounter) {
const boostBars = boostCounter.querySelectorAll(
".ui-boost-base .ui-bar-inner",
);
let totalBoost = 0;
const weights = [25, 25, 40, 10];
boostBars.forEach((bar, index) => {
const width = parseFloat(bar.style.width);
if (!isNaN(width)) {
totalBoost += width * (weights[index] / 100);
}
});
const averageBoost = Math.round(totalBoost);
let boostDisplay = boostCounter.querySelector(".boost-display");
if (!boostDisplay) {
boostDisplay = document.createElement("div");
boostDisplay.classList.add("boost-display");
Object.assign(boostDisplay.style, {
position: "absolute",
bottom: "75px",
right: "335px",
color: "#FF901A",
backgroundColor: "rgba(0, 0, 0, 0.4)",
padding: "5px 10px",
borderRadius: "5px",
fontFamily: "Arial, sans-serif",
fontSize: "14px",
zIndex: "10",
textAlign: "center",
});
boostCounter.appendChild(boostDisplay);
}
boostDisplay.textContent = `AD: ${averageBoost}%`;
}
}
setupWeaponBorderHandler() {
const weaponContainers = Array.from(
document.getElementsByClassName("ui-weapon-switch"),
);
weaponContainers.forEach((container) => {
if (container.id === "ui-weapon-id-4") {
container.style.border = "3px solid #2f4032";
} else {
container.style.border = "3px solid #FFFFFF";
}
});
const weaponNames = Array.from(
document.getElementsByClassName("ui-weapon-name"),
);
weaponNames.forEach((weaponNameElement) => {
const weaponContainer = weaponNameElement.closest(".ui-weapon-switch");
const observer = new MutationObserver(() => {
const weaponName = weaponNameElement.textContent.trim();
let border = "#FFFFFF";
switch (weaponName.toUpperCase()) {
case "CZ-3A1":
case "G18C":
case "M9":
case "M93R":
case "MAC-10":
case "MP5":
case "P30L":
case "DUAL P30L":
case "UMP9":
case "VECTOR":
case "VSS":
case "FLAMETHROWER":
border = "#FFAE00";
break;
case "AK-47":
case "OT-38":
case "OTS-38":
case "M39 EMR":
case "DP-28":
case "MOSIN-NAGANT":
case "SCAR-H":
case "SV-98":
case "M1 GARAND":
case "PKP PECHENEG":
case "AN-94":
case "BAR M1918":
case "BLR 81":
case "SVD-63":
case "M134":
case "WATER GUN":
border = "#007FFF";
break;
case "FAMAS":
case "M416":
case "M249":
case "QBB-97":
case "MK 12 SPR":
case "M4A1-S":
case "SCOUT ELITE":
case "L86A2":
border = "#0f690d";
break;
case "M870":
case "MP220":
case "SAIGA-12":
case "SPAS-12":
case "USAS-12":
case "SUPER 90":
case "LASR GUN":
case "M1100":
border = "#FF0000";
break;
case "DEAGLE 50":
case "RAINBOW BLASTER":
border = "#000000";
break;
case "AWM-S":
case "MK 20 SSR":
border = "#808000";
break;
case "FLARE GUN":
border = "#FF4500";
break;
case "MODEL 94":
case "PEACEMAKER":
case "VECTOR (.45 ACP)":
case "M1911":
case "M1A1":
border = "#800080";
break;
case "M79":
border = "#008080";
break;
case "POTATO CANNON":
case "SPUD GUN":
border = "#A52A2A";
break;
case "HEART CANNON":
border = "#FFC0CB";
break;
default:
border = "#FFFFFF";
break;
}
if (weaponContainer.id !== "ui-weapon-id-4") {
weaponContainer.style.border = `3px solid ${border}`;
}
});
observer.observe(weaponNameElement, {
childList: true,
characterData: true,
subtree: true,
});
});
}
updateUiElements() {
const currentUrl = window.location.href;
const isSpecialUrl = /\/#\w+/.test(currentUrl);
const playerOptions = document.getElementById("player-options");
const teamMenuContents = document.getElementById("team-menu-contents");
const startMenuContainer = document.querySelector(
"#start-menu .play-button-container",
);
if (!playerOptions) return;
if (
isSpecialUrl &&
teamMenuContents &&
playerOptions.parentNode !== teamMenuContents
) {
teamMenuContents.appendChild(playerOptions);
} else if (
!isSpecialUrl &&
startMenuContainer &&
playerOptions.parentNode !== startMenuContainer
) {
const firstChild = startMenuContainer.firstChild;
startMenuContainer.insertBefore(playerOptions, firstChild);
}
const teamMenu = document.getElementById("team-menu");
if (teamMenu) {
teamMenu.style.height = "355px";
}
const menuBlocks = document.querySelectorAll(".menu-block");
menuBlocks.forEach((block) => {
block.style.maxHeight = "355px";
});
//scalable?
}
updateMenuButtonText() {
const hideButton = document.getElementById("hideMenuButton");
hideButton.textContent = this.isMenuVisible
? "Hide Menu [P]"
: "Show Menu [P]";
}
setupKeyListeners() {
document.addEventListener("keydown", (event) => {
if (event.key.toLowerCase() === "p") {
this.toggleMenuVisibility();
}
});
}
//menu
initMenu() {
const menu = document.createElement("div");
menu.id = "menu";
Object.assign(menu.style, {
backgroundColor: "rgba(0, 0, 0, 0.8)",
padding: "15px",
marginLeft: "15px",
borderRadius: "10px",
boxShadow: "0 4px 10px rgba(0, 0, 0, 0.6)",
zIndex: "10001",
width: "250px",
fontFamily: "Arial, sans-serif",
color: "#fff",
maxHeight: "400px",
overflowY: "auto",
});
const title = document.createElement("h2");
title.textContent = "Glxy Client";
title.style.margin = "0 0 10px";
title.style.textAlign = "center";
title.style.fontSize = "18px";
title.style.color = "#FFAE00";
menu.appendChild(title);
const updateLocalStorage = () => {
localStorage.setItem(
"userSettings",
JSON.stringify({
isFpsVisible: this.isFpsVisible,
isPingVisible: this.isPingVisible,
isFpsUncapped: this.isFpsUncapped,
isKillsVisible: this.isKillsVisible,
}),
);
};
this.loadLocalStorage();
const fpsToggle = document.createElement("button");
fpsToggle.textContent = `Show FPS ${this.isFpsVisible ? "✅" : "❌"}`;
Object.assign(fpsToggle.style, {
backgroundColor: this.isFpsVisible ? "#4CAF50" : "#FF0000",
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
fpsToggle.onclick = () => {
this.isFpsVisible = !this.isFpsVisible;
this.updateFpsVisibility();
fpsToggle.textContent = `Show FPS ${this.isFpsVisible ? "✅" : "❌"}`;
fpsToggle.style.backgroundColor = this.isFpsVisible
? "#4CAF50"
: "#FF0000";
updateLocalStorage();
};
menu.appendChild(fpsToggle);
const pingToggle = document.createElement("button");
pingToggle.textContent = `Show Ping ${this.isPingVisible ? "✅" : "❌"}`;
Object.assign(pingToggle.style, {
backgroundColor: this.isPingVisible ? "#4CAF50" : "#FF0000",
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
pingToggle.onclick = () => {
this.isPingVisible = !this.isPingVisible;
this.updatePingVisibility();
pingToggle.textContent = `Show Ping ${this.isPingVisible ? "✅" : "❌"}`;
pingToggle.style.backgroundColor = this.isPingVisible
? "#4CAF50"
: "#FF0000";
updateLocalStorage();
};
menu.appendChild(pingToggle);
const killsToggle = document.createElement("button");
killsToggle.textContent = `Show Kills ${this.isKillsVisible ? "✅" : "❌"}`;
Object.assign(killsToggle.style, {
backgroundColor: this.isKillsVisible ? "#4CAF50" : "#FF0000",
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
killsToggle.onclick = () => {
this.isKillsVisible = !this.isKillsVisible;
this.updateKillsVisibility();
killsToggle.textContent = `Show Kills ${this.isKillsVisible ? "✅" : "❌"}`;
killsToggle.style.backgroundColor = this.isKillsVisible
? "#4CAF50"
: "#FF0000";
updateLocalStorage();
};
menu.appendChild(killsToggle);
const uncapFpsToggle = document.createElement("button");
uncapFpsToggle.textContent = `Uncap FPS ${this.isFpsUncapped ? "✅" : "❌"}`;
Object.assign(uncapFpsToggle.style, {
backgroundColor: this.isFpsUncapped ? "#4CAF50" : "#FF0000",
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
uncapFpsToggle.onclick = () => {
this.toggleFpsUncap();
uncapFpsToggle.textContent = `Uncap FPS ${this.isFpsUncapped ? "✅" : "❌"}`;
uncapFpsToggle.style.backgroundColor = this.isFpsUncapped
? "#4CAF50"
: "#FF0000";
updateLocalStorage();
};
menu.appendChild(uncapFpsToggle);
const hideShowToggle = document.createElement("button");
hideShowToggle.textContent = `👀 Hide/Show Menu [P]`;
Object.assign(hideShowToggle.style, {
backgroundColor: "#6F42C1",
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
hideShowToggle.onclick = () => this.toggleMenuVisibility();
menu.appendChild(hideShowToggle);
const backgroundToggle = document.createElement("button");
backgroundToggle.textContent = `🎨 Change Background`;
Object.assign(backgroundToggle.style, {
backgroundColor: "#007BFF",
border: "none",
color: "#fff",
padding: "10px",
borderRadius: "5px",
width: "100%",
marginBottom: "10px",
fontSize: "14px",
cursor: "pointer",
});
backgroundToggle.onclick = () => {
const backgroundElement = document.getElementById("background");
if (!backgroundElement) {
alert("Element with id 'background' not found.");
return;
}
const choice = prompt(
"Enter '1' to provide a URL or '2' to upload a local image:",
);
if (choice === "1") {
const newBackgroundUrl = prompt(
"Enter the URL of the new background image:",
);
if (newBackgroundUrl) {
backgroundElement.style.backgroundImage = `url(${newBackgroundUrl})`;
this.saveBackgroundToLocalStorage(newBackgroundUrl);
alert("Background updated successfully!");
}
} else if (choice === "2") {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "image/*";
fileInput.onchange = (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
backgroundElement.style.backgroundImage = `url(${reader.result})`;
this.saveBackgroundToLocalStorage(file);
alert("Background updated successfully!");
};
reader.readAsDataURL(file);
}
};
fileInput.click();
}
};
menu.appendChild(backgroundToggle);
window.onload = () => {
const savedBackground = localStorage.getItem("backgroundImage");
if (savedBackground) {
const backgroundElement = document.getElementById("background");
if (backgroundElement) {
backgroundElement.style.backgroundImage = `url(${savedBackground})`;
}
}
};
const startRowTop = document.getElementById("start-row-top");
if (startRowTop) {
startRowTop.appendChild(menu);
}
this.menu = menu;
}
loadLocalStorage() {
const savedSettings = JSON.parse(localStorage.getItem("userSettings"));
if (savedSettings) {
this.isFpsVisible = savedSettings.isFpsVisible ?? this.isFpsVisible;
this.isPingVisible = savedSettings.isPingVisible ?? this.isPingVisible;
this.isFpsUncapped = savedSettings.isFpsUncapped ?? this.isFpsUncapped;
this.isKillsVisible = savedSettings.isKillsVisible ?? this.isKillsVisible;
}
this.updateKillsVisibility();
this.updateFpsVisibility();
this.updatePingVisibility();
}
toggleMenuVisibility() {
const isVisible = this.menu.style.display !== "none";
this.menu.style.display = isVisible ? "none" : "block";
}
startUpdateLoop() {
const now = performance.now();
const delta = now - this.lastFrameTime;
this.frameCount++;
if (delta >= 1000) {
this.fps = Math.round((this.frameCount * 1000) / delta);
this.frameCount = 0;
this.lastFrameTime = now;
this.kills = this.getKills();
if (this.isFpsVisible && this.fpsCounter) {
this.fpsCounter.textContent = `FPS: ${this.fps}`;
}
if (this.isKillsVisible && this.killsCounter) {
this.killsCounter.textContent = `Kills: ${this.kills}`;
}
if (this.isPingVisible && this.pingCounter && this.pingTest) {
const result = this.pingTest.getPingResult();
this.pingCounter.textContent = `PING: ${result.ping} ms`;
}
}
this.startPingTest();
this.animationFrameCallback(() => this.startUpdateLoop());
this.updateUiElements();
this.updateBoostBars();
this.updateHealthBars();
}
}
class PingTest {
constructor(selectedServer) {
this.ptcDataBuf = new ArrayBuffer(1);
this.test = {
region: selectedServer.region,
url: `wss://${selectedServer.url}/ptc`,
ping: 9999,
ws: null,
sendTime: 0,
retryCount: 0,
};
}
startPingTest() {
if (!this.test.ws) {
const ws = new WebSocket(this.test.url);
ws.binaryType = "arraybuffer";
ws.onopen = () => {
this.sendPing();
this.test.retryCount = 0;
};
ws.onmessage = () => {
const elapsed = (Date.now() - this.test.sendTime) / 1e3;
this.test.ping = Math.round(elapsed * 1000);
this.test.retryCount = 0;
setTimeout(() => this.sendPing(), 200);
};
ws.onerror = () => {
this.test.ping = "Error";
this.test.retryCount++;
if (this.test.retryCount < 5) {
setTimeout(() => this.startPingTest(), 2000);
} else {
this.test.ws.close();
this.test.ws = null;
}
};
ws.onclose = () => {
this.test.ws = null;
};
this.test.ws = ws;
}
}
sendPing() {
if (this.test.ws.readyState === WebSocket.OPEN) {
this.test.sendTime = Date.now();
this.test.ws.send(this.ptcDataBuf);
}
}
getPingResult() {
return {
region: this.test.region,
ping: this.test.ping,
};
}
}
const gameMod = new GameMod();