moomooio-client
Version:
MooMooIO-Client is a client-side wrapper API designed for the game MooMoo.io. This package aims to provide a simple yet powerful API for creating clones, mods, or plugins for MooMoo.io.
118 lines (91 loc) • 2.94 kB
text/typescript
import AntiKick from "./AntiKick";
import { decode } from "./ServerPackets";
import UnifyEmitter from "unify-emitter";
export interface MooMooIOConnectionEvents {
close: {
reason: string;
code: number;
};
error: null;
open: null;
message: ReturnType<typeof decode>;
rawMessage: Uint8Array;
deepSend: { data: Uint8Array; isTrusted: boolean };
send: Uint8Array;
}
export default class MooMooIOConnection extends UnifyEmitter<MooMooIOConnectionEvents> {
#trusted: Uint8Array | null = null;
#socket: WebSocket | null = null;
protected antiKick = new AntiKick();
connect(ip: string, token: string) {
const url = `wss://ip_${ip}.moomoo.io:8008/?gameIndex=0&token=${encodeURIComponent(token)}`;
this.use(new WebSocket(url));
}
disconnect() {
if (!this.#socket || this.#socket.readyState == this.#socket.CLOSED) return;
this.#socket.close();
}
destroy() {
this.#socket = null;
this.antiKick.destroy();
this.removeListeners();
}
/**
* Sends the specified data through the socket connection.
* @param data - The data to be sent as a Uint8Array.
* @returns A boolean value indicating if the request has been successfully sent.
*/
send(data: Uint8Array): boolean {
if (!this.#socket || this.#socket.readyState != this.#socket.OPEN) return false;
const canSend = data instanceof Uint8Array && this.antiKick.canSend(data);
if (canSend) {
this.#trusted = data;
this.#socket.send(data);
this.emit("send", data);
}
return canSend;
}
use(socket: WebSocket) {
this.socket = socket;
}
set socket(socket: WebSocket) {
if (socket instanceof WebSocket) {
this.#socket = socket;
this.#initializeSocket();
}
}
isOPEN() {
return this.#socket && this.#socket.readyState == this.#socket.OPEN;
}
#initializeSocket() {
if (!this.#socket) return;
this.#socket.binaryType = "arraybuffer";
this.#socket.addEventListener("message", (ev) => {
if (ev.data instanceof ArrayBuffer) {
this.emit("rawMessage", new Uint8Array(ev.data));
this.emit("message", decode(ev.data));
}
});
this.#socket.addEventListener("open", () => {
this.emit("open", null);
});
this.#socket.addEventListener("close", (ev) => {
this.emit("close", {
reason: ev.reason,
code: ev.code,
});
});
this.#socket.addEventListener("error", () => {
this.emit("error", null);
});
const oldSend = this.#socket.send.bind(this.#socket);
this.#socket.send = (data: Uint8Array) => {
const isTrusted = this.#trusted == data;
this.#trusted = null;
if (data instanceof Uint8Array) {
oldSend(data);
this.emit("deepSend", { data, isTrusted });
}
};
}
}