// ==UserScript== // @name 擂台 // @namespace http://ecmk48.free.mbbs.cc/ // @version 1.2.2 // @description 简单易改的脚本,无Bug // @author EC // @match https://game.elfive.cn:91/wtfgame/ // @match https://wtf.haven.chat/ // @grant none // @run-at document-start // ==/UserScript== // 定义全局变量 var number = 0, // 用于控制消息处理的次数 players = [], ws, ttt = "关", // WebSocket实例 hookmessage, hooksend, // 用于存储原始的WebSocket send方法和onmessage事件 me = [{ // 存储当前玩家的信息 name: "", uuid: 0, x: 0, y: 0 }], ren = [], // 存储其他玩家的信息 player1 = { name: "", uuid: 0 }, player2 = { name: "", uuid: 0 }, score1 = 0, score2 = 0, start = 0 // 拦截原生WebSocket构造函数 var hook = window.WebSocket; window.WebSocket = function(protocols) { ws = new hook(protocols); // 创建一个新的WebSocket实例 // 保存原生的send方法 hooksend = ws.send; // 拦截WebSocket的send方法 ws.send = function(data) { var datas = jie(data); // 解密发送的数据 j3(datas); // 处理发送的数据(例如更新玩家信息) hooksend.call(ws, data); // 调用原生的send方法发送数据 }; // 监听WebSocket的message事件 ws.addEventListener('message', function(event) { if (number < 2) { // 限制消息处理的次数 number++; } if (number == 1) { hookmessage = ws.onmessage; // 保存原始的onmessage事件处理函数 } ws.onmessage = function(e) { var datas = jie(e.data); // 解密收到的消息 f(datas); // 处理消息(调用对应的事件处理函数) hookmessage(e); // 调用原始的onmessage事件处理函数 }; }); ws.addEventListener('open', function(event) { creatui(); }); // 监听WebSocket的close事件 ws.addEventListener('close', function(event) { alert("断开连接"); // 提示用户连接已断开 }); return ws; // 返回新的WebSocket实例 }; // 自定义发送函数(封装了加密和调用原生send方法) function send(message) { let data = jia(message); // 加密消息 hooksend.call(ws, data); // 调用原生的send方法发送加密后的消息 } // 定义事件处理函数 const eventHandlers = { move(e) { // 玩家移动事件 let json = JSON.parse(e); a(arr = j(e)); // 更新玩家位置 if (start) { if (json.v.uuid == player1.uuid || json.v.uuid == player2.uuid) { if (json.v.y > -300) { send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":510,"y":-350}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":950,"y":-350}}`); } } if (e.includes('throw')) { if (json.v.uuid == player1.uuid && json.v.target == player2.uuid) { score1++; send(`{"k":"msg","v":{"msg":"${player1.name} ${score1}:${score2} ${player2.name}"}}`); } else if (json.v.uuid == player2.uuid && json.v.target == player1.uuid) { score2++; send(`{"k":"msg","v":{"msg":"${player1.name} ${score1}:${score2} ${player2.name}"}}`); } } if (score1 == 10) { send(`{"k":"msg","v":{"msg":"${player1.name}获胜"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); reset(); settime(1) } else if (score2 == 10) { send(`{"k":"msg","v":{"msg":"${player2.name}获胜"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); reset(); settime(1) } } }, $leave(e) { // 玩家离开事件 let arr = j2(e); // 解析离开玩家的UUID ren = ren.filter(obj => obj.uuid !== arr); // 从玩家列表中移除该玩家 if (arr == player1.uuid) { send(`{"k":"msg","v":{"msg":"${player1.name}退出游戏结束"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); settime(1) reset() } else if (arr == player2.uuid) { send(`{"k":"msg","v":{"msg":"${player2.name}退出游戏结束"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); settime(1) reset() } }, $playerdata(e) { // 玩家数据更新事件 a(arr = j1(e)); // 更新玩家数据 }, $newplayer(e) { // 新玩家加入事件 const Data = JSON.parse(e); // 解析新玩家数据 const arr = [{ name: Data.v.name, uuid: Data.v.uuid, score: Data.v.score, x: Data.v.x, y: Data.v.y }]; ren = [...ren, ...arr]; // 将新玩家添加到玩家列表 }, mode(e) { // 模式切换事件 ren = []; // 清空玩家列表 ttt = "关"; }, msg(e) { let json = JSON.parse(e); if (json.v.msg == "/join" && ttt == "开") { if (player1.uuid == 0) { player1 = { uuid: json.v.uuid, name: json.v.name }; send(`{"k":"msg","v":{"msg":"${json.v.name}加入游戏"}}`); } else if (player2.uuid == 0 && player1.uuid !== json.v.uuid) { player2 = { uuid: json.v.uuid, name: json.v.name }; ren.forEach(player => { if (player.y < -300) { send(`{"k":"move","v":{"t":"throw","uuid":${player.uuid},"dir":1,"x":0,"y":0}}`); } }); send(`{"k":"msg","v":{"msg":"${json.v.name}和${player1.name}比赛开始计时两分钟"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${json.v.uuid},"dir":1,"x":510,"y":-350}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":950,"y":-350}}`); start = true settime(0) } else if (player1.uuid !== 0 && player2.uuid !== 0) { send(`{"k":"msg","v":{"msg":"${player1.name}和${player2.name}正在比赛"}}`); } } } }; // 定义全局变量存储定时器 ID let timerB, timerC; function settime(e) { // 定义定时器回调函数 function endGame() { if (score1 > score2) { send(`{"k":"msg","v":{"msg":"时间到,${player1.name}获胜"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); } else if (score2 > score1) { send(`{"k":"msg","v":{"msg":"时间到,${player2.name}获胜"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); } else { send(`{"k":"msg","v":{"msg":"${player1.name}和${player2.name}平局"}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player1.uuid},"dir":1,"x":0,"y":0}}`); send(`{"k":"move","v":{"t":"throw","uuid":${player2.uuid},"dir":1,"x":0,"y":0}}`); } reset(); // 确保 reset 函数已定义 } function halfTimeMessage() { send(`{"k":"msg","v":{"msg":"比赛过半,${player1.name}和${player2.name}请加油!"}}`); } if (e == 0) { // 启动计时器 timerB = setTimeout(endGame, 120000); // 120秒后执行 timerC = setTimeout(halfTimeMessage, 60000); // 60秒后执行 } else { // 清除计时器 if (timerB) clearTimeout(timerB); if (timerC) clearTimeout(timerC); console.log("定时器已清除"); } } function reset() { player1 = { name: "", uuid: 0 }; player2 = { name: "", uuid: 0 }; score1 = 0; score2 = 0; start = false; } // 消息处理函数:根据消息类型调用对应的事件处理函数 function f(e) { for (const [event, handler] of Object.entries(eventHandlers)) { if (e.includes(event)) { // 如果消息中包含事件类型 handler(e); // 调用对应的事件处理函数 return; } } } // 更新玩家位置的函数 function a(arr) { if (arr[0].uuid !== me[0].uuid) { // 如果不是当前玩家 let ji = 0; for (let t = 0; t < ren.length; t++) { if (ren[t].uuid == arr[0].uuid) { // 如果玩家已存在 ren[t].x = arr[0].x; // 更新玩家的X坐标 ren[t].y = arr[0].y; // 更新玩家的Y坐标 } else { ji++; } } if (ji == ren.length) { // 如果玩家不存在 ren = [...ren, ...arr]; // 将新玩家添加到玩家列表 } } } // 解析单个玩家数据的函数 function j(jsonData) { const Data = JSON.parse(jsonData); // 解析JSON数据 const arr = [{ name: Data.v.name, uuid: Data.v.uuid, x: Data.v.x, y: Data.v.y }]; return arr; } // 解析多个玩家数据的函数 function j1(jsonData) { const Data = JSON.parse(jsonData); // 解析JSON数据 var arr = Data.v.map(item => { return { name: item.name, uuid: item.uuid, score: item.score, x: item.x, y: item.y }; }); return arr; } // 解析离开玩家的UUID function j2(jsonData) { const Data = JSON.parse(jsonData); // 解析JSON数据 const arr = Data.v.uuid; return arr; } // 处理发送数据的函数:更新当前玩家信息 function j3(datas) { if (datas.includes('move')) { // 如果是移动事件 me = j(datas); // 更新当前玩家信息 } else if (datas.includes('login')) { // 如果是登录事件 const Data = JSON.parse(datas); // 解析数据 me = [{ name: Data.v.name, uuid: 0, x: 0, y: 0 }]; } } // 加密函数:使用Base64加密 function jia(str) { return btoa(unescape(encodeURIComponent(str))); } // 解密函数 function jie(inputString) { try { // 如果输入已经是JSON字符串,直接返回 if (inputString.trim().startsWith('{') && inputString.trim().endsWith('}')) { return inputString; } // 清理输入字符串,移除可能的额外字符 let cleanInput = inputString.replace(/[^A-Za-z0-9+/=]/g, ''); // 确保Base64字符串长度是4的倍数 while (cleanInput.length % 4 !== 0) { cleanInput += '='; } try { // 尝试直接解码Base64 const base64Decoded = atob(cleanInput); // 将解码后的字符串转换为Uint8Array const bytes = new Uint8Array(base64Decoded.length); for (let i = 0; i < base64Decoded.length; i++) { bytes[i] = base64Decoded.charCodeAt(i); } // 使用TextDecoder解码为UTF-8字符串 const decoder = new TextDecoder('utf-8'); let decodedString = decoder.decode(bytes); // 清理解码后的字符串,提取有效的JSON部分 decodedString = extractValidJson(decodedString); if (decodedString && decodedString.trim().startsWith('{') && decodedString.trim().endsWith('}')) { return decodedString; } throw new Error('解码后不是有效的JSON'); } catch (innerError) { console.log('直接Base64解码失败,尝试备用方法:', innerError.message); return tryAlternativeDecoding(inputString); } } catch (e) { console.error('解密完全失败:', e); return null; } } // 提取有效JSON的函数 function extractValidJson(mixedString) { if (!mixedString) return null; // 如果已经是有效的JSON,直接返回 if (mixedString.trim().startsWith('{') && mixedString.trim().endsWith('}')) { try { JSON.parse(mixedString); return mixedString; } catch (e) { // 继续处理 } } // 查找第一个{和最后一个} const startIndex = mixedString.indexOf('{'); const endIndex = mixedString.lastIndexOf('}'); if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) { return null; } let jsonCandidate = mixedString.substring(startIndex, endIndex + 1); // 验证括号平衡 let balance = 0; for (let i = 0; i < jsonCandidate.length; i++) { if (jsonCandidate[i] === '{') balance++; if (jsonCandidate[i] === '}') balance--; if (balance < 0) break; } if (balance !== 0) { // 括号不平衡,尝试逐步调整 return findBalancedJson(mixedString, startIndex); } try { JSON.parse(jsonCandidate); return jsonCandidate; } catch (e) { // 尝试找到平衡的JSON return findBalancedJson(mixedString, startIndex); } } // 查找平衡的JSON function findBalancedJson(str, startIndex) { let openBraces = 0; let endIndex = -1; for (let i = startIndex; i < str.length; i++) { if (str[i] === '{') { openBraces++; } else if (str[i] === '}') { openBraces--; if (openBraces === 0) { endIndex = i; break; } } } if (endIndex !== -1) { const jsonStr = str.substring(startIndex, endIndex + 1); try { JSON.parse(jsonStr); return jsonStr; } catch (e) { console.log('找到的字符串不是有效JSON:', e); } } return null; } // 备用解码方法 function tryAlternativeDecoding(inputString) { try { // 移除所有非Base64字符 let base64String = inputString.replace(/[^A-Za-z0-9+/=]/g, ''); // 填充到4的倍数 while (base64String.length % 4 !== 0) { base64String += '='; } // 尝试不同的编码方式 const decoded = atob(base64String); // 尝试直接作为字符串返回 if (decoded.includes('{') && decoded.includes('}')) { const jsonStr = extractValidJson(decoded); if (jsonStr) return jsonStr; } // 尝试UTF-8解码 try { const bytes = new Uint8Array(decoded.length); for (let i = 0; i < decoded.length; i++) { bytes[i] = decoded.charCodeAt(i); } const decoder = new TextDecoder('utf-8'); const utf8Decoded = decoder.decode(bytes); const jsonStr = extractValidJson(utf8Decoded); if (jsonStr) return jsonStr; } catch (e) { console.log('UTF-8解码失败:', e); } // 最后尝试:直接返回包含大括号的部分 const start = decoded.indexOf('{'); const end = decoded.lastIndexOf('}'); if (start !== -1 && end !== -1 && end > start) { return decoded.substring(start, end + 1); } } catch (e) { console.error('备用解码方法失败:', e); } return null; } function creatui() { var box = document.createElement('div'); box.id = "wtfhelp-container"; box.style.position = "absolute"; box.style.bottom = "10px"; box.style.right = "10px"; box.style.backgroundColor = "rgba(0, 0, 0, 0.7)"; box.style.padding = "10px"; box.style.borderRadius = "5px"; box.style.zIndex = "999999"; // 添加按钮 box.innerHTML = ` `; document.body.appendChild(box); // 按钮点击事件处理 box.onclick = function(event) { if (event.target.id === "001") { if (ttt == "关") { let r = qc.wtf.GameManager.instance.channel; if (r < 0) { send(`{"k":"msg","v":{"msg":"开启擂台"}}`); ttt = "开"; return; } else { alert("擂台仅可在py使用"); } } else if (ttt == "开") { if (timerB) clearTimeout(timerB); if (timerC) clearTimeout(timerC); reset(); send(`{"k":"msg","v":{"msg":"关闭擂台"}}`); ttt = "关"; } } else if (event.target.id === "002" && ttt == "开") { if (timerB) clearTimeout(timerB); if (timerC) clearTimeout(timerC); reset(); send(`{"k":"msg","v":{"msg":"比赛强制结束,需重新加入"}}`); } else if (event.target.id === "003") { const roomNumber = prompt("输入房间号"); if (roomNumber !== null && roomNumber.trim() !== "") { send(`{"k":"msg","v":{"msg":"/room ${roomNumber.trim()}"}}`); } } }; }