PVP Rank System

PVP ranking system with Discord integration

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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();
    }
})();