@colyseus/core 0.17.19 → 0.17.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/MatchMaker.cjs.map +2 -2
- package/build/MatchMaker.d.ts +1 -1
- package/build/MatchMaker.mjs.map +2 -2
- package/build/Server.cjs.map +2 -2
- package/build/Server.d.ts +1 -1
- package/build/Server.mjs.map +2 -2
- package/build/Transport.cjs.map +1 -1
- package/build/Transport.d.ts +1 -1
- package/build/Transport.mjs.map +1 -1
- package/build/index.cjs +3 -3
- package/build/index.cjs.map +2 -2
- package/build/index.d.ts +1 -1
- package/build/index.mjs +2 -2
- package/build/index.mjs.map +2 -2
- package/build/matchmaker/RegisteredHandler.cjs.map +2 -2
- package/build/matchmaker/RegisteredHandler.d.ts +15 -15
- package/build/matchmaker/RegisteredHandler.mjs.map +2 -2
- package/build/rooms/QueueRoom.cjs +240 -0
- package/build/rooms/QueueRoom.cjs.map +7 -0
- package/build/rooms/QueueRoom.d.ts +127 -0
- package/build/rooms/QueueRoom.mjs +205 -0
- package/build/rooms/QueueRoom.mjs.map +7 -0
- package/build/router/index.cjs +2 -2
- package/build/router/index.cjs.map +2 -2
- package/build/router/index.mjs +2 -2
- package/build/router/index.mjs.map +2 -2
- package/package.json +4 -4
- package/src/MatchMaker.ts +2 -2
- package/src/Server.ts +2 -2
- package/src/Transport.ts +1 -1
- package/src/index.ts +1 -1
- package/src/matchmaker/RegisteredHandler.ts +15 -15
- package/src/rooms/{RankedQueueRoom.ts → QueueRoom.ts} +24 -24
- package/src/router/index.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/router/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n // express v5 uses `app.router`, express v4 uses `app._router`\n const stack = (expressApp as any)?.
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,yBAAsH;AACtH,kBAA8B;AAC9B,uBAA0B;AAC1B,wBAA2B;AAC3B,qBAAgB;AAEhB,IAAAA,sBAaO;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,gBAAY,mCAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAY,mCAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,eAAAC,QAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,WAAY,2BAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,6BAAW;AAAA,MACd,GAAG,6BAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;
|
|
4
|
+
"sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n //\n // express v5 uses `app.router`, express v4 uses `app._router`\n // check for `app._router` first, then `app.router`\n //\n // (express v4 will show a warning if `app.router` is used)\n //\n const stack = (expressApp as any)?._router?.stack ?? (expressApp as any)?.router?.stack;\n\n if (!stack) {\n return false;\n }\n\n return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));\n}\n\n/**\n * Do not use this directly. This is used internally by `@colyseus/playground`.\n * TODO: refactor. Avoid using globals.\n * @internal\n */\nexport let __globalEndpoints: Record<string, Endpoint> = {};\n\nexport function createRouter<\n E extends Record<string, Endpoint>,\n Config extends RouterConfig\n>(endpoints: E, config: Config = {} as Config) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints }, config);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,yBAAsH;AACtH,kBAA8B;AAC9B,uBAA0B;AAC1B,wBAA2B;AAC3B,qBAAgB;AAEhB,IAAAA,sBAaO;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,gBAAY,mCAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAY,mCAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,eAAAC,QAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,WAAY,2BAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,6BAAW;AAAA,MACd,GAAG,6BAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;AAOzD,QAAM,QAAS,YAAoB,SAAS,SAAU,YAAoB,QAAQ;AAElF,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,KAAK,CAAC,UAAe,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,SAAS,MAAM,IAAI,CAAC;AACtG;AAOO,IAAI,oBAA8C,CAAC;AAEnD,SAAS,aAGd,WAAc,SAAiB,CAAC,GAAa;AAE7C,sBAAoB;AAEpB,aAAO,mBAAAC,cAAuB,EAAE,GAAG,UAAU,GAAG,MAAM;AACxD;",
|
|
6
6
|
"names": ["import_better_call", "pkg", "createBetterCallRouter"]
|
|
7
7
|
}
|
package/build/router/index.mjs
CHANGED
|
@@ -52,9 +52,9 @@ function bindRouterToTransport(transport, router) {
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
function expressRootRoute(expressApp) {
|
|
55
|
-
const stack = expressApp?.
|
|
55
|
+
const stack = expressApp?._router?.stack ?? expressApp?.router?.stack;
|
|
56
56
|
if (!stack) {
|
|
57
|
-
|
|
57
|
+
return false;
|
|
58
58
|
}
|
|
59
59
|
return stack.find((layer) => layer.match("/") && !["query", "expressInit"].includes(layer.name));
|
|
60
60
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/router/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n // express v5 uses `app.router`, express v4 uses `app._router`\n const stack = (expressApp as any)?.
|
|
5
|
-
"mappings": ";AAEA,SAAwD,gBAAgB,wBAAwB,sBAAsB;AACtH,SAAS,qBAAqB;AAC9B,OAA0B;AAC1B,SAAS,kBAAkB;AAC3B,OAAO,SAAS,qBAAqB,KAAK,EAAE,MAAM,OAAO;AAEzD;AAAA,EACE,kBAAAA;AAAA,EACA;AAAA,EACA;AAAA,OAUK;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,YAAY,eAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,YAAY,eAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,IAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,OAAY,cAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,WAAW;AAAA,MACd,GAAG,WAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;
|
|
4
|
+
"sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n //\n // express v5 uses `app.router`, express v4 uses `app._router`\n // check for `app._router` first, then `app.router`\n //\n // (express v4 will show a warning if `app.router` is used)\n //\n const stack = (expressApp as any)?._router?.stack ?? (expressApp as any)?.router?.stack;\n\n if (!stack) {\n return false;\n }\n\n return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));\n}\n\n/**\n * Do not use this directly. This is used internally by `@colyseus/playground`.\n * TODO: refactor. Avoid using globals.\n * @internal\n */\nexport let __globalEndpoints: Record<string, Endpoint> = {};\n\nexport function createRouter<\n E extends Record<string, Endpoint>,\n Config extends RouterConfig\n>(endpoints: E, config: Config = {} as Config) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints }, config);\n}\n"],
|
|
5
|
+
"mappings": ";AAEA,SAAwD,gBAAgB,wBAAwB,sBAAsB;AACtH,SAAS,qBAAqB;AAC9B,OAA0B;AAC1B,SAAS,kBAAkB;AAC3B,OAAO,SAAS,qBAAqB,KAAK,EAAE,MAAM,OAAO;AAEzD;AAAA,EACE,kBAAAA;AAAA,EACA;AAAA,EACA;AAAA,OAUK;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,YAAY,eAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,YAAY,eAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,IAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,OAAY,cAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,WAAW;AAAA,MACd,GAAG,WAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;AAOzD,QAAM,QAAS,YAAoB,SAAS,SAAU,YAAoB,QAAQ;AAElF,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,KAAK,CAAC,UAAe,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,SAAS,MAAM,IAAI,CAAC;AACtG;AAOO,IAAI,oBAA8C,CAAC;AAEnD,SAAS,aAGd,WAAc,SAAiB,CAAC,GAAa;AAE7C,sBAAoB;AAEpB,SAAO,uBAAuB,EAAE,GAAG,UAAU,GAAG,MAAM;AACxD;",
|
|
6
6
|
"names": ["createEndpoint"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/core",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.21",
|
|
4
4
|
"description": "Multiplayer Framework for Node.js.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"input": "./src/index.ts",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@standard-schema/spec": "^1.0.0",
|
|
52
52
|
"debug": "^4.3.4",
|
|
53
53
|
"nanoid": "^3.3.11",
|
|
54
|
-
"@colyseus/shared-types": "^0.17.
|
|
54
|
+
"@colyseus/shared-types": "^0.17.3",
|
|
55
55
|
"@colyseus/better-call": "^1.2.0",
|
|
56
56
|
"@colyseus/greeting-banner": "^3.0.7"
|
|
57
57
|
},
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"@colyseus/schema": "^4.0.4",
|
|
60
60
|
"express": "^5.0.0",
|
|
61
61
|
"@colyseus/redis-driver": "^0.17.5",
|
|
62
|
-
"@colyseus/
|
|
63
|
-
"@colyseus/
|
|
62
|
+
"@colyseus/redis-presence": "^0.17.5",
|
|
63
|
+
"@colyseus/tools": "^0.17.15"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"@colyseus/schema": "^4.0.4",
|
package/src/MatchMaker.ts
CHANGED
|
@@ -390,8 +390,8 @@ export function defineRoomType<T extends Type<Room>>(
|
|
|
390
390
|
roomName: string,
|
|
391
391
|
klass: T,
|
|
392
392
|
defaultOptions?: OnCreateOptions<T>,
|
|
393
|
-
) {
|
|
394
|
-
const registeredHandler = new RegisteredHandler(klass, defaultOptions)
|
|
393
|
+
): RegisteredHandler<InstanceType<T>> {
|
|
394
|
+
const registeredHandler = new RegisteredHandler(klass, defaultOptions) as unknown as RegisteredHandler<InstanceType<T>>;
|
|
395
395
|
registeredHandler.name = roomName;
|
|
396
396
|
|
|
397
397
|
handlers[roomName] = registeredHandler;
|
package/src/Server.ts
CHANGED
|
@@ -384,6 +384,6 @@ export function defineServer<
|
|
|
384
384
|
export function defineRoom<T extends Type<Room>>(
|
|
385
385
|
roomKlass: T,
|
|
386
386
|
defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],
|
|
387
|
-
): RegisteredHandler<T
|
|
388
|
-
return new RegisteredHandler(roomKlass, defaultOptions)
|
|
387
|
+
): RegisteredHandler<InstanceType<T>> {
|
|
388
|
+
return new RegisteredHandler(roomKlass, defaultOptions) as unknown as RegisteredHandler<InstanceType<T>>;
|
|
389
389
|
}
|
package/src/Transport.ts
CHANGED
|
@@ -30,7 +30,7 @@ export abstract class Transport {
|
|
|
30
30
|
* For uWebSockets transport, this uses the uwebsockets-express module.
|
|
31
31
|
* This method is called lazily only when an express callback is provided in server options.
|
|
32
32
|
*/
|
|
33
|
-
public getExpressApp?(
|
|
33
|
+
public getExpressApp?(): Promise<import('express').Application> | import('express').Application | undefined;
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Binds a router to the transport.
|
package/src/index.ts
CHANGED
|
@@ -73,7 +73,7 @@ export {
|
|
|
73
73
|
// Default rooms
|
|
74
74
|
export { LobbyRoom } from './rooms/LobbyRoom.ts';
|
|
75
75
|
export { RelayRoom } from './rooms/RelayRoom.ts';
|
|
76
|
-
export {
|
|
76
|
+
export { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';
|
|
77
77
|
|
|
78
78
|
// Router / Endpoints
|
|
79
79
|
export {
|
|
@@ -36,32 +36,32 @@ type SortByKeys<RoomType extends Room> =
|
|
|
36
36
|
? keyof ExtractRoomCacheMetadata<RoomType> & string
|
|
37
37
|
: never);
|
|
38
38
|
|
|
39
|
-
export interface RegisteredHandlerEvents<RoomType extends
|
|
40
|
-
create: [room:
|
|
41
|
-
lock: [room:
|
|
42
|
-
unlock: [room:
|
|
43
|
-
join: [room:
|
|
44
|
-
leave: [room:
|
|
45
|
-
dispose: [room:
|
|
46
|
-
'visibility-change': [room:
|
|
47
|
-
'metadata-change': [room:
|
|
39
|
+
export interface RegisteredHandlerEvents<RoomType extends Room = any> {
|
|
40
|
+
create: [room: RoomType];
|
|
41
|
+
lock: [room: RoomType];
|
|
42
|
+
unlock: [room: RoomType];
|
|
43
|
+
join: [room: RoomType, client: Client];
|
|
44
|
+
leave: [room: RoomType, client: Client, willDispose: boolean];
|
|
45
|
+
dispose: [room: RoomType];
|
|
46
|
+
'visibility-change': [room: RoomType, isVisible: boolean];
|
|
47
|
+
'metadata-change': [room: RoomType];
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export class RegisteredHandler<
|
|
51
|
-
RoomType extends
|
|
51
|
+
RoomType extends Room = any
|
|
52
52
|
> extends EventEmitter<RegisteredHandlerEvents<RoomType>> {
|
|
53
53
|
'~room': RoomType;
|
|
54
54
|
|
|
55
|
-
public klass: RoomType
|
|
55
|
+
public klass: Type<RoomType>;
|
|
56
56
|
public options: any;
|
|
57
57
|
|
|
58
58
|
public name: string;
|
|
59
|
-
public filterOptions: Array<FilterByKeys<
|
|
59
|
+
public filterOptions: Array<FilterByKeys<RoomType>> = [];
|
|
60
60
|
public sortOptions?: SortOptions;
|
|
61
61
|
|
|
62
62
|
public realtimeListingEnabled: boolean = false;
|
|
63
63
|
|
|
64
|
-
constructor(klass: RoomType
|
|
64
|
+
constructor(klass: Type<RoomType>, options?: any) {
|
|
65
65
|
super();
|
|
66
66
|
|
|
67
67
|
this.klass = klass;
|
|
@@ -106,7 +106,7 @@ export class RegisteredHandler<
|
|
|
106
106
|
* // Mix both
|
|
107
107
|
* .filterBy(['mode', 'difficulty', 'maxClients'])
|
|
108
108
|
*/
|
|
109
|
-
public filterBy<T extends FilterByKeys<
|
|
109
|
+
public filterBy<T extends FilterByKeys<RoomType>>(
|
|
110
110
|
options: T[]
|
|
111
111
|
) {
|
|
112
112
|
this.filterOptions = options;
|
|
@@ -129,7 +129,7 @@ export class RegisteredHandler<
|
|
|
129
129
|
* // Multiple sort criteria
|
|
130
130
|
* .sortBy({ 'metadata.skillLevel': 1, clients: -1 })
|
|
131
131
|
*/
|
|
132
|
-
public sortBy<T extends SortByKeys<
|
|
132
|
+
public sortBy<T extends SortByKeys<RoomType>>(
|
|
133
133
|
options: { [K in T]: SortOptions[string] }
|
|
134
134
|
): this {
|
|
135
135
|
this.sortOptions = options as unknown as SortOptions;
|
|
@@ -6,7 +6,7 @@ import { debugMatchMaking } from '../Debug.ts';
|
|
|
6
6
|
import { ServerError } from '../errors/ServerError.ts';
|
|
7
7
|
import { ErrorCode } from '@colyseus/shared-types';
|
|
8
8
|
|
|
9
|
-
export interface
|
|
9
|
+
export interface QueueOptions {
|
|
10
10
|
/**
|
|
11
11
|
* number of players on each match
|
|
12
12
|
*/
|
|
@@ -44,29 +44,29 @@ export interface RankedQueueOptions {
|
|
|
44
44
|
* Comparison function for matching clients to groups
|
|
45
45
|
* Returns true if the client is compatible with the group
|
|
46
46
|
*/
|
|
47
|
-
compare?: (client:
|
|
47
|
+
compare?: (client: QueueClientData, matchGroup: QueueMatchGroup) => boolean;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
*
|
|
51
51
|
* When onGroupReady is set, the "roomNameToCreate" option is ignored.
|
|
52
52
|
*/
|
|
53
|
-
onGroupReady?: (this:
|
|
53
|
+
onGroupReady?: (this: QueueRoom, group: QueueMatchGroup) => Promise<IRoomCache>;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
export interface
|
|
56
|
+
export interface QueueMatchGroup {
|
|
57
57
|
averageRank: number;
|
|
58
|
-
clients: Array<Client<{ userData:
|
|
58
|
+
clients: Array<Client<{ userData: QueueClientData }>>,
|
|
59
59
|
ready?: boolean;
|
|
60
60
|
confirmed?: number;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export interface
|
|
63
|
+
export interface QueueMatchTeam {
|
|
64
64
|
averageRank: number;
|
|
65
|
-
clients: Array<Client<{ userData:
|
|
65
|
+
clients: Array<Client<{ userData: QueueClientData }>>,
|
|
66
66
|
teamId: string | symbol;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export interface
|
|
69
|
+
export interface QueueClientData {
|
|
70
70
|
/**
|
|
71
71
|
* Rank of the client
|
|
72
72
|
*/
|
|
@@ -90,7 +90,7 @@ export interface ClientQueueData {
|
|
|
90
90
|
/**
|
|
91
91
|
* Match group the client is currently in
|
|
92
92
|
*/
|
|
93
|
-
group?:
|
|
93
|
+
group?: QueueMatchGroup;
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Whether the client has confirmed the connection to the room
|
|
@@ -110,14 +110,14 @@ export interface ClientQueueData {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
const DEFAULT_TEAM = Symbol("$default_team");
|
|
113
|
-
const DEFAULT_COMPARE = (client:
|
|
113
|
+
const DEFAULT_COMPARE = (client: QueueClientData, matchGroup: QueueMatchGroup) => {
|
|
114
114
|
const diff = Math.abs(client.rank - matchGroup.averageRank);
|
|
115
115
|
const diffRatio = (diff / matchGroup.averageRank);
|
|
116
116
|
// If diff ratio is too high, create a new match group
|
|
117
117
|
return (diff < 10 || diffRatio <= 2);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
export class
|
|
120
|
+
export class QueueRoom extends Room {
|
|
121
121
|
maxPlayers = 4;
|
|
122
122
|
maxTeamSize: number;
|
|
123
123
|
allowIncompleteGroups: boolean = false;
|
|
@@ -133,13 +133,13 @@ export class RankedQueueRoom extends Room {
|
|
|
133
133
|
/**
|
|
134
134
|
* Groups of players per iteration
|
|
135
135
|
*/
|
|
136
|
-
groups:
|
|
137
|
-
highPriorityGroups:
|
|
136
|
+
groups: QueueMatchGroup[] = [];
|
|
137
|
+
highPriorityGroups: QueueMatchGroup[] = [];
|
|
138
138
|
|
|
139
139
|
matchRoomName: string;
|
|
140
140
|
|
|
141
141
|
protected compare = DEFAULT_COMPARE;
|
|
142
|
-
protected onGroupReady = (group:
|
|
142
|
+
protected onGroupReady = (group: QueueMatchGroup) => matchMaker.createRoom(this.matchRoomName, {});
|
|
143
143
|
|
|
144
144
|
messages = {
|
|
145
145
|
confirm: (client: Client, _: unknown) => {
|
|
@@ -153,7 +153,7 @@ export class RankedQueueRoom extends Room {
|
|
|
153
153
|
},
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
onCreate(options:
|
|
156
|
+
onCreate(options: QueueOptions) {
|
|
157
157
|
if (typeof(options.maxWaitingCycles) === "number") {
|
|
158
158
|
this.maxWaitingCycles = options.maxWaitingCycles;
|
|
159
159
|
}
|
|
@@ -182,10 +182,10 @@ export class RankedQueueRoom extends Room {
|
|
|
182
182
|
this.matchRoomName = options.matchRoomName;
|
|
183
183
|
|
|
184
184
|
} else {
|
|
185
|
-
throw new ServerError(ErrorCode.APPLICATION_ERROR, "
|
|
185
|
+
throw new ServerError(ErrorCode.APPLICATION_ERROR, "QueueRoom: 'matchRoomName' option is required.");
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
debugMatchMaking("
|
|
188
|
+
debugMatchMaking("QueueRoom#onCreate() maxPlayers: %d, maxWaitingCycles: %d, maxTeamSize: %d, allowIncompleteGroups: %d, roomNameToCreate: %s", this.maxPlayers, this.maxWaitingCycles, this.maxTeamSize, this.allowIncompleteGroups, this.matchRoomName);
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
191
|
* Redistribute clients into groups at every interval
|
|
@@ -201,7 +201,7 @@ export class RankedQueueRoom extends Room {
|
|
|
201
201
|
});
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
addToQueue(client: Client, queueData:
|
|
204
|
+
addToQueue(client: Client, queueData: QueueClientData) {
|
|
205
205
|
if (queueData.currentCycle === undefined) {
|
|
206
206
|
queueData.currentCycle = 0;
|
|
207
207
|
}
|
|
@@ -212,7 +212,7 @@ export class RankedQueueRoom extends Room {
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
createMatchGroup() {
|
|
215
|
-
const group:
|
|
215
|
+
const group: QueueMatchGroup = { clients: [], averageRank: 0 };
|
|
216
216
|
this.groups.push(group);
|
|
217
217
|
return group;
|
|
218
218
|
}
|
|
@@ -253,8 +253,8 @@ export class RankedQueueRoom extends Room {
|
|
|
253
253
|
this.processGroupsReady();
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
redistributeTeams(sortedClients: Client<{ userData:
|
|
257
|
-
const teamsByID: { [teamId: string | symbol]:
|
|
256
|
+
redistributeTeams(sortedClients: Client<{ userData: QueueClientData }>[]) {
|
|
257
|
+
const teamsByID: { [teamId: string | symbol]: QueueMatchTeam } = {};
|
|
258
258
|
|
|
259
259
|
sortedClients.forEach((client) => {
|
|
260
260
|
const teamId = client.userData.teamId || DEFAULT_TEAM;
|
|
@@ -279,7 +279,7 @@ export class RankedQueueRoom extends Room {
|
|
|
279
279
|
|
|
280
280
|
// Iterate over teams multiple times until all clients are assigned to a group
|
|
281
281
|
do {
|
|
282
|
-
let currentGroup:
|
|
282
|
+
let currentGroup: QueueMatchGroup = this.createMatchGroup();
|
|
283
283
|
teams = teams.filter((team) => {
|
|
284
284
|
// Remove clients from the team and add them to the current group
|
|
285
285
|
const totalRank = team.averageRank * team.clients.length;
|
|
@@ -303,8 +303,8 @@ export class RankedQueueRoom extends Room {
|
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
redistributeClients(
|
|
306
|
-
sortedClients: Client<{ userData:
|
|
307
|
-
currentGroup:
|
|
306
|
+
sortedClients: Client<{ userData: QueueClientData }>[],
|
|
307
|
+
currentGroup: QueueMatchGroup = this.createMatchGroup(),
|
|
308
308
|
totalRank: number = 0,
|
|
309
309
|
) {
|
|
310
310
|
for (let i = 0, l = sortedClients.length; i < l; i++) {
|
package/src/router/index.ts
CHANGED
|
@@ -99,7 +99,7 @@ function expressRootRoute(expressApp: express.Application) {
|
|
|
99
99
|
const stack = (expressApp as any)?._router?.stack ?? (expressApp as any)?.router?.stack;
|
|
100
100
|
|
|
101
101
|
if (!stack) {
|
|
102
|
-
|
|
102
|
+
return false;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));
|