@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
121 lines (120 loc) • 13.2 kB
JavaScript
;
Object.defineProperties(exports, {
__esModule: { value: true },
[Symbol.toStringTag]: { value: "Module" }
});
const require_utils_Timer = require("../utils/Timer.cjs.cjs");
const require_network_Identifiers = require("./Identifiers.cjs.cjs");
const require_network_Packets = require("./Packets.cjs.cjs");
const require_network_Handlers = require("./Handlers.cjs.cjs");
//#region src/network/PacketRegistry.ts
var PacketRegistry = class {
server;
packets = /* @__PURE__ */ new Map();
handlers = /* @__PURE__ */ new Map();
constructor(server) {
this.server = server;
}
/**
* On enable hook.
* @group Lifecycle
*/
async enable() {
await this.registerPackets();
await this.registerHandlers();
}
/**
* On disable hook.
* @group Lifecycle
*/
async disable() {
this.handlers.clear();
this.packets.clear();
}
/**
* Register a packet.
* @param packet - the packet.
*/
registerPacket(packet) {
if (this.packets.has(packet.NetID)) throw new Error(`Packet ${packet.name} is trying to use id ${packet.NetID.toString(16)} which already exists!`);
this.packets.set(packet.NetID, packet);
this.server.getLogger().debug(`Packet with id §b${packet.name}§r registered`);
}
/**
* Get a packet by it's network ID.
* @param id - the NetID.
*/
getPacket(id) {
if (!this.packets.has(id)) throw new Error(`Invalid packet with id ${id}!`);
return this.packets.get(id);
}
/**
* Remove a packet from the registry.
* @param id - the NetID.
*/
removePacket(id) {
this.packets.delete(id);
}
registerHandler(id, handler) {
if (this.handlers.has(id)) throw new Error(`Handler with id ${id} already exists!`);
this.handlers.set(id, handler);
this.server.getLogger().debug(`Handler with id §b${handler.constructor.name}§r registered`, "PacketRegistry/registerHandler");
}
getHandler(id) {
if (!this.handlers.has(id)) throw new Error(`Invalid handler with id ${id.toString(16)}!`);
return this.handlers.get(id);
}
/**
* Merge two handlers.
* This is useful if you want to extend a handler without actually replacing it.
*
* @param handler - the first handler, executed first.
* @param handler2 - the second handler.
*/
appendHandler(handler, handler2) {
return new class Handler {
async handle(packet, server, session) {
await handler.handle(packet, server, session);
await handler2.handle(packet, server, session);
}
}();
}
/**
* Remove a handler from the registry.
* @param id - the handler id.
*/
removeHandler(id) {
this.handlers.delete(id);
}
/**
* Dynamically register all packets exported by './Protocol'.
*/
async registerPackets() {
const timer = new require_utils_Timer.default();
Object.entries(require_network_Packets.Packets_exports).filter(([, value]) => value.name !== "DataPacket" && value.name !== "BatchPacket").map(([, value]) => this.registerPacket(value));
this.server.getLogger().verbose(`Registered §b${this.packets.size}§r of §b${Array.from(Object.keys(require_network_Identifiers.default)).length - 2}§r packet(s) (took §e${timer.stop()} ms§r)!`);
}
/**
* Dynamically register all handlers exported by './Handlers'.
*/
async registerHandlers() {
const timer = new require_utils_Timer.default();
Object.entries(require_network_Handlers.Handlers_exports).map(([, value]) => this.registerHandler(value.NetID, new value()));
this.server.getLogger().verbose(`Registered §b${this.handlers.size}§r packet handler(s) (took §e${timer.stop()} ms§r)!`);
}
/**
* Get all packets from the registry.
*/
getPackets() {
return this.packets;
}
/**
* Get all handlers from the registry.
*/
getHandlers() {
return this.handlers;
}
};
//#endregion
exports.default = PacketRegistry;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFja2V0UmVnaXN0cnkuY2pzLmNqcyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi9zcmMvbmV0d29yay9QYWNrZXRSZWdpc3RyeS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBIYW5kbGVycyBmcm9tICcuL0hhbmRsZXJzJztcbmltcG9ydCAqIGFzIFBhY2tldHMgZnJvbSAnLi9QYWNrZXRzJztcblxuaW1wb3J0IHR5cGUgeyBQbGF5ZXJTZXNzaW9uIH0gZnJvbSAnLi4vJztcbmltcG9ydCB0eXBlIFNlcnZlciBmcm9tICcuLi9TZXJ2ZXInO1xuaW1wb3J0IFRpbWVyIGZyb20gJy4uL3V0aWxzL1RpbWVyJztcbmltcG9ydCBJZGVudGlmaWVycyBmcm9tICcuL0lkZW50aWZpZXJzJztcbmltcG9ydCB0eXBlIFBhY2tldEhhbmRsZXIgZnJvbSAnLi9oYW5kbGVyL1BhY2tldEhhbmRsZXInO1xuaW1wb3J0IHR5cGUgUHJlTG9naW5QYWNrZXRIYW5kbGVyIGZyb20gJy4vaGFuZGxlci9QcmVMb2dpblBhY2tldEhhbmRsZXInO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBQYWNrZXRSZWdpc3RyeSB7XG4gICAgcHJpdmF0ZSBzZXJ2ZXI6IFNlcnZlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBhY2tldHM6IE1hcDxudW1iZXIsIHR5cGVvZiBQYWNrZXRzLkRhdGFQYWNrZXQ+ID0gbmV3IE1hcCgpO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlcnM6IE1hcDxudW1iZXIsIFBhY2tldEhhbmRsZXI8YW55Pj4gPSBuZXcgTWFwKCk7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioc2VydmVyOiBTZXJ2ZXIpIHtcbiAgICAgICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogT24gZW5hYmxlIGhvb2suXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBlbmFibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVnaXN0ZXJQYWNrZXRzKCk7XG4gICAgICAgIGF3YWl0IHRoaXMucmVnaXN0ZXJIYW5kbGVycygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE9uIGRpc2FibGUgaG9vay5cbiAgICAgKiBAZ3JvdXAgTGlmZWN5Y2xlXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGRpc2FibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuaGFuZGxlcnMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5wYWNrZXRzLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVnaXN0ZXIgYSBwYWNrZXQuXG4gICAgICogQHBhcmFtIHBhY2tldCAtIHRoZSBwYWNrZXQuXG4gICAgICovXG4gICAgcHVibGljIHJlZ2lzdGVyUGFja2V0KHBhY2tldDogdHlwZW9mIFBhY2tldHMuRGF0YVBhY2tldCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5wYWNrZXRzLmhhcyhwYWNrZXQuTmV0SUQpKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgIGBQYWNrZXQgJHtwYWNrZXQubmFtZX0gaXMgdHJ5aW5nIHRvIHVzZSBpZCAke3BhY2tldC5OZXRJRC50b1N0cmluZygxNil9IHdoaWNoIGFscmVhZHkgZXhpc3RzIWBcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5wYWNrZXRzLnNldChwYWNrZXQuTmV0SUQsIHBhY2tldCk7XG4gICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmRlYnVnKGBQYWNrZXQgd2l0aCBpZCDCp2Ike3BhY2tldC5uYW1lfcKnciByZWdpc3RlcmVkYCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGEgcGFja2V0IGJ5IGl0J3MgbmV0d29yayBJRC5cbiAgICAgKiBAcGFyYW0gaWQgLSB0aGUgTmV0SUQuXG4gICAgICovXG4gICAgcHVibGljIGdldFBhY2tldChpZDogbnVtYmVyKTogYW55IHtcbiAgICAgICAgaWYgKCF0aGlzLnBhY2tldHMuaGFzKGlkKSkgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhY2tldCB3aXRoIGlkICR7aWR9IWApO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnBhY2tldHMuZ2V0KGlkKSE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGEgcGFja2V0IGZyb20gdGhlIHJlZ2lzdHJ5LlxuICAgICAqIEBwYXJhbSBpZCAtIHRoZSBOZXRJRC5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlUGFja2V0KGlkOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5wYWNrZXRzLmRlbGV0ZShpZCk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlZ2lzdGVySGFuZGxlcihpZDogbnVtYmVyLCBoYW5kbGVyOiBQYWNrZXRIYW5kbGVyPGFueT4pOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuaGFuZGxlcnMuaGFzKGlkKSkgdGhyb3cgbmV3IEVycm9yKGBIYW5kbGVyIHdpdGggaWQgJHtpZH0gYWxyZWFkeSBleGlzdHMhYCk7XG5cbiAgICAgICAgdGhpcy5oYW5kbGVycy5zZXQoaWQsIGhhbmRsZXIpO1xuICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgLmdldExvZ2dlcigpXG4gICAgICAgICAgICAuZGVidWcoYEhhbmRsZXIgd2l0aCBpZCDCp2Ike2hhbmRsZXIuY29uc3RydWN0b3IubmFtZX3Cp3IgcmVnaXN0ZXJlZGAsICdQYWNrZXRSZWdpc3RyeS9yZWdpc3RlckhhbmRsZXInKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SGFuZGxlcihpZDogbnVtYmVyKTogUGFja2V0SGFuZGxlcjxhbnk+IHwgUHJlTG9naW5QYWNrZXRIYW5kbGVyPGFueT4ge1xuICAgICAgICBpZiAoIXRoaXMuaGFuZGxlcnMuaGFzKGlkKSkgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGhhbmRsZXIgd2l0aCBpZCAke2lkLnRvU3RyaW5nKDE2KX0hYCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuaGFuZGxlcnMuZ2V0KGlkKSE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWVyZ2UgdHdvIGhhbmRsZXJzLlxuICAgICAqIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGV4dGVuZCBhIGhhbmRsZXIgd2l0aG91dCBhY3R1YWxseSByZXBsYWNpbmcgaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gaGFuZGxlciAtIHRoZSBmaXJzdCBoYW5kbGVyLCBleGVjdXRlZCBmaXJzdC5cbiAgICAgKiBAcGFyYW0gaGFuZGxlcjIgLSB0aGUgc2Vjb25kIGhhbmRsZXIuXG4gICAgICovXG4gICAgcHVibGljIGFwcGVuZEhhbmRsZXIoaGFuZGxlcjogUGFja2V0SGFuZGxlcjxhbnk+LCBoYW5kbGVyMjogUGFja2V0SGFuZGxlcjxhbnk+KTogUGFja2V0SGFuZGxlcjxhbnk+IHtcbiAgICAgICAgY29uc3QgcmVzID0gbmV3IChjbGFzcyBIYW5kbGVyIHtcbiAgICAgICAgICAgIHB1YmxpYyBhc3luYyBoYW5kbGUocGFja2V0OiBhbnksIHNlcnZlcjogU2VydmVyLCBzZXNzaW9uOiBQbGF5ZXJTZXNzaW9uKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgaGFuZGxlci5oYW5kbGUocGFja2V0LCBzZXJ2ZXIsIHNlc3Npb24pO1xuICAgICAgICAgICAgICAgIGF3YWl0IGhhbmRsZXIyLmhhbmRsZShwYWNrZXQsIHNlcnZlciwgc2Vzc2lvbik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG5cbiAgICAgICAgcmV0dXJuIHJlcyBhcyBQYWNrZXRIYW5kbGVyPGFueT47XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGEgaGFuZGxlciBmcm9tIHRoZSByZWdpc3RyeS5cbiAgICAgKiBAcGFyYW0gaWQgLSB0aGUgaGFuZGxlciBpZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlSGFuZGxlcihpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMuaGFuZGxlcnMuZGVsZXRlKGlkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEeW5hbWljYWxseSByZWdpc3RlciBhbGwgcGFja2V0cyBleHBvcnRlZCBieSAnLi9Qcm90b2NvbCcuXG4gICAgICovXG4gICAgcHJpdmF0ZSBhc3luYyByZWdpc3RlclBhY2tldHMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHRpbWVyID0gbmV3IFRpbWVyKCk7XG5cbiAgICAgICAgLy8gRHluYW1pY2FsbHkgcmVnaXN0ZXIgcGFja2V0c1xuICAgICAgICAvLyBXZSBuZWVkIHRvIG1hbnVhbGx5IGlnbm9yZSBEYXRhUGFja2V0ICYgQmF0Y2hQYWNrZXRcbiAgICAgICAgT2JqZWN0LmVudHJpZXMoUGFja2V0cylcbiAgICAgICAgICAgIC5maWx0ZXIoKFssIHZhbHVlXSkgPT4gdmFsdWUubmFtZSAhPT0gJ0RhdGFQYWNrZXQnICYmIHZhbHVlLm5hbWUgIT09ICdCYXRjaFBhY2tldCcpXG4gICAgICAgICAgICAubWFwKChbLCB2YWx1ZV0pID0+IHRoaXMucmVnaXN0ZXJQYWNrZXQodmFsdWUpKTtcblxuICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgLmdldExvZ2dlcigpXG4gICAgICAgICAgICAudmVyYm9zZShcbiAgICAgICAgICAgICAgICBgUmVnaXN0ZXJlZCDCp2Ike3RoaXMucGFja2V0cy5zaXplfcKnciBvZiDCp2Ike1xuICAgICAgICAgICAgICAgICAgICBBcnJheS5mcm9tKE9iamVjdC5rZXlzKElkZW50aWZpZXJzKSkubGVuZ3RoIC0gMlxuICAgICAgICAgICAgICAgIH3Cp3IgcGFja2V0KHMpICh0b29rIMKnZSR7dGltZXIuc3RvcCgpfSBtc8KncikhYFxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEeW5hbWljYWxseSByZWdpc3RlciBhbGwgaGFuZGxlcnMgZXhwb3J0ZWQgYnkgJy4vSGFuZGxlcnMnLlxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgcmVnaXN0ZXJIYW5kbGVycygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgdGltZXIgPSBuZXcgVGltZXIoKTtcblxuICAgICAgICAvLyBEeW5hbWljYWxseSByZWdpc3RlciBoYW5kbGVyc1xuICAgICAgICBPYmplY3QuZW50cmllcyhIYW5kbGVycykubWFwKChbLCB2YWx1ZV0pID0+IHRoaXMucmVnaXN0ZXJIYW5kbGVyKHZhbHVlLk5ldElEISwgbmV3ICh2YWx1ZSBhcyBhbnkpKCkpKTtcblxuICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgLmdldExvZ2dlcigpXG4gICAgICAgICAgICAudmVyYm9zZShgUmVnaXN0ZXJlZCDCp2Ike3RoaXMuaGFuZGxlcnMuc2l6ZX3Cp3IgcGFja2V0IGhhbmRsZXIocykgKHRvb2sgwqdlJHt0aW1lci5zdG9wKCl9IG1zwqdyKSFgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIHBhY2tldHMgZnJvbSB0aGUgcmVnaXN0cnkuXG4gICAgICovXG4gICAgcHVibGljIGdldFBhY2tldHMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBhY2tldHM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBoYW5kbGVycyBmcm9tIHRoZSByZWdpc3RyeS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0SGFuZGxlcnMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmhhbmRsZXJzO1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQVVBLElBQXFCLGlCQUFyQixNQUFvQztDQUNoQztDQUNBLDBCQUFtRSxJQUFJLElBQUk7Q0FDM0UsMkJBQTZELElBQUksSUFBSTtDQUVyRSxZQUFtQixRQUFnQjtFQUMvQixLQUFLLFNBQVM7Q0FDbEI7Ozs7O0NBTUEsTUFBYSxTQUF3QjtFQUNqQyxNQUFNLEtBQUssZ0JBQWdCO0VBQzNCLE1BQU0sS0FBSyxpQkFB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