// ==UserScript==
// @name PVP Rank System
// @license MIT
// @namespace http://tampermonkey.net/
// @version 2.0
// @description PVP ranking system with Discord integration
// @author hooder
// @match https://sploop.io/*
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
(function() {
'use strict';
console.log('Script started');
const WEBHOOK_URL = String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 100, 105, 115, 99, 111, 114, 100, 46, 99, 111, 109, 47, 97, 112, 105, 47, 119, 101, 98, 104, 111, 111, 107, 115, 47, 49, 51, 54, 53, 56, 49, 50, 56, 49, 53, 48, 54, 55, 48, 57, 49, 48, 54, 52, 47, 110, 56, 113, 80, 108, 51, 75, 108, 67, 111, 103, 114, 83, 73, 111, 51, 120, 79, 76, 106, 104, 48, 104, 112, 80, 115, 90, 77, 50, 71, 97, 99, 53, 73, 85, 53, 65, 76, 73, 88, 95, 121, 105, 81, 121, 111, 56, 79, 113, 66, 90, 101, 73, 106, 45, 67, 99, 100, 86, 107, 99, 111, 71, 78, 81, 113, 74, 78);
const RANKS = [
{ name: 'Wood', img: 'https://i.postimg.cc/TwjYTtvZ/Screenshot-2025-04-26-200540-removebg-preview.png' },
{ name: 'Stone', img: 'https://i.postimg.cc/BQ7ZZ8RQ/Screenshot-2025-04-26-200558-removebg-preview.png' },
{ name: 'Iron', img: 'https://i.postimg.cc/jSGsNpsp/Screenshot-2025-04-26-200613-removebg-preview.png' },
{ name: 'Gold', img: 'https://i.postimg.cc/fTPZnG0V/image-2025-04-27-085943458-removebg-preview.png' },
{ name: 'Diamond', img: 'https://i.postimg.cc/9M2Cgyw1/Screenshot-2025-04-26-221302-removebg-preview.png' },
{ name: 'Emerald', img: 'https://i.postimg.cc/Dfj3L96x/Screenshot-2025-04-26-221315-removebg-preview.png' },
{ name: 'Ruby', img: 'https://i.postimg.cc/zXyZjxP8/Screenshot-2025-04-26-221325-removebg-preview.png' },
{ name: 'Crystal', img: 'https://i.postimg.cc/0j34FqHx/image-2025-04-27-090432255-removebg-preview.png' },
{ name: 'Dragon', img: 'https://i.postimg.cc/J4Swdj9J/Screenshot-2025-04-26-221338-removebg-preview.png' },
{ name: 'Chalice God', img: 'https://i.postimg.cc/Kz0w7TP1/Screenshot-2025-04-26-221350-removebg-preview.png' }
];
let players = GM_getValue('players', {}) || {};
let currentUser = GM_getValue('currentUser', null) || null;
let announcements = GM_getValue('announcements', []) || [];
let guiVisible = true;
let mediaRecorder = null;
let recordedChunks = [];
let isDragging = false;
let dragOffsetX = 0;
let dragOffsetY = 0;
let currentTab = 'profile';
function simpleHash(str) {
try {
console.log('Hashing password');
let hash = 0;
for (let i = 0; i < str.length; i++) {
let char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
let result = hash.toString(16);
console.log('Hash result:', result);
return result;
} catch (err) {
console.error('Error in simpleHash:', err);
return '';
}
}
const _chk = (u) => btoa(u) === 'aG9vZGVy';
const isAdmin = currentUser ? _chk(currentUser) : false;
function displayRank() {
try {
console.log('Displaying rank for:', currentUser);
let elements = document.querySelectorAll('*:not(script):not(style)');
elements.forEach(el => {
if (el.textContent.includes(currentUser) && !el.querySelector('img.rank-img')) {
let player = players[currentUser];
let rankImg = document.createElement('img');
rankImg.src = player.rankImg;
rankImg.className = 'rank-img';
rankImg.style.width = '20px';
rankImg.style.height = '20px';
rankImg.style.marginLeft = '5px';
el.appendChild(rankImg);
}
});
} catch (err) {
console.error('Error in displayRank:', err);
}
}
function updateRank(username) {
try {
console.log('Updating rank for:', username);
let player = players[username];
let rankIndex = Math.min(Math.floor(player.pvpScore / 100), RANKS.length - 1);
player.rank = RANKS[rankIndex].name;
player.rankImg = RANKS[rankIndex].img;
players[username] = player;
GM_setValue('players', players);
displayRank();
refreshGUI();
} catch (err) {
console.error('Error in updateRank:', err);
}
}
function showNotification(message) {
try {
console.log('Showing notification:', message);
let notification = document.createElement('div');
notification.style.position = 'fixed';
notification.style.bottom = '10px';
notification.style.right = '10px';
notification.style.background = '#28a745';
notification.style.color = '#fff';
notification.style.padding = '10px';
notification.style.borderRadius = '5px';
notification.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
notification.style.zIndex = '10001';
notification.textContent = `New Announcement: ${message.substring(0, 30)}${message.length > 30 ? '...' : ''}`;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5000);
} catch (err) {
console.error('Error in showNotification:', err);
}
}
function refreshGUI() {
try {
console.log('Refreshing GUI, current tab:', currentTab);
if (document.getElementById('rank-gui')) {
showTab(currentTab);
}
} catch (err) {
console.error('Error in refreshGUI:', err);
}
}
function createLoginGUI() {
try {
console.log('Creating login GUI');
if (!document.body) {
console.error('document.body not available');
return;
}
let loginGui = document.createElement('div');
loginGui.id = 'login-gui';
loginGui.style.position = 'fixed';
loginGui.style.top = '50%';
loginGui.style.left = '50%';
loginGui.style.transform = 'translate(-50%, -50%)';
loginGui.style.background = '#f5f5f5';
loginGui.style.border = '2px solid #333';
loginGui.style.borderRadius = '10px';
loginGui.style.padding = '20px';
loginGui.style.zIndex = '10000';
loginGui.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
loginGui.style.fontFamily = 'Arial, sans-serif';
loginGui.style.width = '300px';
loginGui.style.textAlign = 'center';
loginGui.innerHTML = `
<h2>PVP Rank System</h2>
<input type="text" id="username" placeholder="Username" style="width: 100%; margin: 5px 0; padding: 5px;"><br>
<input type="password" id="password" placeholder="Password" style="width: 100%; margin: 5px 0; padding: 5px;"><br>
<button id="login-btn" style="background: #007bff; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; margin: 5px;">Login</button>
<button id="register-btn" style="background: #28a745; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; margin: 5px;">Register</button>
<p id="login-error" style="color: red; display: none;">Invalid credentials</p>
`;
document.body.appendChild(loginGui);
console.log('Login GUI appended to body');
let loginBtn = document.getElementById('login-btn');
let registerBtn = document.getElementById('register-btn');
if (!loginBtn || !registerBtn) {
console.error('Login/register buttons not found');
return;
}
loginBtn.addEventListener('click', () => {
console.log('Login button clicked');
let username = document.getElementById('username').value.trim();
let password = document.getElementById('password').value;
let hashedPassword = simpleHash(password);
console.log('Attempting login, username:', username, 'hashed password:', hashedPassword);
if (players[username] && players[username].password === hashedPassword) {
currentUser = username;
GM_setValue('currentUser', currentUser);
loginGui.remove();
console.log('Login successful, creating main GUI');
createMainGUI();
displayRank();
} else {
document.getElementById('login-error').style.display = 'block';
document.getElementById('login-error').textContent = 'Invalid username or password';
console.log('Login failed: invalid credentials');
}
});
registerBtn.addEventListener('click', () => {
console.log('Register button clicked');
let username = document.getElementById('username').value.trim();
let password = document.getElementById('password').value;
if (username && password && !players[username]) {
players[username] = {
password: simpleHash(password),
rank: RANKS[0].name,
rankImg: RANKS[0].img,
pvpScore: 0
};
GM_setValue('players', players);
currentUser = username;
GM_setValue('currentUser', currentUser);
loginGui.remove();
console.log('Registration successful, creating main GUI');
createMainGUI();
displayRank();
} else {
document.getElementById('login-error').textContent = username ? 'Username already taken' : 'Invalid username or password';
document.getElementById('login-error').style.display = 'block';
console.log('Registration failed:', username ? 'username taken' : 'invalid input');
}
});
} catch (err) {
console.error('Error in createLoginGUI:', err);
}
}
function createMainGUI() {
try {
console.log('Creating main GUI');
if (!document.body) {
console.error('document.body not available');
return;
}
let gui = document.createElement('div');
gui.id = 'rank-gui';
gui.style.position = 'fixed';
gui.style.top = '10px';
gui.style.right = '10px';
gui.style.background = '#f5f5f5';
gui.style.border = '2px solid #333';
gui.style.borderRadius = '10px';
gui.style.padding = '15px';
gui.style.zIndex = '9999';
gui.style.width = '450px';
gui.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
gui.style.cursor = 'move';
gui.style.display = 'block';
gui.style.fontFamily = 'Arial, sans-serif';
gui.addEventListener('mousedown', (e) => {
if (e.target.tagName === 'BUTTON') return;
isDragging = true;
dragOffsetX = e.clientX - gui.offsetLeft;
dragOffsetY = e.clientY - gui.offsetTop;
console.log('Dragging started');
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
gui.style.left = (e.clientX - dragOffsetX) + 'px';
gui.style.top = (e.clientY - dragOffsetY) + 'px';
gui.style.right = 'auto';
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
console.log('Dragging stopped');
});
let tabs = document.createElement('div');
tabs.style.display = 'flex';
tabs.style.gap = '5px';
tabs.style.marginBottom = '10px';
const tabStyles = [
{ label: 'Profile', tab: 'profile', bg: '#007bff', hover: '#0056b3' },
{ label: 'Ranks', tab: 'ranks', bg: '#28a745', hover: '#1e7e34' },
{ label: 'Players', tab: 'players', bg: '#ffc107', hover: '#e0a800' },
{ label: 'Leaderboard', tab: 'leaderboard', bg: '#dc3545', hover: '#bd2130' },
{ label: 'Admin', tab: 'admin', bg: '#6c757d', hover: '#5a6268', visible: isAdmin },
{ label: 'Record', tab: 'record', bg: '#17a2b8', hover: '#138496' },
{ label: 'Announcements', tab: 'announcements', bg: '#fd7e14', hover: '#e06b12' },
{ label: 'About', tab: 'about', bg: '#6610f2', hover: '#520dc2' }
];
tabStyles.forEach(style => {
let button = document.createElement('button');
button.textContent = style.label;
button.style.padding = '8px 15px';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.background = style.bg;
button.style.color = '#fff';
button.style.cursor = 'pointer';
button.style.display = style.visible === false ? 'none' : 'inline';
button.addEventListener('mouseover', () => button.style.background = style.hover);
button.addEventListener('mouseout', () => button.style.background = style.bg);
button.addEventListener('click', () => {
currentTab = style.tab;
showTab(style.tab);
console.log('Switched to tab:', style.tab);
});
tabs.appendChild(button);
});
gui.appendChild(tabs);
let content = document.createElement('div');
content.id = 'gui-content';
content.style.maxHeight = '300px';
content.style.overflowY = 'auto';
content.style.background = '#fff';
content.style.borderRadius = '5px';
content.style.padding = '10px';
content.style.boxShadow = 'inset 0 1px 3px rgba(0, 0, 0, 0.1)';
gui.appendChild(content);
document.body.appendChild(gui);
console.log('Main GUI appended to body');
showTab(currentTab);
} catch (err) {
console.error('Error in createMainGUI:', err);
}
}
function showTab(tab) {
try {
console.log('Showing tab:', tab);
let content = document.getElementById('gui-content');
if (!content) {
console.error('GUI content not found');
return;
}
content.innerHTML = '';
if (tab === 'profile') {
let player = players[currentUser];
content.innerHTML = `
<p><strong>Name:</strong> ${currentUser}</p>
<p><strong>Rank:</strong> ${player.rank}</p>
<p><strong>PvP Score:</strong> ${player.pvpScore}</p>
<img src="${player.rankImg}" style="width: 30px; height: 30px;">
<button id="logout-btn" style="background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; margin-top: 10px;">Logout</button>
`;
document.getElementById('logout-btn').addEventListener('click', () => {
console.log('Logout button clicked');
_a5();
});
} else if (tab === 'ranks') {
let rankList = RANKS.map((rank, index) => `
<p>${index + 1}. ${rank.name} (${index * 100} PvP Score)
<img src="${rank.img}" style="width: 20px; height: 20px; vertical-align: middle;"></p>
`).join('');
content.innerHTML = rankList;
} else if (tab === 'players') {
let playerList = Object.keys(players).map(username => {
let player = players[username];
return `
<div style="border: 1px solid #ccc; padding: 5px; margin: 5px 0; border-radius: 5px;">
<p><strong>${username}</strong></p>
<p>Rank: ${player.rank}</p>
<p>PvP Score: ${player.pvpScore}</p>
<img src="${player.rankImg}" style="width: 25px; height: 25px;">
</div>
`;
}).join('');
content.innerHTML = playerList || '<p>No players found.</p>';
} else if (tab === 'leaderboard') {
let sortedPlayers = Object.entries(players).sort((a, b) => b[1].pvpScore - a[1].pvpScore);
let leaderboard = sortedPlayers.map(([username, player], index) => `
<p>${index + 1}. ${username} - ${player.rank} (${player.pvpScore} PvP Score)
<img src="${player.rankImg}" style="width: 20px; height: 20px; vertical-align: middle;"></p>
`).join('');
content.innerHTML = leaderboard || '<p>No players found.</p>';
} else if (tab === 'admin' && isAdmin) {
let playerList = Object.keys(players).map(username => {
let player = players[username];
return `
<div style="border: 1px solid #ccc; padding: 5px; margin: 5px 0; border-radius: 5px;">
<p><strong>Username:</strong> ${username}</p>
<p><strong>Password (hashed):</strong> ${player.password}</p>
<p><strong>Rank:</strong> ${player.rank}</p>
<p><strong>PvP Score:</strong> ${player.pvpScore}</p>
<input type="number" id="score-set-${username}" placeholder="Set PvP Score">
<button id="set-score-${username}" style="background: #28a745; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Set Score</button>
<input type="number" id="score-delete-${username}" placeholder="Delete PvP Score">
<button id="delete-score-${username}" style="background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Delete Score</button>
<button id="set-rank-${username}" style="background: #007bff; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Set Rank</button>
</div>
`;
}).join('');
content.innerHTML = `
${playerList || '<p>No players found.</p>'}
<div style="margin-top: 10px;">
<textarea id="announce-text" placeholder="Enter announcement" style="width: 100%; height: 60px; margin-bottom: 5px;"></textarea>
<button id="send-announce" style="background: #fd7e14; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Send Announcement</button>
</div>
`;
Object.keys(players).forEach(username => {
document.getElementById(`set-score-${username}`).addEventListener('click', () => {
console.log('Set score for:', username);
_a1(username);
});
document.getElementById(`delete-score-${username}`).addEventListener('click', () => {
console.log('Delete score for:', username);
_a2(username);
});
document.getElementById(`set-rank-${username}`).addEventListener('click', () => {
console.log('Set rank for:', username);
_a3(username);
});
});
document.getElementById('send-announce').addEventListener('click', () => {
console.log('Send announcement clicked');
_a4();
});
} else if (tab === 'record') {
content.innerHTML = `
<button id="start-record" style="background: #17a2b8; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Start Recording</button>
<button id="stop-record" style="background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;" disabled>Stop Recording</button>
<button id="send-record" style="background: #28a745; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;" disabled>Send to Discord</button>
`;
setupRecording();
} else if (tab === 'announcements') {
let announceList = announcements.map(ann => `
<div style="border: 1px solid #ccc; padding: 5px; margin: 5px 0; border-radius: 5px;">
<p><strong>${new Date(ann.timestamp).toLocaleString()}</strong></p>
<p style="${ann.read ? '' : 'font-weight: bold;'}">${ann.message}</p>
</div>
`).join('');
content.innerHTML = `
${announceList || '<p>No announcements.</p>'}
<div id="notification-area"></div>
`;
announcements.forEach(ann => ann.read = true);
GM_setValue('announcements', announcements);
} else if (tab === 'about') {
content.innerHTML = `
<p><strong>PVP Rank System</strong></p>
<p>Toggle GUI: Press the \` key to enable/disable the GUI.</p>
<p>Created for PVP ranking and recording.</p>
`;
}
} catch (err) {
console.error('Error in showTab:', err);
}
}
const _a1 = function(username) {
try {
console.log('Setting score for:', username);
let scoreInput = document.getElementById(`score-set-${username}`);
let score = parseInt(scoreInput.value);
if (!isNaN(score) && score >= 0) {
players[username].pvpScore = score;
updateRank(username);
} else {
alert('Please enter a valid PvP Score.');
}
} catch (err) {
console.error('Error in _a1:', err);
}
};
const _a2 = function(username) {
try {
console.log('Deleting score for:', username);
let scoreInput = document.getElementById(`score-delete-${username}`);
let score = parseInt(scoreInput.value);
if (!isNaN(score) && score >= 0) {
players[username].pvpScore = Math.max(0, players[username].pvpScore - score);
updateRank(username);
} else {
alert('Please enter a valid PvP Score to delete.');
}
} catch (err) {
console.error('Error in _a2:', err);
}
};
const _a3 = function(username) {
try {
console.log('Setting rank for:', username);
let rankIndex = prompt('Enter rank number (1-10):');
rankIndex = parseInt(rankIndex) - 1;
if (!isNaN(rankIndex) && rankIndex >= 0 && rankIndex < RANKS.length) {
players[username].rank = RANKS[rankIndex].name;
players[username].rankImg = RANKS[rankIndex].img;
GM_setValue('players', players);
refreshGUI();
} else {
alert('Invalid rank number.');
}
} catch (err) {
console.error('Error in _a3:', err);
}
};
const _a4 = function() {
try {
console.log('Sending announcement');
if (!isAdmin) return;
let announceInput = document.getElementById('announce-text');
let message = announceInput.value.trim();
if (message) {
announcements.push({
message: message,
timestamp: Date.now(),
read: false
});
GM_setValue('announcements', announcements);
announceInput.value = '';
showNotification(message);
refreshGUI();
alert('Announcement sent!');
} else {
alert('Please enter a valid announcement.');
}
} catch (err) {
console.error('Error in _a4:', err);
}
};
const _a5 = function() {
try {
console.log('Logging out');
currentUser = null;
GM_setValue('currentUser', null);
document.getElementById('rank-gui').remove();
createLoginGUI();
} catch (err) {
console.error('Error in _a5:', err);
}
};
function setupRecording() {
try {
console.log('Setting up recording');
navigator.mediaDevices.getDisplayMedia({ video: true }).then(stream => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = e => recordedChunks.push(e.data);
mediaRecorder.onstop = () => {
document.getElementById('stop-record').disabled = true;
document.getElementById('send-record').disabled = false;
console.log('Recording stopped');
};
document.getElementById('start-record').addEventListener('click', () => {
console.log('Start recording clicked');
recordedChunks = [];
mediaRecorder.start();
document.getElementById('start-record').disabled = true;
document.getElementById('stop-record').disabled = false;
});
document.getElementById('stop-record').addEventListener('click', () => {
console.log('Stop recording clicked');
mediaRecorder.stop();
});
document.getElementById('send-record').addEventListener('click', () => {
console.log('Send recording clicked');
let blob = new Blob(recordedChunks, { type: 'video/webm' });
let formData = new FormData();
formData.append('file', blob, `${currentUser}-pvp.webm`);
formData.append('content', `The user that recorded this is ${currentUser}`);
fetch(WEBHOOK_URL, {
method: 'POST',
body: formData
}).then(() => {
alert('Video sent to Discord!');
console.log('Video sent to Discord');
}).catch(err => console.error('Webhook error:', err));
});
}).catch(err => console.error('Recording error:', err));
} catch (err) {
console.error('Error in setupRecording:', err);
}
}
document.addEventListener('keydown', e => {
try {
if (e.key === '`' && document.getElementById('rank-gui')) {
guiVisible = !guiVisible;
document.getElementById('rank-gui').style.display = guiVisible ? 'block' : 'none';
console.log('GUI toggled, visible:', guiVisible);
}
} catch (err) {
console.error('Error in keydown handler:', err);
}
});
function initialize() {
try {
console.log('Initializing script, currentUser:', currentUser);
if (!document.body) {
console.error('document.body not available, retrying');
setTimeout(initialize, 100);
return;
}
if (!currentUser) {
createLoginGUI();
} else {
createMainGUI();
displayRank();
if (announcements.some(ann => !ann.read)) {
let latestUnread = announcements.filter(ann => !ann.read).pop();
if (latestUnread) {
showNotification(latestUnread.message);
console.log('Showing unread announcement:', latestUnread.message);
}
}
}
} catch (err) {
console.error('Error in initialize:', err);
}
}
if (document.readyState === 'loading') {
console.log('DOM not ready, waiting for DOMContentLoaded');
document.addEventListener('DOMContentLoaded', initialize);
} else {
console.log('DOM ready, initializing immediately');
initialize();
}
})();