implement packet compression, implement player controller, implement join server authentication, add cobblestone, implement chunk provider, implement block position, implement session, implement movement, chunk, chat and block update packets, version 1.1.5
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import ByteBuf from "./util/ByteBuf.js";
|
||||
import PacketRegistry from "./PacketRegistry.js";
|
||||
import ProtocolState from "./ProtocolState.js";
|
||||
import {aesjs} from "../../../../../../libraries/aes.js";
|
||||
import {require} from "../../../../Start.js";
|
||||
|
||||
export default class NetworkManager {
|
||||
|
||||
static DEBUG = false;
|
||||
static MAX_COMPRESSION = 2097152;
|
||||
|
||||
constructor(minecraft) {
|
||||
this.minecraft = minecraft;
|
||||
this.socket = null;
|
||||
@@ -14,10 +17,10 @@ export default class NetworkManager {
|
||||
this.registry = new PacketRegistry();
|
||||
this.protocolState = ProtocolState.HANDSHAKE;
|
||||
|
||||
this.readBuffer = new ByteBuf();
|
||||
this.expectedLength = -1;
|
||||
|
||||
this.queue = [];
|
||||
|
||||
this.pako = require("pako");
|
||||
this.compressionThreshold = 0;
|
||||
}
|
||||
|
||||
setNetworkHandler(networkHandler) {
|
||||
@@ -41,11 +44,10 @@ export default class NetworkManager {
|
||||
this.connected = true;
|
||||
|
||||
// Send proxy handshake
|
||||
let object = {
|
||||
"address": this.address,
|
||||
this.sendProxyPacket(0, {
|
||||
"host": this.address,
|
||||
"port": this.port,
|
||||
};
|
||||
this.socket.send(JSON.stringify(object));
|
||||
});
|
||||
|
||||
// Handle connect event
|
||||
this.networkHandler.onConnect();
|
||||
@@ -54,6 +56,14 @@ export default class NetworkManager {
|
||||
this.flushPacketQueue();
|
||||
}
|
||||
|
||||
sendProxyPacket(id, payload) {
|
||||
let object = {
|
||||
"id": id,
|
||||
"payload": payload
|
||||
};
|
||||
this.socket.send(JSON.stringify(object));
|
||||
}
|
||||
|
||||
sendPacket(packet) {
|
||||
if (this.connected) {
|
||||
this._sendPacketImmediately(packet);
|
||||
@@ -67,81 +77,138 @@ export default class NetworkManager {
|
||||
let packetState = this.registry.getPacketState(packet);
|
||||
if (packetState !== this.protocolState) {
|
||||
if (packetState === null) {
|
||||
console.error("[Network] Tried to send unknown packet: " + packet);
|
||||
console.error("[Network] Tried to send unknown packet: " + packet.constructor.name);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[Network] Switching protocol state from " + ProtocolState.getName(this.protocolState) + " to " + ProtocolState.getName(packetState));
|
||||
this.protocolState = packetState;
|
||||
this.setState(packetState);
|
||||
}
|
||||
|
||||
// Write packet to buffer
|
||||
// Packet Codec
|
||||
let buffer = new ByteBuf();
|
||||
buffer.writeByte(this.registry.getClientBoundPacketId(this.protocolState, packet));
|
||||
packet.write(buffer);
|
||||
buffer.setPosition(0);
|
||||
|
||||
// Write chunk header
|
||||
let array = buffer.getArray();
|
||||
// Packet Compression
|
||||
if (this.compressionThreshold !== 0) {
|
||||
let length = buffer.length();
|
||||
if (length > this.compressionThreshold) {
|
||||
let compressed = this.pako.deflate(buffer.getArray(), {
|
||||
chunkSize: 8192
|
||||
});
|
||||
|
||||
buffer = new ByteBuf();
|
||||
buffer.writeVarInt(length);
|
||||
buffer.write(compressed);
|
||||
} else {
|
||||
let copy = buffer.getArray();
|
||||
buffer = new ByteBuf();
|
||||
buffer.writeVarInt(0);
|
||||
buffer.write(copy);
|
||||
}
|
||||
buffer.setPosition(0);
|
||||
}
|
||||
|
||||
// Packet Sizer
|
||||
let wrapper = new ByteBuf();
|
||||
wrapper.writeVarInt(array.length);
|
||||
wrapper.write(array);
|
||||
let chunk = wrapper.getArray().buffer;
|
||||
wrapper.writeVarInt(buffer.length());
|
||||
wrapper.write(buffer.getArray());
|
||||
|
||||
// Encrypt chunk
|
||||
// Packet Compression
|
||||
if (this.isEncrypted) {
|
||||
chunk = this.encryption.encrypt(new Uint8Array(chunk));
|
||||
wrapper = new ByteBuf(this.encryption.encrypt(wrapper.getArray()));
|
||||
}
|
||||
|
||||
// Send chunk
|
||||
this.socket.send(chunk);
|
||||
this.socket.send(wrapper.getArray());
|
||||
|
||||
console.log("[Network] [OUT] " + packet.constructor.name);
|
||||
if (NetworkManager.DEBUG) {
|
||||
console.log("[Network] [OUT] " + packet.constructor.name);
|
||||
}
|
||||
}
|
||||
|
||||
_onMessage(event) {
|
||||
let chunk = new Int8Array(event.data);
|
||||
try {
|
||||
let data = new Uint8Array(event.data);
|
||||
|
||||
// Decrypt chunk
|
||||
if (this.isEncrypted) {
|
||||
chunk = this.encryption.decrypt(new Uint8Array(event.data));
|
||||
}
|
||||
// Packet Compression
|
||||
if (this.isEncrypted) {
|
||||
data = this.decryption.decrypt(data);
|
||||
}
|
||||
|
||||
// Read packet header
|
||||
if (this.expectedLength === -1) {
|
||||
let buf = new ByteBuf(chunk);
|
||||
this.expectedLength = buf.readVarInt(); // Read packet length
|
||||
this.readBuffer.setPosition(0);
|
||||
chunk = chunk.slice(buf.getPosition());
|
||||
}
|
||||
// Packet Sizer
|
||||
let bufferIn = new ByteBuf(new Int8Array(data));
|
||||
while (bufferIn.readableBytes() > 0) {
|
||||
let three = [0, 0, 0];
|
||||
for (let i = 0; i < three.length; i++) {
|
||||
three[i] = bufferIn.readByte();
|
||||
if (three[i] >= 0) {
|
||||
let length = new ByteBuf(three).readVarInt();
|
||||
if (length === 0) {
|
||||
throw new Error("Empty Packet!");
|
||||
}
|
||||
|
||||
// Fill packet content
|
||||
this.readBuffer.write(chunk);
|
||||
|
||||
// Handle packet
|
||||
if (this.readBuffer.getPosition() >= this.expectedLength) {
|
||||
this.expectedLength = -1;
|
||||
this.readBuffer.setPosition(0);
|
||||
this.onPacketBufferReceived(this.readBuffer);
|
||||
if (bufferIn.readableBytes() < length) {
|
||||
break;
|
||||
} else {
|
||||
this.handlePacket(new ByteBuf(bufferIn.getSlicedArray(length)));
|
||||
bufferIn.skipBytes(length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
onPacketBufferReceived(buffer) {
|
||||
handlePacket(buffer) {
|
||||
// Packet Compression
|
||||
if (this.compressionThreshold !== 0) {
|
||||
let uncompressedLength = buffer.readVarInt();
|
||||
|
||||
if (uncompressedLength !== 0) {
|
||||
if (uncompressedLength < this.compressionThreshold) {
|
||||
throw new Error("Badly compressed packet - size of " + uncompressedLength + " is below server threshold of " + this.compressionThreshold);
|
||||
}
|
||||
if (uncompressedLength > NetworkManager.MAX_COMPRESSION) {
|
||||
throw new Error("Badly compressed packet - size of " + uncompressedLength + " is larger than protocol maximum of " + NetworkManager.MAX_COMPRESSION);
|
||||
}
|
||||
|
||||
// Decompress
|
||||
buffer = new ByteBuf(this.pako.inflate(new Uint8Array(buffer.getSlicedArray()), {
|
||||
chunkSize: 8192
|
||||
}));
|
||||
|
||||
if (buffer.length() !== uncompressedLength) {
|
||||
throw new Error("Badly compressed packet - decompressed size of " + buffer.length() + " is not equal to original size of " + uncompressedLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Packet Codec
|
||||
let packetId = buffer.readByte(); // Read packet id
|
||||
let clazz = this.registry.getServerBoundById(this.protocolState, packetId);
|
||||
if (clazz === null) {
|
||||
console.log("[Network] Unknown packet id: " + packetId);
|
||||
if (NetworkManager.DEBUG) {
|
||||
console.log("[Network] [IN] Unknown packet id: " + packetId + " (0x" + packetId.toString(16) + ")");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (NetworkManager.DEBUG) {
|
||||
console.log("[Network] [IN] " + clazz.name);
|
||||
}
|
||||
}
|
||||
|
||||
let packet = new clazz;
|
||||
console.log("[Network] [IN] " + packet.constructor.name);
|
||||
|
||||
packet.read(buffer, buffer.length);
|
||||
packet.handle(this.networkHandler);
|
||||
}
|
||||
|
||||
_onError(event) {
|
||||
|
||||
console.error("[Network] Error: " + event.data);
|
||||
}
|
||||
|
||||
_onClose(event) {
|
||||
@@ -164,6 +231,26 @@ export default class NetworkManager {
|
||||
|
||||
enableEncryption(secretKey) {
|
||||
this.isEncrypted = true;
|
||||
this.encryption = new aesjs.ModeOfOperation.cfb(secretKey, secretKey, 1);
|
||||
this.decryption = new (require("aesjs").ModeOfOperation).cfb(secretKey, secretKey, 1);
|
||||
this.encryption = new (require("aesjs").ModeOfOperation).cfb(secretKey, secretKey, 1);
|
||||
}
|
||||
|
||||
setState(packetState) {
|
||||
console.log("[Network] Switching protocol state from " + this.protocolState.getName() + " to " + packetState.getName());
|
||||
this.protocolState = packetState;
|
||||
}
|
||||
|
||||
getState() {
|
||||
return this.protocolState;
|
||||
}
|
||||
|
||||
setCompressionThreshold(threshold) {
|
||||
console.log("[Network] Set compression threshold to " + threshold);
|
||||
|
||||
if (threshold >= 0) {
|
||||
this.compressionThreshold = threshold;
|
||||
} else {
|
||||
this.compressionThreshold = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user