-
Notifications
You must be signed in to change notification settings - Fork 27
/
client.ts
95 lines (89 loc) · 3.27 KB
/
client.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import * as ByteBuffer from "bytebuffer";
import { EventEmitter } from "events";
import { Socket } from "net";
import { Server } from "./server";
function writeString(buff: ByteBuffer, s: string) {
buff.writeVarint32(s.length);
buff.writeUTF8String(s);
}
function handshake(host: string, port: number, connection: Socket) {
return new Promise<string>((resolve, reject) => {
const buffer = ByteBuffer.allocate(256);
// packet id
buffer.writeByte(0x00);
// protocol version
buffer.writeVarint32(210);
writeString(buffer, host);
buffer.writeShort(port & 0xffff);
buffer.writeVarint32(1);
buffer.flip();
const handshakeBuf = ByteBuffer.allocate(buffer.limit + 8);
handshakeBuf.writeVarint32(buffer.limit);
handshakeBuf.append(buffer);
handshakeBuf.flip();
connection.write(Buffer.from(handshakeBuf.toArrayBuffer()));
connection.write(Buffer.from([0x01, 0x00]));
let remain: number | undefined;
let msg: ByteBuffer;
const listener = (incoming: Buffer) => {
const inbuf = ByteBuffer.wrap(incoming);
if (remain === undefined) {
remain = inbuf.readVarint32();
msg = ByteBuffer.allocate(remain);
remain -= inbuf.remaining();
msg.append(inbuf.slice(inbuf.offset));
} else {
msg.append(inbuf);
remain -= inbuf.limit;
if (remain <= 0) {
connection.removeListener("data", listener);
msg.flip();
const id = msg.readVarint32();
const length = msg.readVarint32();
const u8 = msg.slice(msg.offset).toUTF8();
resolve(u8);
}
}
};
connection.on("data", listener);
connection.once("error", (error) => {
reject(error);
});
});
}
export type Handler = (buffer: ByteBuffer) => void;
const internalHandlers = {
0x00: {
accept(buffer: ByteBuffer): void {
},
},
};
export class MinecraftConnection extends EventEmitter {
private cache: ByteBuffer | undefined;
private remaining: number = -1;
constructor(readonly host: string, readonly port: number,
private connection: Socket, private cachedStatus: Server.Status) {
super();
connection.on("data", this.handlePacket);
}
on(event: "packet", listener: Handler): this {
return super.on(event, listener);
}
private handlePacket(buffer: Buffer) {
if (!this.cache) {
const incoming = ByteBuffer.wrap(buffer);
this.remaining = incoming.readVarint32();
this.cache = ByteBuffer.allocate(this.remaining);
this.remaining -= incoming.remaining();
this.cache.append(incoming.slice(incoming.offset));
} else {
this.cache.append(buffer);
this.remaining -= buffer.byteLength;
if (this.remaining <= 0) {
const packetId = this.cache.readByte();
this.emit("packet", this.cache.slice(this.cache.offset));
// handler.accept(this.cache.slice(this.cache.offset))
}
}
}
}