UNPKG

@colyseus/core

Version:

Multiplayer Framework for Node.js.

264 lines (262 loc) 9.69 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/core/src/Server.ts var Server_exports = {}; __export(Server_exports, { Server: () => Server, defineRoom: () => defineRoom, defineServer: () => defineServer, registerRoomDefinitions: () => registerRoomDefinitions, unregisterRoomDefinitions: () => unregisterRoomDefinitions }); module.exports = __toCommonJS(Server_exports); var import_greeting_banner = require("@colyseus/greeting-banner"); var import_Debug = require("./Debug.cjs"); var matchMaker = __toESM(require("./MatchMaker.cjs"), 1); var import_RegisteredHandler = require("./matchmaker/RegisteredHandler.cjs"); var import_Room = require("./Room.cjs"); var import_Utils = require("./utils/Utils.cjs"); var import_Transport = require("./Transport.cjs"); var import_Logger = require("./Logger.cjs"); var import_DevMode = require("./utils/DevMode.cjs"); var import_router = require("./router/index.cjs"); var import_shared_types = require("@colyseus/shared-types"); var import_default_routes = require("./router/default_routes.cjs"); var Server = class { constructor(options = {}) { this._onTransportReady = new import_Utils.Deferred(); this._originalRoomOnMessage = null; this.onShutdownCallback = () => Promise.resolve(); this.onBeforeShutdownCallback = () => Promise.resolve(); const { gracefullyShutdown: gracefullyShutdown2 = true, greet: greet2 = true } = options; (0, import_DevMode.setDevMode)(options.devMode === true); this.options = options; this.greet = greet2; this.attach(options); matchMaker.setup( options.presence, options.driver, options.publicAddress, options.selectProcessIdToCreateRoom ).then(() => { this.presence = matchMaker.presence; this.driver = matchMaker.driver; }); if (gracefullyShutdown2) { (0, import_Utils.registerGracefulShutdown)((err) => this.gracefullyShutdown(true, err)); } if (options.logger) { (0, import_Logger.setLogger)(options.logger); } } async attach(options) { this.transport = options.transport || await this.getDefaultTransport(options); if (options.express && this.transport.getExpressApp) { const expressApp = await this.transport.getExpressApp(); await options.express(expressApp); } this._onTransportReady.resolve(this.transport); } /** * Bind the server into the port specified. * * @param port - Port number or Unix socket path * @param hostname * @param backlog * @param listeningListener */ async listen(port, hostname, backlog, listeningListener) { if (this.options.beforeListen) { await this.options.beforeListen(); } if (process.env.COLYSEUS_CLOUD !== void 0) { if (typeof hostname === "number") { hostname = void 0; } else { try { return (await (0, import_Utils.dynamicImport)("@colyseus/tools")).listen(this); } catch (error) { const err = new Error("Please install @colyseus/tools to be able to host on Colyseus Cloud."); err.cause = error; throw err; } } } this.port = port; await matchMaker.accept(this.options.isStandaloneMatchMaker); if (this.greet) { (0, import_greeting_banner.greet)(); } await this._onTransportReady; return new Promise((resolve, reject) => { (0, import_Transport.setTransport)(this.transport); this.transport.listen(port, hostname, backlog, (err) => { if (this.transport.server) { this.transport.server.on("error", (err2) => reject(err2)); } if (!this.router) { this.router = (0, import_default_routes.getDefaultRouter)(); } else { this.router = this.router.extend({ ...(0, import_default_routes.getDefaultRouter)().endpoints }); } (0, import_router.bindRouterToTransport)(this.transport, this.router, this.options.express !== void 0); if (listeningListener) { listeningListener(err); } if (err) { reject(err); } else { resolve(); } }); }); } define(nameOrHandler, handlerOrOptions, defaultOptions) { const name = typeof nameOrHandler === "string" ? nameOrHandler : nameOrHandler.name; const roomClass = typeof nameOrHandler === "string" ? handlerOrOptions : nameOrHandler; const options = typeof nameOrHandler === "string" ? defaultOptions : handlerOrOptions; return matchMaker.defineRoomType(name, roomClass, options); } /** * Remove a room definition from matchmaking. * This method does not destroy any room. It only dissallows matchmaking */ removeRoomType(name) { matchMaker.removeRoomType(name); } async gracefullyShutdown(exit = true, err) { if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) { return; } try { await this.onBeforeShutdownCallback(); await matchMaker.gracefullyShutdown(); this.transport.shutdown(); this.presence?.shutdown(); await this.driver?.shutdown(); await this.onShutdownCallback(); } catch (e) { (0, import_Debug.debugAndPrintError)(`error during shutdown: ${e}`); } finally { if (exit) { process.exit(err && !import_DevMode.isDevMode ? 1 : 0); } } } /** * Add simulated latency between client and server. * @param milliseconds round trip latency in milliseconds. */ simulateLatency(milliseconds) { if (milliseconds > 0) { import_Logger.logger.warn(`\u{1F4F6}\uFE0F\u2757 Colyseus latency simulation enabled \u2192 ${milliseconds}ms latency for round trip.`); } else { import_Logger.logger.warn(`\u{1F4F6}\uFE0F\u2757 Colyseus latency simulation disabled.`); } const halfwayMS = milliseconds / 2; this.transport.simulateLatency(halfwayMS); if (this._originalRoomOnMessage == null) { this._originalRoomOnMessage = import_Room.Room.prototype["_onMessage"]; } const originalOnMessage = this._originalRoomOnMessage; import_Room.Room.prototype["_onMessage"] = milliseconds <= Number.EPSILON ? originalOnMessage : function(client, buffer) { const cachedBuffer = Buffer.from(buffer); setTimeout(() => originalOnMessage.call(this, client, cachedBuffer), halfwayMS); }; } /** * Register a callback that is going to be executed before the server shuts down. * @param callback */ onShutdown(callback) { this.onShutdownCallback = callback; } onBeforeShutdown(callback) { this.onBeforeShutdownCallback = callback; } async getDefaultTransport(options) { try { const module2 = await (0, import_Utils.dynamicImport)("@colyseus/ws-transport"); const WebSocketTransport = module2.WebSocketTransport; return new WebSocketTransport(options); } catch (error) { this._onTransportReady.reject(error); throw new Error("Please provide a 'transport' layer. Default transport not set."); } } }; function isRegisteredHandler(value) { return value instanceof import_RegisteredHandler.RegisteredHandler || typeof value === "object" && value !== null && "klass" in value; } function registerRoomDefinitions(rooms) { const roomNames = []; for (const [name, value] of Object.entries(rooms)) { if (isRegisteredHandler(value)) { value.name = name; matchMaker.addRoomType(value); } else { matchMaker.defineRoomType(name, value); } roomNames.push(name); } return roomNames; } function unregisterRoomDefinitions(roomNames) { for (const roomName of roomNames) { matchMaker.removeRoomType(roomName); } } function defineServer(options) { const { rooms, routes, ...serverOptions } = options; if (import_DevMode.isDevMode) { return { options: serverOptions, router: routes, "~rooms": rooms }; } const server = new Server(serverOptions); server.router = routes; registerRoomDefinitions(rooms); return server; } function defineRoom(roomKlass, defaultOptions) { return new import_RegisteredHandler.RegisteredHandler(roomKlass, defaultOptions); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Server, defineRoom, defineServer, registerRoomDefinitions, unregisterRoomDefinitions });