// ==UserScript== // @name 违规检测 // @namespace http://ecmk48.free.mbbs.cc/ // @version 2.0.0 // @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.innerHTML = `
🔍 侦测
📝 总消息: 0
👥 在线玩家: 0
⏰ 状态: 运行中
最后更新: -
`; // 违规记录面板(红色)- 放在蓝色面板上方 const violationPanel = document.createElement('div'); violationPanel.id = 'violation-panel'; violationPanel.style.position = 'fixed'; violationPanel.style.bottom = '160px'; // 蓝色面板高度 + 间距 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; let currentY; let initialX; let initialY; let xOffset = 0; let yOffset = 0; const header = element.querySelector('div[style*="cursor:move"]'); if (!header) return; header.style.cursor = 'move'; header.addEventListener("mousedown", dragStart); document.addEventListener("mousemove", drag); document.addEventListener("mouseup", dragEnd); function dragStart(e) { initialX = e.clientX - xOffset; initialY = e.clientY - yOffset; if (e.target === header) { isDragging = true; // 拖动时提高z-index确保在最前面 element.style.zIndex = '10002'; } } function drag(e) { if (isDragging) { e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; xOffset = currentX; yOffset = currentY; // 边界检查 - 确保面板不会移出视口 const maxX = window.innerWidth - element.offsetWidth; const maxY = window.innerHeight - element.offsetHeight; let newX = currentX; let newY = currentY; // 限制在视口范围内 if (newX < 0) newX = 0; if (newY < 0) newY = 0; if (newX > maxX) newX = maxX; if (newY > maxY) newY = maxY; setTranslate(newX, newY, element); // 检查并防止面板重叠 preventOverlap(element); } } function setTranslate(xPos, yPos, el) { el.style.left = xPos + "px"; el.style.top = yPos + "px"; el.style.right = "auto"; el.style.bottom = "auto"; } function dragEnd(e) { initialX = currentX; initialY = currentY; isDragging = false; // 恢复正常的z-index if (element.id === 'violation-panel') { element.style.zIndex = '10001'; } else { element.style.zIndex = '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 isOverlapping = !( draggedRect.right < otherRect.left || draggedRect.left > otherRect.right || draggedRect.bottom < otherRect.top || draggedRect.top > otherRect.bottom ); if (isOverlapping) { // 如果重叠,将另一个面板推开 const overlapX = Math.min( Math.abs(draggedRect.right - otherRect.left), Math.abs(draggedRect.left - otherRect.right) ); const overlapY = Math.min( Math.abs(draggedRect.bottom - otherRect.top), Math.abs(draggedRect.top - otherRect.bottom) ); // 选择重叠较小的方向进行移动 if (overlapX < overlapY) { // 水平方向重叠较小,水平移动另一个面板 if (draggedRect.right > otherRect.left && draggedRect.left < otherRect.left) { // 拖动面板在右侧重叠 otherPanel.style.left = (draggedRect.right + 10) + 'px'; otherPanel.style.right = 'auto'; } else { // 拖动面板在左侧重叠 otherPanel.style.left = (draggedRect.left - otherRect.width - 10) + 'px'; otherPanel.style.right = 'auto'; } } else { // 垂直方向重叠较小,垂直移动另一个面板 if (draggedRect.bottom > otherRect.top && draggedRect.top < otherRect.top) { // 拖动面板在下方重叠 otherPanel.style.top = (draggedRect.bottom + 10) + 'px'; otherPanel.style.bottom = 'auto'; } else { // 拖动面板在上方重叠 otherPanel.style.top = (draggedRect.top - otherRect.height - 10) + 'px'; otherPanel.style.bottom = 'auto'; } } } } } // 更新侦测面板 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(); })();