bedrock-protocol/src/server.js
extremeheat a55eaddc98
Add packet dumper, new server example, internal client/server test (#4)
* Add packet dumper, configuable vanilla server, client events

* Fix server/client closing

* Add internal server test

* protocol: use WindowID types

* Add internal client/server test

* test timeout fixes

* client example updates

* update server example, use protocol updates
Server example with bedrock-provider
Use 64-bit varints for entity runtime ids

* fix internal test packet path
2021-03-26 05:19:08 -04:00

78 lines
2.6 KiB
JavaScript

const { EventEmitter } = require('events')
const { createDeserializer, createSerializer } = require('./transforms/serializer')
const { Player } = require('./serverPlayer')
const { RakServer } = require('./rak')
const Options = require('./options')
const debug = require('debug')('minecraft-protocol')
class Server extends EventEmitter {
constructor (options) {
super()
this.options = { ...Options.defaultOptions, ...options }
this.validateOptions()
this.serializer = createSerializer(this.options.version)
this.deserializer = createDeserializer(this.options.version)
/** @type {Object<string, Player>} */
this.clients = {}
this.clientCount = 0
this.inLog = (...args) => debug('S ->', ...args)
this.outLog = (...args) => debug('S <-', ...args)
}
validateOptions () {
if (!Options.Versions[this.options.version]) {
console.warn('Supported versions: ', Options.Versions)
throw Error(`Unsupported version ${this.options.version}`)
}
this.options.protocolVersion = Options.Versions[this.options.version]
if (this.options.protocolVersion < Options.MIN_VERSION) {
throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`)
}
}
onOpenConnection = (conn) => {
this.inLog('new connection', conn)
const player = new Player(this, conn)
this.clients[conn.address] = player
this.clientCount++
this.emit('connect', player)
}
onCloseConnection = (inetAddr, reason) => {
console.debug('close connection', inetAddr, reason)
delete this.clients[inetAddr]?.connection // Prevent close loop
this.clients[inetAddr]?.close()
delete this.clients[inetAddr]
this.clientCount--
}
onEncapsulated = (buffer, address) => {
// this.inLog('encapsulated', address, buffer)
const client = this.clients[address]
if (!client) {
throw new Error(`packet from unknown inet addr: ${address}`)
}
client.handle(buffer)
}
async listen (hostname = this.options.hostname, port = this.options.port) {
this.raknet = new RakServer({ hostname, port })
await this.raknet.listen()
console.debug('Listening on', hostname, port)
this.raknet.onOpenConnection = this.onOpenConnection
this.raknet.onCloseConnection = this.onCloseConnection
this.raknet.onEncapsulated = this.onEncapsulated
}
close (disconnectReason) {
for (const caddr in this.clients) {
const client = this.clients[caddr]
client.disconnect(disconnectReason)
}
this.raknet.close()
this.clients = {}
this.clientCount = 0
}
}
module.exports = { Server }