您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced real-time moderator tool for Drawaria with additional features, custom chat messages, and improved visuals
// ==UserScript== // @name Drawaria Moderator Menu With Tools // @namespace drawaria.moderator.tool // @version 3.0 // @description Enhanced real-time moderator tool for Drawaria with additional features, custom chat messages, and improved visuals // @author YouTube And Minish // @match https://drawaria.online/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // Initialize data structures const bannedPlayers = new Set(); const mutedPlayers = new Set(); const reportedPlayers = []; const warnedPlayers = new Map(); const suspiciousPlayers = new Set(); // Style definitions const styles = ` #moderatorMenuContainer { position: fixed; bottom: 60px; right: 10px; z-index: 1000; background-color: #333; border-radius: 5px; padding: 0; color: white; width: 250px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); cursor: move; font-family: Arial, sans-serif; } #moderatorMenuTitle { padding: 10px; background-color: #555; border-radius: 5px 5px 0 0; text-align: center; cursor: pointer; display: flex; justify-content: space-between; align-items: center; } #moderatorMenuContent { padding: 10px; display: none; } .menuButton { display: block; width: 100%; margin-bottom: 5px; padding: 10px; background-color: #444; color: white; border: none; border-radius: 5px; cursor: pointer; transition: background-color 0.3s; text-align: left; } .menuButton:hover { background-color: #666; } .menuButton i { margin-right: 10px; } .playerList { max-height: 200px; overflow-y: auto; border: 1px solid #555; border-radius: 5px; margin-top: 10px; } .playerListItem { padding: 5px; border-bottom: 1px solid #555; } .highlight { background-color: #ff9999; } `; // Create the moderator menu function createModeratorMenu() { const menuContainer = document.createElement('div'); menuContainer.id = 'moderatorMenuContainer'; document.body.appendChild(menuContainer); const styleElement = document.createElement('style'); styleElement.textContent = styles; document.head.appendChild(styleElement); const menuTitle = document.createElement('div'); menuTitle.id = 'moderatorMenuTitle'; menuTitle.innerHTML = '<span>Moderator Menu</span><span id="toggleArrow">▼</span>'; menuContainer.appendChild(menuTitle); const menuContent = document.createElement('div'); menuContent.id = 'moderatorMenuContent'; menuContainer.appendChild(menuContent); menuTitle.addEventListener('click', () => { menuContent.style.display = menuContent.style.display === 'none' ? 'block' : 'none'; const toggleArrow = document.getElementById('toggleArrow'); toggleArrow.innerText = menuContent.style.display === 'none' ? '▼' : '▲'; }); // Add buttons to the menu addMenuButton(menuContent, '<i class="fas fa-ban"></i> Ban Player', handleBanButtonClick); addMenuButton(menuContent, '<i class="fas fa-undo"></i> Unban Player', handleUnbanButtonClick); addMenuButton(menuContent, '<i class="fas fa-volume-mute"></i> Mute Player', handleMuteButtonClick); addMenuButton(menuContent, '<i class="fas fa-volume-up"></i> Unmute Player', handleUnmuteButtonClick); addMenuButton(menuContent, '<i class="fas fa-exclamation-triangle"></i> Warn Player', handleWarnButtonClick); addMenuButton(menuContent, '<i class="fas fa-flag"></i> Report Player', handleReportButtonClick); addMenuButton(menuContent, '<i class="fas fa-eye"></i> View Reports', handleViewReportsClick); addMenuButton(menuContent, '<i class="fas fa-users"></i> View Banned Players', handleViewBannedPlayersClick); addMenuButton(menuContent, '<i class="fas fa-microphone-alt-slash"></i> View Muted Players', handleViewMutedPlayersClick); addMenuButton(menuContent, '<i class="fas fa-user-times"></i> Kick Player', handleKickButtonClick); addMenuButton(menuContent, '<i class="fas fa-exclamation"></i> Highlight Suspicious', handleHighlightSuspiciousClick); // Create player lists createPlayerList(menuContent, 'bannedPlayersList', 'Banned Players'); createPlayerList(menuContent, 'mutedPlayersList', 'Muted Players'); createPlayerList(menuContent, 'warnedPlayersList', 'Warned Players'); createPlayerList(menuContent, 'reportedPlayersList', 'Reported Players'); createPlayerList(menuContent, 'suspiciousPlayersList', 'Suspicious Players'); // Make the menu draggable makeDraggable(menuContainer); } // Add a button to the menu function addMenuButton(menu, text, onClick) { const button = document.createElement('button'); button.innerHTML = text; button.className = 'menuButton'; button.addEventListener('click', onClick); menu.appendChild(button); } // Create a player list function createPlayerList(menu, id, title) { const listTitle = document.createElement('h3'); listTitle.textContent = title; menu.appendChild(listTitle); const listContainer = document.createElement('div'); listContainer.id = id; listContainer.className = 'playerList'; menu.appendChild(listContainer); } // Function to handle the "Ban" button click event function handleBanButtonClick() { const nickname = prompt("Enter the player's nickname to ban:"); if (nickname) { bannedPlayers.add(nickname); addModeratorMessages(nickname, 'Ban'); removePlayer(nickname); updatePlayerList(); disableChatWithUser(nickname); broadcastBanMessage(nickname); updateBannedPlayersList(); } } // Function to handle the "Unban" button click event function handleUnbanButtonClick() { const nickname = prompt("Enter the player's nickname to unban:"); if (nickname) { if (bannedPlayers.has(nickname)) { bannedPlayers.delete(nickname); addModeratorMessages(nickname, 'Unban'); updatePlayerList(); enableChatWithUser(nickname); broadcastUnbanMessage(nickname); updateBannedPlayersList(); } else { alert('Player is not banned.'); } } } // Function to handle the "Mute" button click event function handleMuteButtonClick() { const nickname = prompt("Enter the player's nickname to mute:"); if (nickname) { mutedPlayers.add(nickname); addModeratorMessages(nickname, 'Mute'); disableChatWithUser(nickname); updateMutedPlayersList(); } } // Function to handle the "Unmute" button click event function handleUnmuteButtonClick() { const nickname = prompt("Enter the player's nickname to unmute:"); if (nickname) { if (mutedPlayers.has(nickname)) { mutedPlayers.delete(nickname); addModeratorMessages(nickname, 'Unmute'); enableChatWithUser(nickname); updateMutedPlayersList(); } else { alert('Player is not muted.'); } } } // Function to handle the "Warn" button click event function handleWarnButtonClick() { const nickname = prompt("Enter the player's nickname to warn:"); const reason = prompt("Enter the reason for the warning:"); if (nickname && reason) { if (warnedPlayers.has(nickname)) { warnedPlayers.set(nickname, warnedPlayers.get(nickname) + 1); } else { warnedPlayers.set(nickname, 1); } addModeratorMessages(nickname, 'Warn', reason); updateWarnedPlayersList(); if (warnedPlayers.get(nickname) >= 3) { if (confirm(`Player ${nickname} has 3 warnings. Do you want to ban them?`)) { handleBanButtonClick(nickname); } } } } // Function to handle the "Report" button click event function handleReportButtonClick() { const nickname = prompt("Enter the player's nickname to report:"); const reason = prompt("Enter the reason for the report:"); if (nickname && reason) { reportedPlayers.push({ nickname, reason, timestamp: new Date() }); addModeratorMessages(nickname, 'Report', reason); updateReportedPlayersList(); } } // Function to handle the "View Reports" button click event function handleViewReportsClick() { const sortedReports = reportedPlayers.sort((a, b) => b.timestamp - a.timestamp); const reports = sortedReports.map(player => `${player.nickname}: ${player.reason} (at ${player.timestamp.toLocaleString()})`).join('\n'); alert(reports || 'No reports available.'); } // Function to handle the "View Banned Players" button click event function handleViewBannedPlayersClick() { const banned = Array.from(bannedPlayers).join('\n'); alert(banned || 'No banned players.'); } // Function to handle the "View Muted Players" button click event function handleViewMutedPlayersClick() { const muted = Array.from(mutedPlayers).join('\n'); alert(muted || 'No muted players.'); } // Function to handle the "Kick" button click event function handleKickButtonClick() { const nickname = prompt("Enter the player's nickname to kick:"); if (nickname) { addModeratorMessages(nickname, 'Kick'); removePlayer(nickname); updatePlayerList(); broadcastKickMessage(nickname); } } // Function to handle the "Highlight Suspicious" button click event function handleHighlightSuspiciousClick() { const nickname = prompt("Enter the player's nickname to highlight as suspicious:"); if (nickname) { suspiciousPlayers.add(nickname); highlightPlayer(nickname); updateSuspiciousPlayersList(); } } // Function to add moderator messages with custom formatting function addModeratorMessages(nickname, action, additionalInfo = '') { const chatBox = document.getElementById('chatbox_messages'); if (chatBox) { let messages = []; if (action === 'Ban') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Banned ${nickname}</div>`, `<div class="chatmessage systemchatmessage7" data-ts="${Date.now()}">Complain about the moderator on Discord, on this channel: <a href="https://discord.gg/XeVKWWs" target="_blank">#report-a-moderator</a></div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">Someone voted to ban from the room: ${nickname}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been banned from the room!</div>`, `<div class="chatmessage systemchatmessage7" data-ts="${Date.now()}">${nickname} - player has left the room</div>` ]; } else if (action === 'Unban') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Unbanned ${nickname}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been unbanned from the room!</div>` ]; } else if (action === 'Mute') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Muted ${nickname}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been muted in the room!</div>` ]; } else if (action === 'Unmute') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Unmuted ${nickname}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been unmuted in the room!</div>` ]; } else if (action === 'Warn') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Warned ${nickname} for: ${additionalInfo}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been warned! (${warnedPlayers.get(nickname)}/3)</div>` ]; } else if (action === 'Report') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Reported ${nickname}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been reported for: ${additionalInfo}</div>` ]; } else if (action === 'Kick') { messages = [ `<div class="chatmessage systemchatmessage5" data-ts="${Date.now()}">Moderator: Kicked ${nickname}</div>`, `<div class="chatmessage systemchatmessage" data-ts="${Date.now()}">${nickname} has been kicked from the room!</div>` ]; } messages.forEach(message => { chatBox.innerHTML += message; }); } } // Function to remove a player from the list function removePlayer(nickname) { const playerList = document.getElementById('playerlist'); if (playerList) { const playerToRemove = Array.from(playerList.querySelectorAll('.playerlist-row')).find(player => { const nameElement = player.querySelector('.playerlist-name a'); return nameElement && nameElement.textContent.trim() === nickname; }); if (playerToRemove) { playerToRemove.remove(); } } } // Function to update the player list function updatePlayerList() { const playerList = document.getElementById('playerlist'); if (playerList) { Array.from(playerList.querySelectorAll('.playerlist-row')).forEach(player => { const nameElement = player.querySelector('.playerlist-name a'); if (nameElement) { const playerName = nameElement.textContent.trim(); if (bannedPlayers.has(playerName)) { player.remove(); } } }); } } // Function to sanitize nickname for use in CSS selectors function sanitizeNickname(nickname) { return nickname.replace(/[^a-zA-Z0-9]/g, ''); } // Function to disable chat with the banned player function disableChatWithUser(nickname) { const sanitizedNickname = sanitizeNickname(nickname); const chatWithUser = document.querySelector(`.chat-with-${sanitizedNickname}`); if (chatWithUser) { chatWithUser.style.display = 'none'; } } // Function to enable chat with the unbanned player function enableChatWithUser(nickname) { const sanitizedNickname = sanitizeNickname(nickname); const chatWithUser = document.querySelector(`.chat-with-${sanitizedNickname}`); if (chatWithUser) { chatWithUser.style.display = 'block'; } } // Function to broadcast the ban message to all players function broadcastBanMessage(nickname) { if (window.myRoom.players && Array.isArray(window.myRoom.players)) { const message = JSON.stringify([ "bc_uc_freedrawsession_changedroom", null, null, window.myRoom.players.filter(player => player.nickname !== nickname) ]); sendMessageToAll(`42${message}`); } } // Function to broadcast the unban message to all players function broadcastUnbanMessage(nickname) { if (window.myRoom.players && Array.isArray(window.myRoom.players)) { const message = JSON.stringify([ "bc_uc_freedrawsession_changedroom", null, null, window.myRoom.players ]); sendMessageToAll(`42${message}`); } } // Function to broadcast the kick message to all players function broadcastKickMessage(nickname) { if (window.myRoom.players && Array.isArray(window.myRoom.players)) { const message = JSON.stringify([ "bc_uc_freedrawsession_changedroom", null, null, window.myRoom.players.filter(player => player.nickname !== nickname) ]); sendMessageToAll(`42${message}`); } } // Function to update the banned players list function updateBannedPlayersList() { updatePlayerListContainer('bannedPlayersList', Array.from(bannedPlayers)); } // Function to update the muted players list function updateMutedPlayersList() { updatePlayerListContainer('mutedPlayersList', Array.from(mutedPlayers)); } // Function to update the warned players list function updateWarnedPlayersList() { const warnedList = Array.from(warnedPlayers).map(([name, count]) => `${name} (${count}/3)`); updatePlayerListContainer('warnedPlayersList', warnedList); } // Function to update the reported players list function updateReportedPlayersList() { const reportedList = reportedPlayers.map(player => `${player.nickname}: ${player.reason}`); updatePlayerListContainer('reportedPlayersList', reportedList); } // Function to update the suspicious players list function updateSuspiciousPlayersList() { updatePlayerListContainer('suspiciousPlayersList', Array.from(suspiciousPlayers)); } // Generic function to update player list containers function updatePlayerListContainer(containerId, playerList) { const listContainer = document.getElementById(containerId); if (listContainer) { listContainer.innerHTML = ''; playerList.forEach(player => { const playerItem = document.createElement('div'); playerItem.textContent = player; playerItem.className = 'playerListItem'; listContainer.appendChild(playerItem); }); } } // Function to highlight a suspicious player function highlightPlayer(nickname) { const playerList = document.getElementById('playerlist'); if (playerList) { const playerToHighlight = Array.from(playerList.querySelectorAll('.playerlist-row')).find(player => { const nameElement = player.querySelector('.playerlist-name a'); return nameElement && nameElement.textContent.trim() === nickname; }); if (playerToHighlight) { playerToHighlight.classList.add('highlight'); } } } // WebSocket handling const originalSend = WebSocket.prototype.send; WebSocket.prototype.send = function (...args) { if (window.sockets.indexOf(this) === -1) { window.sockets.push(this); if (window.sockets.indexOf(this) === 0) { this.addEventListener('message', handleIncomingMessage); } } return originalSend.call(this, ...args); }; // Initialize createModeratorMenu(); // Room & Socket Control window.myRoom = { players: [] }; window.sockets = []; // Ensure the WebSocket messages are correctly formatted and sent to all players function sendMessageToAll(message) { window.sockets.forEach(socket => { if (socket.readyState === WebSocket.OPEN) { socket.send(message); } }); } // Function to handle incoming WebSocket messages function handleIncomingMessage(event) { let message = String(event.data); if (message.startsWith('42')) { let payload = JSON.parse(message.slice(2)); if (payload[0] == 'bc_uc_freedrawsession_changedroom' || payload[0] == 'mc_roomplayerschange') { window.myRoom.players = payload[3]; updatePlayerList(); updateBannedPlayersList(); updateMutedPlayersList(); updateWarnedPlayersList(); updateReportedPlayersList(); updateSuspiciousPlayersList(); } } else if (message.startsWith('430')) { let configs = JSON.parse(message.slice(3))[0]; window.myRoom.players = configs.players; window.myRoom.id = configs.roomid; updatePlayerList(); updateBannedPlayersList(); updateMutedPlayersList(); updateWarnedPlayersList(); updateReportedPlayersList(); updateSuspiciousPlayersList(); } } // Connect to the WebSocket server function connectToWebSocketServer() { const socket = new WebSocket('wss://sv3.drawaria.online/socket.io/?sid1=s%3A11JLEUID6B8TEN3-RCEDSV1h8ZzvoF3a.99s79DOPC%2Fb2ajOJBEBNkhMT0Z1FSm8jzcCGzohk%2FeI&hostname=drawaria.online&EIO=3&transport=websocket'); socket.onopen = () => { console.log('WebSocket connection opened'); window.sockets.push(socket); socket.addEventListener('message', handleIncomingMessage); }; socket.onclose = () => { console.log('WebSocket connection closed'); window.sockets = window.sockets.filter(s => s !== socket); }; socket.onerror = (error) => { console.error('WebSocket error:', error); }; } // Connect to the WebSocket server connectToWebSocketServer(); // Make an element draggable function makeDraggable(element) { let isDragging = false; let offsetX, offsetY; element.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - element.getBoundingClientRect().left; offsetY = e.clientY - element.getBoundingClientRect().top; element.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', (e) => { if (isDragging) { element.style.left = `${e.clientX - offsetX}px`; element.style.top = `${e.clientY - offsetY}px`; element.style.bottom = 'auto'; element.style.right = 'auto'; } }); document.addEventListener('mouseup', () => { isDragging = false; element.style.cursor = 'move'; }); } // Add custom chat commands for moderators function addCustomChatCommands() { const originalSendChat = window.sendChat; window.sendChat = function(message) { if (message.startsWith('/')) { const [command, ...args] = message.slice(1).split(' '); handleChatCommand(command, args); } else { originalSendChat.call(this, message); } }; } // Handle custom chat commands function handleChatCommand(command, args) { switch(command.toLowerCase()) { case 'ban': if (args.length > 0) { handleBanButtonClick(args.join(' ')); } break; case 'unban': if (args.length > 0) { handleUnbanButtonClick(args.join(' ')); } break; case 'mute': if (args.length > 0) { handleMuteButtonClick(args.join(' ')); } break; case 'unmute': if (args.length > 0) { handleUnmuteButtonClick(args.join(' ')); } break; case 'kick': if (args.length > 0) { handleKickButtonClick(args.join(' ')); } break; case 'warn': if (args.length > 1) { handleWarnButtonClick(args[0], args.slice(1).join(' ')); } break; case 'report': if (args.length > 1) { handleReportButtonClick(args[0], args.slice(1).join(' ')); } break; case 'highlight': if (args.length > 0) { handleHighlightSuspiciousClick(args.join(' ')); } break; default: addModeratorMessages('System', 'Unknown command', `Unknown command: /${command}`); } } // Initialize custom chat commands addCustomChatCommands(); })();