PVP Rank System

PVP ranking system with Discord integration

  1. // ==UserScript==
  2. // @name PVP Rank System
  3. // @license MIT
  4. // @namespace http://tampermonkey.net/
  5. // @version 2.0
  6. // @description PVP ranking system with Discord integration
  7. // @author hooder
  8. // @match https://sploop.io/*
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. console.log('Script started');
  17.  
  18. 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);
  19.  
  20. const RANKS = [
  21. { name: 'Wood', img: 'https://i.postimg.cc/TwjYTtvZ/Screenshot-2025-04-26-200540-removebg-preview.png' },
  22. { name: 'Stone', img: 'https://i.postimg.cc/BQ7ZZ8RQ/Screenshot-2025-04-26-200558-removebg-preview.png' },
  23. { name: 'Iron', img: 'https://i.postimg.cc/jSGsNpsp/Screenshot-2025-04-26-200613-removebg-preview.png' },
  24. { name: 'Gold', img: 'https://i.postimg.cc/fTPZnG0V/image-2025-04-27-085943458-removebg-preview.png' },
  25. { name: 'Diamond', img: 'https://i.postimg.cc/9M2Cgyw1/Screenshot-2025-04-26-221302-removebg-preview.png' },
  26. { name: 'Emerald', img: 'https://i.postimg.cc/Dfj3L96x/Screenshot-2025-04-26-221315-removebg-preview.png' },
  27. { name: 'Ruby', img: 'https://i.postimg.cc/zXyZjxP8/Screenshot-2025-04-26-221325-removebg-preview.png' },
  28. { name: 'Crystal', img: 'https://i.postimg.cc/0j34FqHx/image-2025-04-27-090432255-removebg-preview.png' },
  29. { name: 'Dragon', img: 'https://i.postimg.cc/J4Swdj9J/Screenshot-2025-04-26-221338-removebg-preview.png' },
  30. { name: 'Chalice God', img: 'https://i.postimg.cc/Kz0w7TP1/Screenshot-2025-04-26-221350-removebg-preview.png' }
  31. ];
  32.  
  33. let players = GM_getValue('players', {}) || {};
  34. let currentUser = GM_getValue('currentUser', null) || null;
  35. let announcements = GM_getValue('announcements', []) || [];
  36. let guiVisible = true;
  37. let mediaRecorder = null;
  38. let recordedChunks = [];
  39. let isDragging = false;
  40. let dragOffsetX = 0;
  41. let dragOffsetY = 0;
  42. let currentTab = 'profile';
  43.  
  44. function simpleHash(str) {
  45. try {
  46. console.log('Hashing password');
  47. let hash = 0;
  48. for (let i = 0; i < str.length; i++) {
  49. let char = str.charCodeAt(i);
  50. hash = ((hash << 5) - hash) + char;
  51. hash = hash & hash;
  52. }
  53. let result = hash.toString(16);
  54. console.log('Hash result:', result);
  55. return result;
  56. } catch (err) {
  57. console.error('Error in simpleHash:', err);
  58. return '';
  59. }
  60. }
  61.  
  62. const _chk = (u) => btoa(u) === 'aG9vZGVy';
  63. const isAdmin = currentUser ? _chk(currentUser) : false;
  64.  
  65. function displayRank() {
  66. try {
  67. console.log('Displaying rank for:', currentUser);
  68. let elements = document.querySelectorAll('*:not(script):not(style)');
  69. elements.forEach(el => {
  70. if (el.textContent.includes(currentUser) && !el.querySelector('img.rank-img')) {
  71. let player = players[currentUser];
  72. let rankImg = document.createElement('img');
  73. rankImg.src = player.rankImg;
  74. rankImg.className = 'rank-img';
  75. rankImg.style.width = '20px';
  76. rankImg.style.height = '20px';
  77. rankImg.style.marginLeft = '5px';
  78. el.appendChild(rankImg);
  79. }
  80. });
  81. } catch (err) {
  82. console.error('Error in displayRank:', err);
  83. }
  84. }
  85.  
  86. function updateRank(username) {
  87. try {
  88. console.log('Updating rank for:', username);
  89. let player = players[username];
  90. let rankIndex = Math.min(Math.floor(player.pvpScore / 100), RANKS.length - 1);
  91. player.rank = RANKS[rankIndex].name;
  92. player.rankImg = RANKS[rankIndex].img;
  93. players[username] = player;
  94. GM_setValue('players', players);
  95. displayRank();
  96. refreshGUI();
  97. } catch (err) {
  98. console.error('Error in updateRank:', err);
  99. }
  100. }
  101.  
  102. function showNotification(message) {
  103. try {
  104. console.log('Showing notification:', message);
  105. let notification = document.createElement('div');
  106. notification.style.position = 'fixed';
  107. notification.style.bottom = '10px';
  108. notification.style.right = '10px';
  109. notification.style.background = '#28a745';
  110. notification.style.color = '#fff';
  111. notification.style.padding = '10px';
  112. notification.style.borderRadius = '5px';
  113. notification.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
  114. notification.style.zIndex = '10001';
  115. notification.textContent = `New Announcement: ${message.substring(0, 30)}${message.length > 30 ? '...' : ''}`;
  116. document.body.appendChild(notification);
  117. setTimeout(() => notification.remove(), 5000);
  118. } catch (err) {
  119. console.error('Error in showNotification:', err);
  120. }
  121. }
  122.  
  123. function refreshGUI() {
  124. try {
  125. console.log('Refreshing GUI, current tab:', currentTab);
  126. if (document.getElementById('rank-gui')) {
  127. showTab(currentTab);
  128. }
  129. } catch (err) {
  130. console.error('Error in refreshGUI:', err);
  131. }
  132. }
  133.  
  134. function createLoginGUI() {
  135. try {
  136. console.log('Creating login GUI');
  137. if (!document.body) {
  138. console.error('document.body not available');
  139. return;
  140. }
  141.  
  142. let loginGui = document.createElement('div');
  143. loginGui.id = 'login-gui';
  144. loginGui.style.position = 'fixed';
  145. loginGui.style.top = '50%';
  146. loginGui.style.left = '50%';
  147. loginGui.style.transform = 'translate(-50%, -50%)';
  148. loginGui.style.background = '#f5f5f5';
  149. loginGui.style.border = '2px solid #333';
  150. loginGui.style.borderRadius = '10px';
  151. loginGui.style.padding = '20px';
  152. loginGui.style.zIndex = '10000';
  153. loginGui.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
  154. loginGui.style.fontFamily = 'Arial, sans-serif';
  155. loginGui.style.width = '300px';
  156. loginGui.style.textAlign = 'center';
  157.  
  158. loginGui.innerHTML = `
  159. <h2>PVP Rank System</h2>
  160. <input type="text" id="username" placeholder="Username" style="width: 100%; margin: 5px 0; padding: 5px;"><br>
  161. <input type="password" id="password" placeholder="Password" style="width: 100%; margin: 5px 0; padding: 5px;"><br>
  162. <button id="login-btn" style="background: #007bff; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; margin: 5px;">Login</button>
  163. <button id="register-btn" style="background: #28a745; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; margin: 5px;">Register</button>
  164. <p id="login-error" style="color: red; display: none;">Invalid credentials</p>
  165. `;
  166.  
  167. document.body.appendChild(loginGui);
  168. console.log('Login GUI appended to body');
  169.  
  170. let loginBtn = document.getElementById('login-btn');
  171. let registerBtn = document.getElementById('register-btn');
  172.  
  173. if (!loginBtn || !registerBtn) {
  174. console.error('Login/register buttons not found');
  175. return;
  176. }
  177.  
  178. loginBtn.addEventListener('click', () => {
  179. console.log('Login button clicked');
  180. let username = document.getElementById('username').value.trim();
  181. let password = document.getElementById('password').value;
  182. let hashedPassword = simpleHash(password);
  183. console.log('Attempting login, username:', username, 'hashed password:', hashedPassword);
  184. if (players[username] && players[username].password === hashedPassword) {
  185. currentUser = username;
  186. GM_setValue('currentUser', currentUser);
  187. loginGui.remove();
  188. console.log('Login successful, creating main GUI');
  189. createMainGUI();
  190. displayRank();
  191. } else {
  192. document.getElementById('login-error').style.display = 'block';
  193. document.getElementById('login-error').textContent = 'Invalid username or password';
  194. console.log('Login failed: invalid credentials');
  195. }
  196. });
  197.  
  198. registerBtn.addEventListener('click', () => {
  199. console.log('Register button clicked');
  200. let username = document.getElementById('username').value.trim();
  201. let password = document.getElementById('password').value;
  202. if (username && password && !players[username]) {
  203. players[username] = {
  204. password: simpleHash(password),
  205. rank: RANKS[0].name,
  206. rankImg: RANKS[0].img,
  207. pvpScore: 0
  208. };
  209. GM_setValue('players', players);
  210. currentUser = username;
  211. GM_setValue('currentUser', currentUser);
  212. loginGui.remove();
  213. console.log('Registration successful, creating main GUI');
  214. createMainGUI();
  215. displayRank();
  216. } else {
  217. document.getElementById('login-error').textContent = username ? 'Username already taken' : 'Invalid username or password';
  218. document.getElementById('login-error').style.display = 'block';
  219. console.log('Registration failed:', username ? 'username taken' : 'invalid input');
  220. }
  221. });
  222. } catch (err) {
  223. console.error('Error in createLoginGUI:', err);
  224. }
  225. }
  226.  
  227. function createMainGUI() {
  228. try {
  229. console.log('Creating main GUI');
  230. if (!document.body) {
  231. console.error('document.body not available');
  232. return;
  233. }
  234.  
  235. let gui = document.createElement('div');
  236. gui.id = 'rank-gui';
  237. gui.style.position = 'fixed';
  238. gui.style.top = '10px';
  239. gui.style.right = '10px';
  240. gui.style.background = '#f5f5f5';
  241. gui.style.border = '2px solid #333';
  242. gui.style.borderRadius = '10px';
  243. gui.style.padding = '15px';
  244. gui.style.zIndex = '9999';
  245. gui.style.width = '450px';
  246. gui.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
  247. gui.style.cursor = 'move';
  248. gui.style.display = 'block';
  249. gui.style.fontFamily = 'Arial, sans-serif';
  250.  
  251. gui.addEventListener('mousedown', (e) => {
  252. if (e.target.tagName === 'BUTTON') return;
  253. isDragging = true;
  254. dragOffsetX = e.clientX - gui.offsetLeft;
  255. dragOffsetY = e.clientY - gui.offsetTop;
  256. console.log('Dragging started');
  257. });
  258.  
  259. document.addEventListener('mousemove', (e) => {
  260. if (isDragging) {
  261. gui.style.left = (e.clientX - dragOffsetX) + 'px';
  262. gui.style.top = (e.clientY - dragOffsetY) + 'px';
  263. gui.style.right = 'auto';
  264. }
  265. });
  266.  
  267. document.addEventListener('mouseup', () => {
  268. isDragging = false;
  269. console.log('Dragging stopped');
  270. });
  271.  
  272. let tabs = document.createElement('div');
  273. tabs.style.display = 'flex';
  274. tabs.style.gap = '5px';
  275. tabs.style.marginBottom = '10px';
  276.  
  277. const tabStyles = [
  278. { label: 'Profile', tab: 'profile', bg: '#007bff', hover: '#0056b3' },
  279. { label: 'Ranks', tab: 'ranks', bg: '#28a745', hover: '#1e7e34' },
  280. { label: 'Players', tab: 'players', bg: '#ffc107', hover: '#e0a800' },
  281. { label: 'Leaderboard', tab: 'leaderboard', bg: '#dc3545', hover: '#bd2130' },
  282. { label: 'Admin', tab: 'admin', bg: '#6c757d', hover: '#5a6268', visible: isAdmin },
  283. { label: 'Record', tab: 'record', bg: '#17a2b8', hover: '#138496' },
  284. { label: 'Announcements', tab: 'announcements', bg: '#fd7e14', hover: '#e06b12' },
  285. { label: 'About', tab: 'about', bg: '#6610f2', hover: '#520dc2' }
  286. ];
  287.  
  288. tabStyles.forEach(style => {
  289. let button = document.createElement('button');
  290. button.textContent = style.label;
  291. button.style.padding = '8px 15px';
  292. button.style.border = 'none';
  293. button.style.borderRadius = '5px';
  294. button.style.background = style.bg;
  295. button.style.color = '#fff';
  296. button.style.cursor = 'pointer';
  297. button.style.display = style.visible === false ? 'none' : 'inline';
  298. button.addEventListener('mouseover', () => button.style.background = style.hover);
  299. button.addEventListener('mouseout', () => button.style.background = style.bg);
  300. button.addEventListener('click', () => {
  301. currentTab = style.tab;
  302. showTab(style.tab);
  303. console.log('Switched to tab:', style.tab);
  304. });
  305. tabs.appendChild(button);
  306. });
  307.  
  308. gui.appendChild(tabs);
  309.  
  310. let content = document.createElement('div');
  311. content.id = 'gui-content';
  312. content.style.maxHeight = '300px';
  313. content.style.overflowY = 'auto';
  314. content.style.background = '#fff';
  315. content.style.borderRadius = '5px';
  316. content.style.padding = '10px';
  317. content.style.boxShadow = 'inset 0 1px 3px rgba(0, 0, 0, 0.1)';
  318. gui.appendChild(content);
  319.  
  320. document.body.appendChild(gui);
  321. console.log('Main GUI appended to body');
  322. showTab(currentTab);
  323. } catch (err) {
  324. console.error('Error in createMainGUI:', err);
  325. }
  326. }
  327.  
  328. function showTab(tab) {
  329. try {
  330. console.log('Showing tab:', tab);
  331. let content = document.getElementById('gui-content');
  332. if (!content) {
  333. console.error('GUI content not found');
  334. return;
  335. }
  336. content.innerHTML = '';
  337.  
  338. if (tab === 'profile') {
  339. let player = players[currentUser];
  340. content.innerHTML = `
  341. <p><strong>Name:</strong> ${currentUser}</p>
  342. <p><strong>Rank:</strong> ${player.rank}</p>
  343. <p><strong>PvP Score:</strong> ${player.pvpScore}</p>
  344. <img src="${player.rankImg}" style="width: 30px; height: 30px;">
  345. <button id="logout-btn" style="background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 3px; margin-top: 10px;">Logout</button>
  346. `;
  347. document.getElementById('logout-btn').addEventListener('click', () => {
  348. console.log('Logout button clicked');
  349. _a5();
  350. });
  351. } else if (tab === 'ranks') {
  352. let rankList = RANKS.map((rank, index) => `
  353. <p>${index + 1}. ${rank.name} (${index * 100} PvP Score)
  354. <img src="${rank.img}" style="width: 20px; height: 20px; vertical-align: middle;"></p>
  355. `).join('');
  356. content.innerHTML = rankList;
  357. } else if (tab === 'players') {
  358. let playerList = Object.keys(players).map(username => {
  359. let player = players[username];
  360. return `
  361. <div style="border: 1px solid #ccc; padding: 5px; margin: 5px 0; border-radius: 5px;">
  362. <p><strong>${username}</strong></p>
  363. <p>Rank: ${player.rank}</p>
  364. <p>PvP Score: ${player.pvpScore}</p>
  365. <img src="${player.rankImg}" style="width: 25px; height: 25px;">
  366. </div>
  367. `;
  368. }).join('');
  369. content.innerHTML = playerList || '<p>No players found.</p>';
  370. } else if (tab === 'leaderboard') {
  371. let sortedPlayers = Object.entries(players).sort((a, b) => b[1].pvpScore - a[1].pvpScore);
  372. let leaderboard = sortedPlayers.map(([username, player], index) => `
  373. <p>${index + 1}. ${username} - ${player.rank} (${player.pvpScore} PvP Score)
  374. <img src="${player.rankImg}" style="width: 20px; height: 20px; vertical-align: middle;"></p>
  375. `).join('');
  376. content.innerHTML = leaderboard || '<p>No players found.</p>';
  377. } else if (tab === 'admin' && isAdmin) {
  378. let playerList = Object.keys(players).map(username => {
  379. let player = players[username];
  380. return `
  381. <div style="border: 1px solid #ccc; padding: 5px; margin: 5px 0; border-radius: 5px;">
  382. <p><strong>Username:</strong> ${username}</p>
  383. <p><strong>Password (hashed):</strong> ${player.password}</p>
  384. <p><strong>Rank:</strong> ${player.rank}</p>
  385. <p><strong>PvP Score:</strong> ${player.pvpScore}</p>
  386. <input type="number" id="score-set-${username}" placeholder="Set PvP Score">
  387. <button id="set-score-${username}" style="background: #28a745; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Set Score</button>
  388. <input type="number" id="score-delete-${username}" placeholder="Delete PvP Score">
  389. <button id="delete-score-${username}" style="background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Delete Score</button>
  390. <button id="set-rank-${username}" style="background: #007bff; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Set Rank</button>
  391. </div>
  392. `;
  393. }).join('');
  394. content.innerHTML = `
  395. ${playerList || '<p>No players found.</p>'}
  396. <div style="margin-top: 10px;">
  397. <textarea id="announce-text" placeholder="Enter announcement" style="width: 100%; height: 60px; margin-bottom: 5px;"></textarea>
  398. <button id="send-announce" style="background: #fd7e14; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Send Announcement</button>
  399. </div>
  400. `;
  401. Object.keys(players).forEach(username => {
  402. document.getElementById(`set-score-${username}`).addEventListener('click', () => {
  403. console.log('Set score for:', username);
  404. _a1(username);
  405. });
  406. document.getElementById(`delete-score-${username}`).addEventListener('click', () => {
  407. console.log('Delete score for:', username);
  408. _a2(username);
  409. });
  410. document.getElementById(`set-rank-${username}`).addEventListener('click', () => {
  411. console.log('Set rank for:', username);
  412. _a3(username);
  413. });
  414. });
  415. document.getElementById('send-announce').addEventListener('click', () => {
  416. console.log('Send announcement clicked');
  417. _a4();
  418. });
  419. } else if (tab === 'record') {
  420. content.innerHTML = `
  421. <button id="start-record" style="background: #17a2b8; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;">Start Recording</button>
  422. <button id="stop-record" style="background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;" disabled>Stop Recording</button>
  423. <button id="send-record" style="background: #28a745; color: #fff; border: none; padding: 5px 10px; border-radius: 3px;" disabled>Send to Discord</button>
  424. `;
  425. setupRecording();
  426. } else if (tab === 'announcements') {
  427. let announceList = announcements.map(ann => `
  428. <div style="border: 1px solid #ccc; padding: 5px; margin: 5px 0; border-radius: 5px;">
  429. <p><strong>${new Date(ann.timestamp).toLocaleString()}</strong></p>
  430. <p style="${ann.read ? '' : 'font-weight: bold;'}">${ann.message}</p>
  431. </div>
  432. `).join('');
  433. content.innerHTML = `
  434. ${announceList || '<p>No announcements.</p>'}
  435. <div id="notification-area"></div>
  436. `;
  437. announcements.forEach(ann => ann.read = true);
  438. GM_setValue('announcements', announcements);
  439. } else if (tab === 'about') {
  440. content.innerHTML = `
  441. <p><strong>PVP Rank System</strong></p>
  442. <p>Toggle GUI: Press the \` key to enable/disable the GUI.</p>
  443. <p>Created for PVP ranking and recording.</p>
  444. `;
  445. }
  446. } catch (err) {
  447. console.error('Error in showTab:', err);
  448. }
  449. }
  450.  
  451. const _a1 = function(username) {
  452. try {
  453. console.log('Setting score for:', username);
  454. let scoreInput = document.getElementById(`score-set-${username}`);
  455. let score = parseInt(scoreInput.value);
  456. if (!isNaN(score) && score >= 0) {
  457. players[username].pvpScore = score;
  458. updateRank(username);
  459. } else {
  460. alert('Please enter a valid PvP Score.');
  461. }
  462. } catch (err) {
  463. console.error('Error in _a1:', err);
  464. }
  465. };
  466.  
  467. const _a2 = function(username) {
  468. try {
  469. console.log('Deleting score for:', username);
  470. let scoreInput = document.getElementById(`score-delete-${username}`);
  471. let score = parseInt(scoreInput.value);
  472. if (!isNaN(score) && score >= 0) {
  473. players[username].pvpScore = Math.max(0, players[username].pvpScore - score);
  474. updateRank(username);
  475. } else {
  476. alert('Please enter a valid PvP Score to delete.');
  477. }
  478. } catch (err) {
  479. console.error('Error in _a2:', err);
  480. }
  481. };
  482.  
  483. const _a3 = function(username) {
  484. try {
  485. console.log('Setting rank for:', username);
  486. let rankIndex = prompt('Enter rank number (1-10):');
  487. rankIndex = parseInt(rankIndex) - 1;
  488. if (!isNaN(rankIndex) && rankIndex >= 0 && rankIndex < RANKS.length) {
  489. players[username].rank = RANKS[rankIndex].name;
  490. players[username].rankImg = RANKS[rankIndex].img;
  491. GM_setValue('players', players);
  492. refreshGUI();
  493. } else {
  494. alert('Invalid rank number.');
  495. }
  496. } catch (err) {
  497. console.error('Error in _a3:', err);
  498. }
  499. };
  500.  
  501. const _a4 = function() {
  502. try {
  503. console.log('Sending announcement');
  504. if (!isAdmin) return;
  505. let announceInput = document.getElementById('announce-text');
  506. let message = announceInput.value.trim();
  507. if (message) {
  508. announcements.push({
  509. message: message,
  510. timestamp: Date.now(),
  511. read: false
  512. });
  513. GM_setValue('announcements', announcements);
  514. announceInput.value = '';
  515. showNotification(message);
  516. refreshGUI();
  517. alert('Announcement sent!');
  518. } else {
  519. alert('Please enter a valid announcement.');
  520. }
  521. } catch (err) {
  522. console.error('Error in _a4:', err);
  523. }
  524. };
  525.  
  526. const _a5 = function() {
  527. try {
  528. console.log('Logging out');
  529. currentUser = null;
  530. GM_setValue('currentUser', null);
  531. document.getElementById('rank-gui').remove();
  532. createLoginGUI();
  533. } catch (err) {
  534. console.error('Error in _a5:', err);
  535. }
  536. };
  537.  
  538. function setupRecording() {
  539. try {
  540. console.log('Setting up recording');
  541. navigator.mediaDevices.getDisplayMedia({ video: true }).then(stream => {
  542. mediaRecorder = new MediaRecorder(stream);
  543. mediaRecorder.ondataavailable = e => recordedChunks.push(e.data);
  544. mediaRecorder.onstop = () => {
  545. document.getElementById('stop-record').disabled = true;
  546. document.getElementById('send-record').disabled = false;
  547. console.log('Recording stopped');
  548. };
  549.  
  550. document.getElementById('start-record').addEventListener('click', () => {
  551. console.log('Start recording clicked');
  552. recordedChunks = [];
  553. mediaRecorder.start();
  554. document.getElementById('start-record').disabled = true;
  555. document.getElementById('stop-record').disabled = false;
  556. });
  557.  
  558. document.getElementById('stop-record').addEventListener('click', () => {
  559. console.log('Stop recording clicked');
  560. mediaRecorder.stop();
  561. });
  562.  
  563. document.getElementById('send-record').addEventListener('click', () => {
  564. console.log('Send recording clicked');
  565. let blob = new Blob(recordedChunks, { type: 'video/webm' });
  566. let formData = new FormData();
  567. formData.append('file', blob, `${currentUser}-pvp.webm`);
  568. formData.append('content', `The user that recorded this is ${currentUser}`);
  569. fetch(WEBHOOK_URL, {
  570. method: 'POST',
  571. body: formData
  572. }).then(() => {
  573. alert('Video sent to Discord!');
  574. console.log('Video sent to Discord');
  575. }).catch(err => console.error('Webhook error:', err));
  576. });
  577. }).catch(err => console.error('Recording error:', err));
  578. } catch (err) {
  579. console.error('Error in setupRecording:', err);
  580. }
  581. }
  582.  
  583. document.addEventListener('keydown', e => {
  584. try {
  585. if (e.key === '`' && document.getElementById('rank-gui')) {
  586. guiVisible = !guiVisible;
  587. document.getElementById('rank-gui').style.display = guiVisible ? 'block' : 'none';
  588. console.log('GUI toggled, visible:', guiVisible);
  589. }
  590. } catch (err) {
  591. console.error('Error in keydown handler:', err);
  592. }
  593. });
  594.  
  595. function initialize() {
  596. try {
  597. console.log('Initializing script, currentUser:', currentUser);
  598. if (!document.body) {
  599. console.error('document.body not available, retrying');
  600. setTimeout(initialize, 100);
  601. return;
  602. }
  603.  
  604. if (!currentUser) {
  605. createLoginGUI();
  606. } else {
  607. createMainGUI();
  608. displayRank();
  609. if (announcements.some(ann => !ann.read)) {
  610. let latestUnread = announcements.filter(ann => !ann.read).pop();
  611. if (latestUnread) {
  612. showNotification(latestUnread.message);
  613. console.log('Showing unread announcement:', latestUnread.message);
  614. }
  615. }
  616. }
  617. } catch (err) {
  618. console.error('Error in initialize:', err);
  619. }
  620. }
  621.  
  622. if (document.readyState === 'loading') {
  623. console.log('DOM not ready, waiting for DOMContentLoaded');
  624. document.addEventListener('DOMContentLoaded', initialize);
  625. } else {
  626. console.log('DOM ready, initializing immediately');
  627. initialize();
  628. }
  629. })();