您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Provides a basic understanding of how sploop handles websockets, lets connect a bot via console
当前为
// ==UserScript== // @name Sploop.io Socket API // @author Murka // @description Provides a basic understanding of how sploop handles websockets, lets connect a bot via console // @icon https://sploop.io/img/ui/favicon.png // @version 1.0 // @match *://sploop.io/ // @run-at document-start // @grant none // @license MIT // @namespace https://greasyforks.org/users/919633 // ==/UserScript== /* jshint esversion:6 */ /* Author: Murka Github: https://github.com/Murka007 Greasyfork: https://greasyforks.org/users/919633 Discord: https://discord.gg/cPRFdcZkeD Connect a bot via console using `SocketAPI.createClient();` */ (function() { "use strict"; const log = console.log; localStorage.removeItem("_adIds"); const getAngle = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1); const hashing = { 9303: function(t, n) { t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]; n = [n[0] >>> 16, 65535 & n[0], n[1] >>> 16, 65535 & n[1]]; const i = [0, 0, 0, 0]; i[3] += t[3] + n[3]; i[2] += i[3] >>> 16; i[3] &= 65535; i[2] += t[2] + n[2]; i[1] += i[2] >>> 16; i[2] &= 65535; i[1] += t[1] + n[1]; i[0] += i[1] >>> 16; i[1] &= 65535; i[0] += t[0] + n[0]; i[0] &= 65535; return [i[0] << 16 | i[1], i[2] << 16 | i[3]]; }, 3235: function(t, n) { t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]; n = [n[0] >>> 16, 65535 & n[0], n[1] >>> 16, 65535 & n[1]]; const i = [0, 0, 0, 0]; i[3] += t[3] * n[3]; i[2] += i[3] >>> 16; i[3] &= 65535; i[2] += t[2] * n[3]; i[1] += i[2] >>> 16; i[2] &= 65535; i[2] += t[3] * n[2]; i[1] += i[2] >>> 16; i[2] &= 65535; i[1] += t[1] * n[3]; i[0] += i[1] >>> 16; i[1] &= 65535; i[1] += t[2] * n[2]; i[0] += i[1] >>> 16; i[1] &= 65535; i[1] += t[3] * n[1]; i[0] += i[1] >>> 16; i[1] &= 65535; i[0] += t[0] * n[3] + t[1] * n[2] + t[2] * n[1] + t[3] * n[0]; i[0] &= 65535 return [i[0] << 16 | i[1], i[2] << 16 | i[3]]; }, 9869: function(t, n) { n %= 64; if (32 == n) return [t[1], t[0]]; if (n < 32) return [t[0] << n | t[1] >>> 32 - n, t[1] << n | t[0] >>> 32 - n]; n -= 32; return [t[1] << n | t[0] >>> 32 - n, t[0] << n | t[1] >>> 32 - n]; }, 1318: function(t, n) { n %= 64; if (0 == n) return t; if (n < 32) return [t[0] << n | t[1] >>> 32 - n, t[1] << n]; return [t[1] << n - 32, 0]; }, 6217: function(t, n) { return [t[0] ^ n[0], t[1] ^ n[1]]; }, 1552: function(t) { const o = hashing[3235]; const e = hashing[6217]; t = e(t, [0, t[0] >>> 1]); t = o(t, [4283543511, 3981806797]); t = e(t, [0, t[0] >>> 1]); t = o(t, [3301882366, 444984403]); return e(t, [0, t[0] >>> 1]); }, 6112: function(t, i) { const e = hashing[9303]; const r = hashing[3235]; const c = hashing[9869]; const a = hashing[1318]; const s = hashing[6217]; const h = hashing[1552]; i = i || 0; const u = (t = t || "").length % 16; const f = t.length - u; let l = [0, i]; let d = [0, i]; let g = [0, 0]; let w = [0, 0]; const b = [2277735313, 289559509]; const M = [1291169091, 658871167]; let v; for (v = 0; v < f; v += 16) { g = [255 & t.charCodeAt(v + 4) | (255 & t.charCodeAt(v + 5)) << 8 | (255 & t.charCodeAt(v + 6)) << 16 | (255 & t.charCodeAt(v + 7)) << 24, 255 & t.charCodeAt(v) | (255 & t.charCodeAt(v + 1)) << 8 | (255 & t.charCodeAt(v + 2)) << 16 | (255 & t.charCodeAt(v + 3)) << 24]; w = [255 & t.charCodeAt(v + 12) | (255 & t.charCodeAt(v + 13)) << 8 | (255 & t.charCodeAt(v + 14)) << 16 | (255 & t.charCodeAt(v + 15)) << 24, 255 & t.charCodeAt(v + 8) | (255 & t.charCodeAt(v + 9)) << 8 | (255 & t.charCodeAt(v + 10)) << 16 | (255 & t.charCodeAt(v + 11)) << 24]; g = r(g, b); g = c(g, 31); g = r(g, M); l = s(l, g); l = c(l, 27); l = e(l, d); l = e(r(l, [0, 5]), [0, 1390208809]); w = r(w, M); w = c(w, 33); w = r(w, b); d = s(d, w); d = c(d, 31); d = e(d, l); d = e(r(d, [0, 5]), [0, 944331445]); } g = [0, 0]; w = [0, 0]; switch (u) { case 15: w = s(w, a([0, t.charCodeAt(v + 14)], 48)); case 14: w = s(w, a([0, t.charCodeAt(v + 13)], 40)); case 13: w = s(w, a([0, t.charCodeAt(v + 12)], 32)); case 12: w = s(w, a([0, t.charCodeAt(v + 11)], 24)); case 11: w = s(w, a([0, t.charCodeAt(v + 10)], 16)); case 10: w = s(w, a([0, t.charCodeAt(v + 9)], 8)); case 9: w = s(w, [0, t.charCodeAt(v + 8)]), w = r(w, M), w = c(w, 33), w = r(w, b), d = s(d, w); case 8: g = s(g, a([0, t.charCodeAt(v + 7)], 56)); case 7: g = s(g, a([0, t.charCodeAt(v + 6)], 48)); case 6: g = s(g, a([0, t.charCodeAt(v + 5)], 40)); case 5: g = s(g, a([0, t.charCodeAt(v + 4)], 32)); case 4: g = s(g, a([0, t.charCodeAt(v + 3)], 24)); case 3: g = s(g, a([0, t.charCodeAt(v + 2)], 16)); case 2: g = s(g, a([0, t.charCodeAt(v + 1)], 8)); case 1: g = s(g, [0, t.charCodeAt(v)]), g = r(g, b), g = c(g, 31), g = r(g, M), l = s(l, g); } l = s(l, [0, t.length]); d = s(d, [0, t.length]); l = e(l, d); d = e(d, l); l = h(l); d = h(d); l = e(l, d); d = e(d, l); return ("00000000" + (l[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (l[1] >>> 0).toString(16)).slice(-8) + ("00000000" + (d[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (d[1] >>> 0).toString(16)).slice(-8); }, 3028: function(t, n, i, o) { return function() { let e = (t >>>= 0) + (n >>>= 0) | 0; t = n ^ n >>> 9; n = (i >>>= 0) + (i << 3) | 0; i = (i = i << 21 | i >>> 11) + (e = e + (o = 1 + (o >>>= 0) | 0) | 0) | 0; return (e >>> 0) / 4294967296; } }, 9623: function(t) { for (var o = 0, e = 1779033703 ^ t.length; o < t.length; o++) { e = (e = Math.imul(e ^ t.charCodeAt(o), 3432918353)) << 13 | e >>> 19; } return function() { e = Math.imul(e ^ e >>> 16, 2246822507); e = Math.imul(e ^ e >>> 13, 3266489909); return (e ^= e >>> 16) >>> 0; } }, 1122: function(t) { const o = hashing[3028]; const e = hashing[9623]; t = e(t || ""); return o(t(), t(), t(), t()); }, 9629: function(t, n) { const o = hashing[6112]; const e = hashing[1122]; const i = o("" + t, "" + n); const r = e(i); return [~~(246 * r()), ~~(255 * r()), ~~(255 * r()), ~~(255 * r())]; } } class Vector { constructor(x = 0, y = 0) { this.x = x; this.y = y; } static fromAngle(angle, length = 1) { return new Vector(Math.cos(angle) * length, Math.sin(angle) * length); } add(vec) { if (vec instanceof Vector) { this.x += vec.x; this.y += vec.y; } else { this.x += vec; this.y += vec; } return this; } sub(vec) { if (vec instanceof Vector) { this.x -= vec.x; this.y -= vec.y; } else { this.x -= vec; this.y -= vec; } return this; } mult(vec) { if (vec instanceof Vector) { this.x *= vec.x; this.y *= vec.y; } else { this.x *= vec; this.y *= vec; } return this; } div(vec) { if (vec instanceof Vector) { this.x /= vec.x; this.y /= vec.y; } else { this.x /= vec; this.y /= vec; } return this; } get length() { return Math.sqrt(this.x * this.x + this.y * this.y); } normalize() { return this.length > 0 ? this.div(this.length) : this; } dot(vec) { return this.x * vec.x + this.y * vec.y; } proj(vec) { const k = this.dot(vec) / vec.dot(vec); return vec.copy().mult(k); } setXY(x, y) { this.x = x; this.y = y; return this; } setVec(vec) { return this.setXY(vec.x, vec.y); } setLength(value) { return this.normalize().mult(value); } copy() { return new Vector(this.x, this.y); } distance(vec) { return this.copy().sub(vec).length; } angle(vec) { const copy = vec.copy().sub(this); return Math.atan2(copy.y, copy.x); } direction(angle, length) { return this.copy().add(Vector.fromAngle(angle, length)); } isEqual(vec) { return this.x === vec.x && this.y === vec.y; } stringify() { return this.x + ":" + this.y; } min(vec) { this.x = Math.min(this.x, vec.x); this.y = Math.min(this.y, vec.y); return this; } max(vec) { this.x = Math.max(this.x, vec.x); this.y = Math.max(this.y, vec.y); return this; } trunc() { this.x = Math.trunc(this.x); this.y = Math.trunc(this.y); return this; } } const formatButton = (button) => { if (0 === button) return "LBTN"; if (1 === button) return "MBTN"; if (2 === button) return "RBTN"; if (3 === button) return "BBTN"; if (4 === button) return "FBTN"; throw new Error(`formatButton Error: "${button}" is not valid button`); } const InputHandler = new class InputHandler { mouse = new Vector; innerSize = new Vector; angle = 0; canvas = {}; startMouse = false; attach() { const canvas = document.querySelector("#game-canvas"); this.canvas.mousedown = canvas.onmousedown; this.canvas.mouseup = canvas.onmouseup; canvas.onmousedown = null canvas.onmouseup = null; window.addEventListener("mousemove", event => { this.mouse.setXY(event.clientX, event.clientY); this.angle = getAngle(innerWidth / 2, innerHeight / 2, this.mouse.x, this.mouse.y); }); canvas.addEventListener("mousedown", event => this.mousedown(event)); window.addEventListener("mouseup", event => this.mouseup(event)); const resize = () => { const w = window.innerWidth; const h = window.innerHeight; this.mouse.x *= w / this.innerSize.x; this.mouse.y *= h / this.innerSize.y; this.innerSize.setXY(w, h); } window.addEventListener("resize", resize); resize(); } cursorPosition(target) { const w = window.innerWidth; const h = window.innerHeight; const scale = Math.max(w / 1824, h / 1026); const cursorX = (this.mouse.x - w / 2) / scale; const cursorY = (this.mouse.y - h / 2) / scale; return new Vector(target.x + cursorX, target.y + cursorY); } mousedown(event) { const { ModuleHandler, myPlayer, clients } = playerClient; const button = formatButton(event.button); if (button === "LBTN" && !this.startMouse) { this.startMouse = true; this.canvas.mousedown(event); /*ModuleHandler.attacking = 1; const pos = this.cursorPosition(myPlayer.position); for (const client of clients) { const angle = client.myPlayer.position.angle(pos); client.PacketHandler.attack(angle); }*/ } } mouseup(event) { const { ModuleHandler, clients } = playerClient; const button = formatButton(event.button); if (button === "LBTN" && this.startMouse) { this.startMouse = false; this.canvas.mouseup(event); /*if (ModuleHandler.attacking !== 0) { for (const client of clients) { client.PacketHandler.stopAttack(); } }*/ } } } window.addEventListener("load", () => { InputHandler.attach(); }); const HookedArrays = { joins: null, } class TempData { constructor(client) { this.client = client; } setAttacking(attacking) { /*const { ModuleHandler } = this.client; if (ModuleHandler.attacking === attacking) { return; } ModuleHandler.attacking = attacking; if (0 !== attacking) { ModuleHandler.attackingState = attacking; }*/ } } class ClanJoiner { constructor(client) { this.client = client; this.joinCount = 0; } postTick() { const { myPlayer, owner, PacketHandler } = this.client; const ownerClan = owner.myPlayer.clan; if (ownerClan === myPlayer.clan) return; if (this.joinCount === 0) { if (myPlayer.clan === 0) { owner.pendingJoins.add(myPlayer.globalID); PacketHandler.joinClan(ownerClan); } else { PacketHandler.leaveClan(); } } this.joinCount = (this.joinCount + 1) % 10; } } class Movement { constructor(client) { this.client = client; } postTick() { const { myPlayer, owner, ModuleHandler } = this.client; const pos1 = this.client.myPlayer.position; const pos2 = InputHandler.cursorPosition(this.client.owner.myPlayer.position); const distance = pos1.distance(pos2); const angle = pos1.angle(pos2); const currentAngle = distance > 0 ? angle: null; ModuleHandler.targetAngle = angle; ModuleHandler.moveByAngle(currentAngle); } } class AutoAccept { constructor(client) { this.client = client; } postTick() { const { myPlayer, PlayerManager, owner, pendingJoins, PacketHandler } = this.client; if (!PlayerManager.isClanOwner(myPlayer) || myPlayer.joinRequests.length === 0) return; const id = myPlayer.joinRequests[0]; if (pendingJoins.size !== 0) { PacketHandler.acceptDecline(pendingJoins.has(id)); this.client.removeJoin(id); } } } class AutoHeal { constructor(client) { this.client = client; } postTick() { if (this.client.myPlayer.health === 100) return; setTimeout(() => { this.client.ModuleHandler.heal(); }, 120); } } class UpdateAngle { constructor(client) { this.client = client; } /*getAngle() { if (this.client.isOwner) return InputHandler._angle; return null; }*/ postTick() { const { ModuleHandler } = this.client; const angle = ModuleHandler.targetAngle; if (angle !== null) { ModuleHandler.updateAngle(angle); } } } class ModuleHandler { constructor(client) { this.client = client; this.reset(); this.statisModules = { tempData: new TempData(client), }; this.botModules = [ new ClanJoiner(client), new Movement(client), ]; this.modules = [ new AutoAccept(client), new AutoHeal(client), new UpdateAngle(client), ]; this.rotation = true; this.mouse = { x: 0, y: 0, lockX: 0, lockY: 0, angle: 0, _angle: 0, } } reset() { this.weapon = 0; this.moveAngle = null; this.targetAngle = null; this.currentAngle = 0; this.attacking = 0; this.attackingState = 0; } attachMouse() { window.addEventListener("mousemove", event => { this.mouse.x = event.clientX; this.mouse.y = event.clientY; const angle = getAngle(innerWidth / 2, innerHeight / 2, this.mouse.x, this.mouse.y); this.mouse._angle = angle; if (this.rotation) { this.mouse.lockX = event.clientX; this.mouse.lockY = event.clientY; this.mouse.angle = angle; } }); } moveByAngle(angle) { if (angle === this.moveAngle) return; this.moveAngle = angle; const { PacketHandler } = this.client; if (angle === null) { PacketHandler.stopMovement(); } else { PacketHandler.moveByAngle(angle); } } updateAngle(angle) { if (angle === this.currentAngle) return; this.currentAngle = angle; const { PacketHandler } = this.client; PacketHandler.updateAngle(angle); } whichWeapon(type = this.weapon) { if (this.weapon === type) return; this.weapon = type; this.client.PacketHandler.selectItemByType(type); } placeItemByType(type) { this.client.PacketHandler.selectItemByType(type); this.client.PacketHandler.attack(this.mouse.angle); this.client.PacketHandler.stopAttack(); this.whichWeapon(); } heal() { this.placeItemByType(2); } postTick() { if (!this.client.isOwner) { for (const botModule of this.botModules) { botModule.postTick(); } } for (const module of this.modules) { module.postTick(); } this.attackingState = this.attacking; } } class Player { type = 0; globalID = 0; id = 0; position = new Vector; angle = 0; health = 100; clan = 0; constructor(client) { this.client = client; } update(type, globalID, id, x, y, angle, health, clanID) { this.type = type; this.globalID = globalID; this.id = id; this.position.setXY(x, y); this.angle = angle; this.health = health; this.clan = clanID; } } class ClientPlayer extends Player { constructor(client) { super(client); this.joinRequests = []; this.upgradeList = []; this.reset(); } reset() { this.inGame = false; this.upgradeList.length = 0; this.upgradeIndex = 0; this.upgradeAge = 0; this.prevAge = 0; this.age = 0; this.food = 0; this.wood = 0; this.stone = 0; this.gold = 0; } handleUpgrade(items) { if (this.client.isOwner) return; const { upgradeList } = this.client.owner.myPlayer; const currentItem = upgradeList[this.upgradeIndex]; if (upgradeList.includes(currentItem)) { this.upgradeItem(currentItem); } } upgradeItem(id) { this.upgradeAge += 1; if (this.client.isOwner) { this.upgradeList.push(id); for (const client of this.client.clients) { const { age, upgradeAge, upgradeIndex } = client.myPlayer; if (age > upgradeAge) { const item = this.upgradeList[upgradeIndex]; client.myPlayer.upgradeItem(item); } } return; } this.client.PacketHandler.upgradeItem(id); this.upgradeIndex += 1; } updateAge() { //log(this.age, this.upgradeAge); } handleStats(age, food, wood, stone, gold) { this.food = food; this.wood = wood; this.stone = stone; this.gold = gold; if (age === 0) return; this.prevAge = this.age; this.age = age; if (this.age > this.prevAge) { this.updateAge(); } } postTick() { if (this.inGame) { this.client.ModuleHandler.postTick(); } } } class PlayerManager { playerData = new Map(); clanData = new Map(); constructor(client) { this.client = client; } isClanOwner(player) { const clan = this.clanData.get(player.clan); return clan && clan.owner === player.globalID; } getPlayer(id) { if (this.playerData.has(id)) { return this.playerData.get(id); } const player = new Player(); this.playerData.set(id, player); return player; } createClan(id, owner, name) { const clanData = this.clanData; if (!clanData.has(id)) { clanData.set(id, {}); } const clan = clanData.get(id); clan.id = id; clan.owner = owner; clan.name = name; } } const random = (min, max) => { return Math.floor(Math.random() * (max - min + 1) + min); } const PI = Math.PI; const PI2 = PI * 2; const formatAge = (age) => Math.floor(Math.log(1 + Math.max(0, age)) ** 2.4 / 13); const formatAngle = (byte) => byte / 255 * PI2 - PI; const encodeAngle = (angle) => { angle = 65535 * (angle + PI) / PI2; return [255 & angle, angle >> 8 & 255]; } const getRandomString = (len, numbers) => { let output = ""; const nums = "0123456789"; const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; const text = numbers ? nums : alphabet; for (let i=0;i<len;i++) { const index = Math.floor(Math.random() * (text.length - 1)); const char = text[index]; output += char; } return output; } const StoreState = { BUY: 0, EQUIP: 1, UNEQUIP: 2, } const EntityState = { UPDATE: 0, Nr: 1, DELETE: 2, IN_WATER: 4, UNDER_ROOF: 8, Vr: 16, TRAPPED: 32, ON_PLATFORM: 64, Yr: 128 } const SocketServer = { UPDATE_MOVEMENT: 20, MY_PLAYER_INIT: 35, CONNECT: 25, Xn: 26, // not used in the code $n: 9, // most likely old player init, with toggle mechanism or death marker, [byte, byte, byte, byte] UPDATE_INVENTORY: 2, PLAYER_SPAWNED: 32, ATTACK_ANIMATION: 29, LEADERBOARD: 3, DEFAULT_DATA: 33, ri: 31, // most likely unvalid shit, used in rendering, some boss or icon shit DAMAGE: 6, KILL_UPDATE: 22, DIED: 19, PLAYER_RESOURCES: 8, KILL_MESSAGE: 28, ch: 13, // somehow related to clans UPDATE_STORE: 5, TEXT_MESSAGE: 30, UPGRADE: 14, CLEAR_UPGRADE: 34, // some init, reset upgrade bar wi: 11, // not used in the code PING_REQUEST: 0, PING_RESPONSE: 15, CLAN_JOIN: 24, CLAN_LEAVE: 27, CLAN_CREATED: 4, CLAN_DELETED: 1, JOIN_REQUEST: 17, CLAN_UPDATED: 16, ITEM_COUNTER: 36, MINIMAP_DATA: 10, BOSS_SPAWNED: 37, BOSS_KILLED: 21, cy: 23, // some shit with text rendering HANDSHAKE: 12, // some hash shit Ui: 7, // some server event or boss shit CLAN_MESSAGE: 18 }; const SocketClient = { VERIFICATION: 11, MOVE_BITMASK: 6, UPDATE_ANGLE: 13, SELECT_BY_ID: 2, START_ATTACK: 19, STOP_ATTACK: 18, LOGIN: 10, UPGRADE_SCYTHE: 20, SELECT_BY_TYPE: 0, SWITCH_HAT: 5, CHAT: 7, UPGRADE_ITEM: 14, Ri: 12, // not used in the code PING_CALLBACK: 3, TOGGLE_AUTOATTACK: 23, MOVE_ANGLE: 1, STOP_MOVEMENT: 15, touchAttackStart: 9, Wi: 4, // not used in the code touchAttackStop: 8, // some shit with angle LEAVE_CLAN: 24, JOIN_CLAN: 21, ACCEPT_DECLINE: 17, KICK: 25, CREATE_CLAN: 22, io: 16, // not used in the code } class PacketHandler { constructor(client) { this.client = client; } encoder = new TextEncoder(); sendData(data) { const socket = this.client.SocketManager.socket; if (socket !== null && socket.readyState === 1) { socket.send(data, true); } } sendString(data) { this.sendData(JSON.stringify(data)); } send(...bytes) { this.sendData(new Uint8Array(bytes)); } moveByBitmask(bitmask) { this.send(SocketClient.MOVE_BITMASK, bitmask); } updateAngle(angle) { this.send(SocketClient.UPDATE_ANGLE, ...encodeAngle(angle)); } selectByID(itemID) { this.send(SocketClient.SELECT_BY_ID, itemID); } attack(angle) { this.send(SocketClient.START_ATTACK, ...encodeAngle(angle)); } stopAttack() { this.send(SocketClient.STOP_ATTACK); } login(nickname = "", skin = "0", accessory = "0", back = "0", email = "", token = "") { this.sendString([SocketClient.LOGIN, nickname, skin + "", "FFFFFEEEEGGBBBAAA", accessory + "", email, token, back + ""]); } upgradeScythe(goldenCowID) { this.send(SocketClient.UPGRADE_SCYTHE, 255 & goldenCowID, goldenCowID >> 8); } selectItemByType(type) { this.send(SocketClient.SELECT_BY_TYPE, type); } switchHat(hat) { this.send(SocketClient.SWITCH_HAT, hat); } chat(message) { const bytes = this.encoder.encode(message); this.send(SocketClient.CHAT, ...bytes); } upgradeItem(id) { this.send(SocketClient.UPGRADE_ITEM, id); } pingCallback(value) { this.send(SocketClient.PING_CALLBACK, value); } autoAttack(state) { this.send(SocketClient.TOGGLE_AUTOATTACK, Number(state)); } moveByAngle(angle) { this.send(SocketClient.MOVE_ANGLE, ...encodeAngle(angle)); } stopMovement() { this.send(SocketClient.STOP_MOVEMENT); } touchAttackStart(angle) { this.send(SocketClient.touchAttackStart, ...encodeAngle(angle)); } touchAttackStop(angle) { this.send(SocketClient.touchAttackStop, ...encodeAngle(angle)); } leaveClan() { this.send(SocketClient.LEAVE_CLAN); } joinClan(id) { this.send(SocketClient.JOIN_CLAN, id); } acceptDecline(state) { this.send(SocketClient.ACCEPT_DECLINE, Number(state)); } kick(id) { this.send(SocketClient.KICK, id); } createClan(name) { const bytes = this.encoder.encode(name); this.send(SocketClient.CREATE_CLAN, ...bytes); } } class SocketManager { constructor(client) { this.client = client; this.socket = null; this.decoder = new TextDecoder(); } init(socket) { this.socket = socket; socket.addEventListener("message", event => { const data = event.data; if (typeof data === "string") { this.handleStringMessage(JSON.parse(data)); } else { this.handleByteMessage(new Uint8Array(data)); } }); const that = this; const _send = socket.send; socket.send = function(data, ignore) { if (!ignore && typeof data !== "string" && that.client.isOwner) { const { myPlayer, clients } = that.client; switch (data[0]) { case SocketClient.START_ATTACK: { const pos = InputHandler.cursorPosition(myPlayer.position); for (const client of clients) { const angle = client.myPlayer.position.angle(pos); client.PacketHandler.attack(angle); } break; } case SocketClient.STOP_ATTACK: { for (const client of clients) { client.PacketHandler.stopAttack(); } break; } case SocketClient.UPGRADE_ITEM: { const item = data[1]; that.client.myPlayer.upgradeItem(item); break; } } } return _send.call(this, data); } } selfMessage(data) { this.socket.onmessage({ data }); } handleStringMessage(data) { const { myPlayer, PlayerManager, PacketHandler } = this.client; switch (data[0]) { case SocketServer.MY_PLAYER_INIT: { const id = data[1]; const nickname = data[2]; // const ageXP = data[3]; const inventory = data[4]; const resources = data[5]; // const hatData = data[6]; // const someEvent = data[7]; //myPlayer.id = id; //myPlayer.nickname = nickname; //myPlayer.inGame = true; const { myPlayer } = this.client; myPlayer.id = id; myPlayer.inGame = true; //log("MY_PLAYER_INIT", id, nickname); break; } case SocketServer.PLAYER_SPAWNED: { const globalID = data[1]; const nickname = data[2]; //log("PLAYER_SPAWNED", globalID, nickname); break; } case SocketServer.LEADERBOARD: { for (const [id, score] of data[1]) { } break; } case SocketServer.DEFAULT_DATA: { const globalID = data[1]; // const serverSize = data[2]; const players = data[3]; // [globalID, nickname, id] const clanData = data[4]; // [clanID, ownerID, clanName] for (const [id, owner, name] of clanData) { PlayerManager.createClan(id, owner, name); } // const someState = data[5]; myPlayer.globalID = globalID; PlayerManager.playerData.set(globalID, myPlayer); log("DEFAULT_DATA", globalID, data); if (!this.client.isOwner) { this.client.connection(); } break; } case SocketServer.DAMAGE: { const damage = data[1]; const id = data[2]; const isHeal = data[3]; //log("DAMAGE", damage, id, isHeal); break; } case SocketServer.KILL_UPDATE: { const [ kills, nuggets ] = data[1]; //log("KILL_UPDATE", kills, nuggets); break; } case SocketServer.DIED: { myPlayer.reset(); if (!this.client.isOwner) { PacketHandler.login("Murka"); } //log("DIED"); break; } case SocketServer.KILL_MESSAGE: { const text = data[1]; // Killed (nickname) //log(text); break; } case SocketServer.UPGRADE: { const items = data[1]; /*for (const item of items) { }*/ myPlayer.handleUpgrade(items); break; } case SocketServer.HANDSHAKE: { const someHash = data[1]; if (!this.client.isOwner) { PacketHandler.sendData("");//window.solve(0)); } break; } default: { log("default data", data); break; } } } handleByteMessage(buffer) { const { myPlayer, PlayerManager, PacketHandler } = this.client; switch (buffer[0]) { case SocketServer.UPDATE_MOVEMENT: { for (let i=1;i<buffer.length;i+=19) { const type = buffer[i]; const globalID = buffer[i + 1]; const id = buffer[i + 2] | buffer[i + 3] << 8; const x = buffer[i + 4] | buffer[i + 5] << 8; const y = buffer[i + 6] | buffer[i + 7] << 8; const state = buffer[i + 8]; const angle = formatAngle(buffer[i + 9]); const item = buffer[i + 10]; const hat = buffer[i + 11]; const clanID = buffer[i + 12]; const health = buffer[i + 13]; const skin = buffer[i + 14]; const accessory = buffer[i + 15]; const rank = buffer[i + 16]; const back = buffer[i + 17]; const a9 = buffer[i + 18]; if (type === 0) { const player = PlayerManager.getPlayer(globalID); player.update(type, globalID, id, x, y, angle, health / 255 * 100, clanID); } } myPlayer.postTick(); break; } case SocketServer.UPDATE_INVENTORY: { for (let i=1;i<buffer.length;i++) { const id = buffer[i]; } break; } case SocketServer.CONNECT: { // executed only once const num = buffer[1]; // Necessary handshakre, otherwise the game wont let to connect if (!this.client.isOwner) { const bytes = hashing[9629](num, getRandomString(16)); const tokenBytes = new Array(24).fill(0); PacketHandler.send(SocketClient.VERIFICATION, num, ...bytes, ...tokenBytes); } break; } case SocketServer.ATTACK_ANIMATION: { for (let i=1;i<buffer.length;i+=5) { const type = buffer[i]; const id = buffer[i + 1] | buffer[i + 2] << 8; const isObject = buffer[3]; const weapon = buffer[4]; //log(type, id, isObject, weapon); } break; } case SocketServer.PLAYER_RESOURCES: { const b = buffer; const age = formatAge(b[1] | b[2] << 8 | b[3] << 16 | b[4] << 24); const food = b[5] | b[6] << 8 | b[7] << 16 | b[8] << 24; const wood = b[9] | b[10] << 8 | b[11] << 16 | b[12] << 24; const stone = b[13] | b[14] << 8 | b[15] << 16 | b[16] << 24; const gold = b[17] | b[18] << 8 | b[19] << 16 | b[20] << 24; myPlayer.handleStats(age, food, wood, stone, gold); break; } case SocketServer.UPDATE_STORE: { for (let i=1;i<buffer.length;i+=2) { const hatID = buffer[i]; const state = buffer[i + 1]; //log(hatID, state); } break; } case SocketServer.TEXT_MESSAGE: { const id = buffer[1] | buffer[2] << 8; const text = this.decoder.decode(buffer.subarray(3)); //log(id, text); break; } case SocketServer.CLEAR_UPGRADE: { //log("clear upgrade bar"); break; } case SocketServer.PING_REQUEST: { const value = buffer[1]; //log("PING_REQUEST", value); break; } case SocketServer.PING_RESPONSE: { const ping = buffer[1] | buffer[2] << 8; //myPlayer.ping = ping; //log("PING_RESPONSE", ping); break; } case SocketServer.CLAN_JOIN: { const clanID = buffer[1]; const isOwner = buffer[2]; /*myPlayer.clan.id = clanID; myPlayer.clan.isOwner = isOwner; myPlayer.clan.name = clanData.get(clanID).name; for (let i=3;i<buffer.length;i++) { const id = buffer[i]; if (id !== myPlayer.id) { myPlayer.clan.members.push(id); } }*/ //log("CLAN_JOIN", clanID, isOwner, buffer.slice(3)); break; } case SocketServer.CLAN_LEAVE: { /*myPlayer.clan.id = 0; myPlayer.clan.isOwner = 0; myPlayer.clan.members.length = 0; myPlayer.clan.name = "";*/ break; } case SocketServer.CLAN_CREATED: { const clanID = buffer[1]; const ownerID = buffer[2]; const clanName = this.decoder.decode(buffer.subarray(3)); PlayerManager.createClan(clanID, ownerID, clanName); //log("CLAN_CREATED", { clanID, ownerID, clanName }); break; } case SocketServer.CLAN_DELETED: { const clanID = buffer[1]; PlayerManager.clanData.delete(clanID); //log("CLAN_DELETED", { clanID }); break; } case SocketServer.JOIN_REQUEST: { const globalID = buffer[1]; myPlayer.joinRequests.push(globalID); break; } case SocketServer.CLAN_UPDATED: { /*const myPlayer = this.client.myPlayer; myPlayer.clan.members.length = 0; const clanID = buffer[1]; for (let i=2;i<buffer.length;i++) { const id = buffer[i]; if (id !== myPlayer.id) { myPlayer.clan.members.push(id); } } log("clan updated", myPlayer.clan);*/ break; } case SocketServer.ITEM_COUNTER: { break; } case SocketServer.MINIMAP_DATA: { for (let i=1;i<buffer.length;i+=3) { const id = buffer[i + 0]; const x = buffer[i + 1] / 255; const y = buffer[i + 2] / 255; //log("MINIMAP_DATA", id, x, y); } break; } case SocketServer.BOSS_SPAWNED: { const type = buffer[1]; const x = buffer[2] / 255; const y = buffer[3] / 255; //log("BOSS_SPAWNED", type, x, y); break; } case SocketServer.BOSS_KILLED: { //log("BOSS_KILLED", buffer); break; } case SocketServer.CLAN_MESSAGE: { const id = buffer[1] | buffer[2] << 8; const text = this.decoder.decode(buffer.subarray(3)); break; } default: { log("default byte", buffer); break; } } } } class PlayerClient { constructor(owner = null) { this.owner = owner; this.clients = new Set(); this.pendingJoins = new Set(); this.PacketHandler = new PacketHandler(this); this.SocketManager = new SocketManager(this); this.ModuleHandler = new ModuleHandler(this); this.myPlayer = new ClientPlayer(this); this.PlayerManager = new PlayerManager(this); } get isOwner() { return this.owner === null; } addClient(client) { this.clients.add(client); } removeClient(client) { this.clients.delete(client); } init(socket) { this.SocketManager.init(socket); } disconnect() { const socket = this.SocketManager.socket; if (socket !== null) { socket.close(); } } connection() { this.SocketManager.socket.dispatchEvent(new Event("connected")); } removeJoin(globalID) { this.pendingJoins.delete(globalID); this.myPlayer.joinRequests.shift(); if (this.isOwner) HookedArrays.joins.shift(); } } const _WebSocket = WebSocket; const playerClient = new PlayerClient(); const createClient = () => { const socket = new _WebSocket(playerClient.SocketManager.socket.url); socket.binaryType = "arraybuffer"; socket.onopen = () => { //log("Opened"); const client = new PlayerClient(playerClient); client.init(socket); const onconnect = () => { //log("Connected"); playerClient.addClient(client); client.PacketHandler.login("Murka"); } socket.addEventListener("connected", onconnect, { once: true }); socket.onclose = () => { log("Closed"); playerClient.removeClient(client); } } } window.SocketAPI = { myClient: playerClient, createClient, HookedArrays, } let hooked = false; const defaultHooks = () => { if (hooked) return; hooked = true; Array.prototype.push = new Proxy(Array.prototype.push, { apply(target, _this, args) { if (args[0] === 255) { HookedArrays.joins = _this; Array.prototype.push = target; return; } return target.apply(_this, args); } }); playerClient.SocketManager.selfMessage([SocketServer.JOIN_REQUEST, 255]); } window.WebSocket = new Proxy(WebSocket, { construct(target, args) { const socket = new target(...args); playerClient.init(socket); Object.defineProperty(socket, "onmessage", { set(callback) { delete socket.onmessage; socket.onmessage = callback; defaultHooks(); }, configurable: true }); return socket; } }); })(); /* Author: Мurkа Github: github.com/Murka007 Greasyfork: greasyforks.org/users/919633 Discord: discord.gg/cPRFdcZkeD */