@colyseus/core
Version:
Multiplayer Framework for Node.js.
264 lines (262 loc) • 9.69 kB
JavaScript
;
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
});