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