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