// ==UserScript== // @name 违规检测 // @namespace http://ecmk48.free.mbbs.cc/ // @version 2.0.1 // @description 检测玩家的违规事件并记录 // @author EC // @match https://wtf.haven.chat/ // @match https://game.elfive.cn:91/wtfgame/ // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; // 违禁词列表 const bannedWords = ['神经', '骚', '逼', '外挂', '作弊', '王八蛋','操','全家','智障','fuck','Fuck','sb','SB']; const violationRecords = new Map(); // 创建监控面板 function createMonitorPanels() { // 侦测面板(蓝色)- 放在右下角底部 const detectPanel = document.createElement('div'); detectPanel.id = 'detect-panel'; detectPanel.style.position = 'fixed'; detectPanel.style.bottom = '20px'; detectPanel.style.right = '20px'; detectPanel.style.background = 'rgba(0, 50, 100, 0.9)'; detectPanel.style.color = 'white'; detectPanel.style.padding = '10px'; detectPanel.style.border = '2px solid #0088ff'; detectPanel.style.borderRadius = '8px'; detectPanel.style.zIndex = '10000'; detectPanel.style.width = '250px'; detectPanel.style.fontFamily = 'Arial, sans-serif'; detectPanel.style.fontSize = '12px'; detectPanel.style.userSelect = 'none'; detectPanel.style.height = '120px'; // 固定高度避免位置偏移 detectPanel.innerHTML = `
🔍 侦测
📝 总消息: 0
👥 在线玩家: 0
⏰ 状态: 运行中
最后更新: -
`; // 违规记录面板(红色)- 放在蓝色面板上方 const violationPanel = document.createElement('div'); violationPanel.id = 'violation-panel'; violationPanel.style.position = 'fixed'; violationPanel.style.bottom = '150px'; // 增加间距避免初始重叠 violationPanel.style.right = '20px'; violationPanel.style.background = 'rgba(100, 0, 0, 0.9)'; violationPanel.style.color = 'white'; violationPanel.style.padding = '10px'; violationPanel.style.border = '2px solid #ff4444'; violationPanel.style.borderRadius = '8px'; violationPanel.style.zIndex = '10001'; // 比蓝色面板更高 violationPanel.style.width = '250px'; violationPanel.style.fontFamily = 'Arial, sans-serif'; violationPanel.style.fontSize = '12px'; violationPanel.style.maxHeight = '150px'; // 限制高度避免重叠 violationPanel.style.overflowY = 'auto'; violationPanel.style.userSelect = 'none'; violationPanel.innerHTML = `
🚨 违规记录
🚫 违规次数: 0
👤 违规玩家: 0
暂无违规记录
`; document.body.appendChild(detectPanel); document.body.appendChild(violationPanel); // 使面板可拖动 makeDraggable(detectPanel); makeDraggable(violationPanel); return { detectPanel, violationPanel }; } // 修复后的拖动功能 - 解决重叠和定位问题 function makeDraggable(element) { let isDragging = false; let currentX, currentY; let initialX, initialY; let xOffset = 0, yOffset = 0; const header = element.querySelector('div[style*="cursor:move"]'); if (!header) return; header.style.cursor = 'move'; // 存储初始位置(用于计算基准) const initialPosition = { bottom: element.style.bottom, right: element.style.right, top: element.style.top, left: element.style.left }; header.addEventListener("mousedown", dragStart); document.addEventListener("mousemove", drag); document.addEventListener("mouseup", dragEnd); function dragStart(e) { // 计算初始位置(兼容初始定位为bottom/right的情况) const rect = element.getBoundingClientRect(); initialX = e.clientX - (rect.left - window.scrollX); initialY = e.clientY - (rect.top - window.scrollY); isDragging = true; element.style.zIndex = '10002'; // 拖动时置顶 } function drag(e) { if (!isDragging) return; e.preventDefault(); // 计算新位置(相对于视口) currentX = e.clientX - initialX; currentY = e.clientY - initialY; // 边界检查(限制在可视区域内) const maxX = window.innerWidth - element.offsetWidth; const maxY = window.innerHeight - element.offsetHeight; currentX = Math.max(0, Math.min(currentX, maxX)); currentY = Math.max(0, Math.min(currentY, maxY)); // 更新位置(统一使用top/left定位,避免冲突) element.style.top = `${currentY}px`; element.style.left = `${currentX}px`; element.style.bottom = 'auto'; element.style.right = 'auto'; // 防止与另一个面板重叠 preventOverlap(element); } function dragEnd() { isDragging = false; // 恢复层级(违规面板始终在侦测面板上方) element.style.zIndex = element.id === 'violation-panel' ? '10001' : '10000'; } // 改进的防重叠逻辑 function preventOverlap(draggedPanel) { const otherPanel = draggedPanel.id === 'detect-panel' ? document.getElementById('violation-panel') : document.getElementById('detect-panel'); if (!otherPanel) return; const draggedRect = draggedPanel.getBoundingClientRect(); const otherRect = otherPanel.getBoundingClientRect(); // 检查是否重叠 const overlap = !( draggedRect.right < otherRect.left || draggedRect.left > otherRect.right || draggedRect.bottom < otherRect.top || draggedRect.top > otherRect.bottom ); if (overlap) { // 计算重叠方向,向相反方向移动10px if (draggedRect.left < otherRect.left) { // 拖动面板在左侧,将另一个面板向右移 otherPanel.style.left = `${otherRect.left + draggedRect.width + 10 - window.scrollX}px`; } else { // 拖动面板在右侧,将另一个面板向左移 otherPanel.style.left = `${otherRect.left - draggedRect.width - 10 - window.scrollX}px`; } // 确保移动后仍在视口内 const otherMaxX = window.innerWidth - otherPanel.offsetWidth; const otherLeft = parseInt(otherPanel.style.left); otherPanel.style.left = `${Math.max(0, Math.min(otherLeft, otherMaxX))}px`; } } } // 更新侦测面板 function updateDetectPanel(messageCount, playerCount) { const messageElement = document.getElementById('detect-message-count'); const playerElement = document.getElementById('detect-player-count'); const updateElement = document.getElementById('detect-last-update'); if (messageElement) messageElement.textContent = messageCount; if (playerElement) playerElement.textContent = playerCount; if (updateElement) updateElement.textContent = new Date().toLocaleTimeString(); } // 更新违规面板 function updateViolationPanel() { const countElement = document.getElementById('violation-count'); const playerCountElement = document.getElementById('violation-player-count'); const listElement = document.getElementById('violation-list'); if (countElement) { let totalViolations = 0; for (const record of violationRecords.values()) { totalViolations += record.count; } countElement.textContent = totalViolations; } if (playerCountElement) { playerCountElement.textContent = violationRecords.size; } if (listElement) { if (violationRecords.size === 0) { listElement.innerHTML = '
暂无违规记录
'; } else { let html = ''; violationRecords.forEach((record, playerName) => { html += `
${playerName}
违规${record.count}次 最后更新: ${record.lastTime.toLocaleTimeString()}
`; }); listElement.innerHTML = html; // 添加删除按钮事件监听 document.querySelectorAll('.delete-violation-btn').forEach(btn => { btn.addEventListener('click', function() { const playerName = this.getAttribute('data-player'); deleteViolationRecord(playerName); }); }); } } } // 删除违规记录 function deleteViolationRecord(playerName) { if (violationRecords.has(playerName)) { const record = violationRecords.get(playerName); const uuid = record.uuid; // 踢出 qc.wtf.ServerManager.instance.sendMessage('kick',{uuid:uuid}); // 删除记录 violationRecords.delete(playerName); // 更新面板 updateViolationPanel(); console.log(`删除了 ${playerName} UUID: ${uuid}`); } } // 主逻辑 var messageCount = 0, playerCount = 0, ren = [], ws, hooksend; var hook = window.WebSocket; window.WebSocket = function(protocols) { ws = new hook(protocols); hooksend = ws.send; ws.send = function(data) { hooksend.call(ws, data); }; ws.addEventListener('message', function(event) { const datas = jie(event.data); processMessage(datas); }); return ws; }; function send(message) { let data = jia(message) hooksend.call(ws, data); } function processMessage(e) { try { if (e.includes('msg')) { // 处理聊天消息 const text = JSON.parse(e); if (text.v.msg && text.v.name && text.v.uuid) { messageCount++; const playerName = text.v.name; const playerUUID = text.v.uuid; const message = text.v.msg.toLowerCase(); console.log('收到消息:', playerName, ':', message); // 检查违禁词 const hasBannedWord = bannedWords.some(word => message.includes(word.toLowerCase()) ); if (hasBannedWord) { handleViolation(playerName, playerUUID); } updateDetectPanel(messageCount, ren.length); } } else if (e.includes('$newplayer')) { // 玩家加入 const arr = parsePlayerData(e); if (arr && arr.length > 0) { ren.push(arr[0]); playerCount = ren.length; updateDetectPanel(messageCount, playerCount); } } else if (e.includes('$leave')) { // 玩家离开 const arr = parsePlayerData(e); if (arr && arr.length > 0) { ren = ren.filter(obj => obj.uuid !== arr[0].uuid); playerCount = ren.length; updateDetectPanel(messageCount, playerCount); } } else if (e.includes('$playerdata')) { // 玩家数据更新 const arr = parseMultiplePlayers(e); if (arr && arr.length > 0) { ren = arr; playerCount = ren.length; updateDetectPanel(messageCount, playerCount); } } } catch (error) { console.debug('消息处理错误:', error); } } function parsePlayerData(data) { try { const Data = JSON.parse(data); return [{ name: Data.v.name, uuid: Data.v.uuid, x: Data.v.x, y: Data.v.y }]; } catch (e) { return []; } } function parseMultiplePlayers(data) { try { const Data = JSON.parse(data); return Data.v.map(item => ({ name: item.name, uuid: item.uuid, x: item.x, y: item.y })); } catch (e) { return []; } } // 加密函数 function jia(str) { return btoa(unescape(encodeURIComponent(str))); } // 解密函数 function jie(encodedStr) { return decodeURIComponent(escape(atob(encodedStr))); } function handleViolation(playerName, uid) { if (!violationRecords.has(playerName)) { violationRecords.set(playerName, { count: 0, uuid: 0, lastTime: new Date() }); } const record = violationRecords.get(playerName); record.count++; record.uuid = uid; record.lastTime = new Date(); console.log(`玩家 ${playerName} 违规次数: ${record.count}`); updateViolationPanel(); } // 初始化 function init() { // 等待页面加载完成 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { createMonitorPanels(); updateDetectPanel(0, 0); updateViolationPanel(); console.log('违禁词检测系统已启动!'); }); } else { createMonitorPanels(); updateDetectPanel(0, 0); updateViolationPanel(); console.log('违禁词检测系统已启动!'); } } // 启动系统 init(); })();