@colyseus/core 0.17.4 → 0.17.6
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/Debug.cjs +13 -11
- package/build/Debug.cjs.map +1 -1
- package/build/IPC.cjs +6 -4
- package/build/IPC.cjs.map +1 -1
- package/build/Logger.cjs +5 -3
- package/build/Logger.cjs.map +1 -1
- package/build/MatchMaker.cjs +31 -29
- package/build/MatchMaker.cjs.map +1 -1
- package/build/Protocol.cjs +8 -6
- package/build/Protocol.cjs.map +1 -1
- package/build/Room.cjs +22 -20
- package/build/Room.cjs.map +1 -1
- package/build/Server.cjs +22 -20
- package/build/Server.cjs.map +3 -3
- package/build/Server.mjs +4 -4
- package/build/Server.mjs.map +3 -3
- package/build/Stats.cjs +8 -6
- package/build/Stats.cjs.map +1 -1
- package/build/Transport.cjs +12 -20
- package/build/Transport.cjs.map +1 -1
- package/build/errors/RoomExceptions.cjs +18 -16
- package/build/errors/RoomExceptions.cjs.map +1 -1
- package/build/errors/SeatReservationError.cjs +4 -2
- package/build/errors/SeatReservationError.cjs.map +1 -1
- package/build/errors/ServerError.cjs +6 -4
- package/build/errors/ServerError.cjs.map +1 -1
- package/build/index.cjs +27 -25
- package/build/index.cjs.map +1 -1
- package/build/matchmaker/Lobby.cjs +4 -2
- package/build/matchmaker/Lobby.cjs.map +1 -1
- package/build/matchmaker/LocalDriver/LocalDriver.cjs +6 -4
- package/build/matchmaker/LocalDriver/LocalDriver.cjs.map +1 -1
- package/build/matchmaker/LocalDriver/Query.cjs +4 -2
- package/build/matchmaker/LocalDriver/Query.cjs.map +1 -1
- package/build/matchmaker/RegisteredHandler.cjs +8 -6
- package/build/matchmaker/RegisteredHandler.cjs.map +1 -1
- package/build/matchmaker/controller.cjs +5 -3
- package/build/matchmaker/controller.cjs.map +1 -1
- package/build/matchmaker/driver.cjs +2 -0
- package/build/matchmaker/driver.cjs.map +1 -1
- package/build/presence/LocalPresence.cjs +6 -4
- package/build/presence/LocalPresence.cjs.map +1 -1
- package/build/presence/Presence.cjs +2 -0
- package/build/presence/Presence.cjs.map +1 -1
- package/build/rooms/LobbyRoom.cjs +7 -5
- package/build/rooms/LobbyRoom.cjs.map +1 -1
- package/build/rooms/RankedQueueRoom.cjs +6 -4
- package/build/rooms/RankedQueueRoom.cjs.map +1 -1
- package/build/rooms/RelayRoom.cjs +10 -8
- package/build/rooms/RelayRoom.cjs.map +1 -1
- package/build/router/default_routes.cjs +5 -3
- package/build/router/default_routes.cjs.map +1 -1
- package/build/router/index.cjs +3 -1
- package/build/router/index.cjs.map +1 -1
- package/build/serializer/NoneSerializer.cjs +4 -2
- package/build/serializer/NoneSerializer.cjs.map +1 -1
- package/build/serializer/SchemaSerializer.cjs +8 -6
- package/build/serializer/SchemaSerializer.cjs.map +1 -1
- package/build/serializer/SchemaSerializerDebug.cjs +7 -27
- package/build/serializer/SchemaSerializerDebug.cjs.map +1 -1
- package/build/serializer/Serializer.cjs +2 -0
- package/build/serializer/Serializer.cjs.map +1 -1
- package/build/utils/DevMode.cjs +7 -5
- package/build/utils/DevMode.cjs.map +1 -1
- package/build/utils/StandardSchema.cjs +2 -0
- package/build/utils/StandardSchema.cjs.map +1 -1
- package/build/utils/Utils.cjs +13 -11
- package/build/utils/Utils.cjs.map +1 -1
- package/build/utils/nanoevents.cjs +3 -1
- package/build/utils/nanoevents.cjs.map +1 -1
- package/package.json +3 -3
- package/src/Server.ts +2 -2
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/matchmaker/driver.ts"],
|
|
4
4
|
"sourcesContent": ["import type { Room } from \"@colyseus/core\";\n\n/**\n * Sort options for room queries.\n */\nexport interface SortOptions {\n [fieldName: string]: 1 | -1 | 'asc' | 'desc' | 'ascending' | 'descending';\n}\n\n/**\n * Built-in room cache fields that can be used for sorting.\n */\nexport type IRoomCacheSortByKeys = 'clients' | 'maxClients' | 'createdAt';\n\n/**\n * Built-in room cache fields that can be used for filtering.\n */\nexport type IRoomCacheFilterByKeys = 'clients' | 'maxClients' | 'processId';\n\n/**\n * Extract metadata type from Room type\n */\nexport type ExtractMetadata<RoomType extends Room> = RoomType['~metadata'];\n\n/**\n * Generates a unique lock ID based on filter options.\n */\nexport function getLockId(filterOptions: any) {\n return Object.keys(filterOptions).map((key) => `${key}:${filterOptions[key]}`).join(\"-\");\n}\n\n/**\n * Initialize a room cache which contains CRUD operations for room listings.\n *\n * @internal\n * @param initialValues - Predefined room properties.\n * @returns RoomData - New room cache.\n */\nexport function initializeRoomCache(initialValues: Partial<IRoomCache> = {}): IRoomCache {\n return {\n clients: 0,\n maxClients: Infinity,\n locked: false,\n private: false,\n metadata: undefined,\n createdAt: (initialValues && initialValues.createdAt) ? new Date(initialValues.createdAt) : new Date(),\n unlisted: false,\n ...initialValues,\n } as IRoomCache;\n}\n\nexport interface IRoomCache<Metadata = any> {\n /**\n * Room name.\n */\n name: string;\n\n /**\n * Unique identifier for the room.\n */\n roomId: string;\n\n /**\n * Process id where the room is running.\n */\n processId: string;\n\n /**\n * Number of clients connected to this room.\n */\n clients: number;\n\n /**\n * Maximum number of clients allowed to join the room.\n */\n maxClients: number;\n\n /**\n * Indicates if the room is locked (i.e. join requests are rejected).\n */\n locked?: boolean;\n\n /**\n * Indicates if the room is private\n * Private rooms can't be joined via `join()` or `joinOrCreate()`.\n */\n private?: boolean;\n\n /**\n * Public address of the server.\n */\n publicAddress?: string;\n\n /**\n * Do not show this room in lobby listing.\n */\n unlisted?: boolean;\n\n /**\n * Metadata associated with the room.\n */\n metadata?: Metadata;\n\n /**\n * When the room was created.\n */\n createdAt?: Date;\n}\n\nexport interface MatchMakerDriver {\n /**\n * Check if a room exists in room cache.\n *\n * @param roomId - The room id.\n *\n * @returns Promise<boolean> | boolean - A promise or a boolean value indicating if the room exists.\n */\n has(roomId: string): Promise<boolean> | boolean;\n\n /**\n * Query rooms in room cache for given conditions.\n *\n * @param conditions - Filtering conditions.\n *\n * @returns Promise<IRoomCache[]> | IRoomCache[] - A promise or an object contaning room metadata list.\n */\n query<T extends Room = any>(\n conditions: Partial<IRoomCache & ExtractMetadata<T>>,\n sortOptions?: SortOptions\n ): Promise<Array<IRoomCache<ExtractMetadata<T>>>> | Array<IRoomCache<ExtractMetadata<T>>>;\n\n /**\n * Clean up rooms in room cache by process id.\n * @param processId - The process id.\n */\n cleanup?(processId: string): Promise<void>;\n\n /**\n * Query for a room in room cache for given conditions.\n *\n * @param conditions - Filtering conditions.\n *\n * @returns `IRoomCache` - An object contaning filtered room metadata.\n */\n findOne<T extends Room = any>(\n conditions: Partial<IRoomCache & ExtractMetadata<T>>,\n sortOptions?: SortOptions\n ): Promise<IRoomCache<ExtractMetadata<T>>>;\n\n /**\n * Remove a room from room cache.\n *\n * @param roomId - The room id.\n */\n remove(roomId: string): Promise<boolean> | boolean;\n\n /**\n * Update a room in room cache.\n *\n * @param IRoomCache - The room to update.\n * @param operations - The operations to update the room.\n */\n update(\n room: IRoomCache,\n operations: Partial<{ $set: Partial<IRoomCache>, $inc: Partial<IRoomCache> }>\n ): Promise<boolean> | boolean;\n\n /**\n * Persist a room in room cache.\n *\n * @param room - The room to persist.\n * @param create - If true, create a new record. If false (default), update existing record.\n */\n persist(room: IRoomCache, create?: boolean): Promise<boolean> | boolean;\n\n /**\n * Empty the room cache. Used for testing purposes only.\n * @internal Do not call this method yourself.\n */\n clear(): void;\n\n /**\n * Boot the room cache medium (if available).\n */\n boot?(): Promise<void>;\n\n /**\n * Dispose the connection of the room cache medium.\n */\n shutdown(): void;\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BO,SAAS,UAAU,eAAoB;AAC5C,SAAO,OAAO,KAAK,aAAa,EAAE,IAAI,CAAC,QAAQ,GAAG,GAAG,IAAI,cAAc,GAAG,CAAC,EAAE,EAAE,KAAK,GAAG;AACzF;AASO,SAAS,oBAAoB,gBAAqC,CAAC,GAAe;AACvF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,WAAY,iBAAiB,cAAc,YAAa,IAAI,KAAK,cAAc,SAAS,IAAI,oBAAI,KAAK;AAAA,IACrG,UAAU;AAAA,IACV,GAAG;AAAA,EACL;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,15 +16,17 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/presence/LocalPresence.ts
|
|
19
21
|
var LocalPresence_exports = {};
|
|
20
22
|
__export(LocalPresence_exports, {
|
|
21
23
|
LocalPresence: () => LocalPresence
|
|
22
24
|
});
|
|
23
25
|
module.exports = __toCommonJS(LocalPresence_exports);
|
|
24
26
|
var import_events = require("events");
|
|
25
|
-
var import_Utils = require("../utils/Utils.
|
|
26
|
-
var import_DevMode = require("../utils/DevMode.
|
|
27
|
-
|
|
27
|
+
var import_Utils = require("../utils/Utils.cjs");
|
|
28
|
+
var import_DevMode = require("../utils/DevMode.cjs");
|
|
29
|
+
var LocalPresence = class {
|
|
28
30
|
constructor() {
|
|
29
31
|
this.subscriptions = new import_events.EventEmitter();
|
|
30
32
|
this.data = {};
|
|
@@ -272,7 +274,7 @@ class LocalPresence {
|
|
|
272
274
|
});
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
|
-
}
|
|
277
|
+
};
|
|
276
278
|
// Annotate the CommonJS export names for ESM import in node:
|
|
277
279
|
0 && (module.exports = {
|
|
278
280
|
LocalPresence
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/presence/LocalPresence.ts"],
|
|
4
4
|
"sourcesContent": ["\nimport { EventEmitter } from 'events';\nimport { spliceOne } from '../utils/Utils.ts';\nimport type { Presence } from './Presence.ts';\n\nimport { hasDevModeCache, isDevMode, getDevModeCache, writeDevModeCache } from '../utils/DevMode.ts';\n\ntype Callback = (...args: any[]) => void;\n\nexport class LocalPresence implements Presence {\n public subscriptions = new EventEmitter();\n\n public data: {[roomName: string]: string[]} = {};\n public hash: {[roomName: string]: {[key: string]: string}} = {};\n\n public keys: {[name: string]: string | number} = {};\n\n private timeouts: {[name: string]: NodeJS.Timeout} = {};\n\n constructor() {\n //\n // reload from local cache on devMode\n //\n if (\n isDevMode &&\n hasDevModeCache()\n ) {\n const cache = getDevModeCache();\n if (cache.data) { this.data = cache.data; }\n if (cache.hash) { this.hash = cache.hash; }\n if (cache.keys) { this.keys = cache.keys; }\n }\n }\n\n public subscribe(topic: string, callback: (...args: any[]) => void) {\n this.subscriptions.on(topic, callback);\n return Promise.resolve(this);\n }\n\n public unsubscribe(topic: string, callback?: Callback) {\n if (callback) {\n this.subscriptions.removeListener(topic, callback);\n\n } else {\n this.subscriptions.removeAllListeners(topic);\n }\n\n return this;\n }\n\n public publish(topic: string, data: any) {\n this.subscriptions.emit(topic, data);\n return this;\n }\n\n public async channels (pattern?: string) {\n let eventNames = this.subscriptions.eventNames() as string[];\n if (pattern) {\n //\n // This is a limited glob pattern to regexp implementation.\n // If needed, we can use a full implementation like picomatch: https://github.com/micromatch/picomatch/\n //\n const regexp = new RegExp(\n pattern.\n replaceAll(\".\", \"\\\\.\").\n replaceAll(\"$\", \"\\\\$\").\n replaceAll(\"*\", \".*\").\n replaceAll(\"?\", \".\"),\n \"i\"\n );\n eventNames = eventNames.filter((eventName) => regexp.test(eventName));\n }\n return eventNames;\n }\n\n public async exists(key: string): Promise<boolean> {\n return (\n this.keys[key] !== undefined ||\n this.data[key] !== undefined ||\n this.hash[key] !== undefined\n );\n }\n\n public set(key: string, value: string) {\n this.keys[key] = value;\n }\n\n public setex(key: string, value: string, seconds: number) {\n this.keys[key] = value;\n this.expire(key, seconds);\n }\n\n public expire(key: string, seconds: number) {\n // ensure previous timeout is clear before setting another one.\n if (this.timeouts[key]) {\n clearTimeout(this.timeouts[key]);\n }\n this.timeouts[key] = setTimeout(() => {\n delete this.keys[key];\n delete this.timeouts[key];\n }, seconds * 1000);\n }\n\n public get(key: string) {\n return this.keys[key];\n }\n\n public del(key: string) {\n delete this.keys[key];\n delete this.data[key];\n delete this.hash[key];\n }\n\n public sadd(key: string, value: any) {\n if (!this.data[key]) {\n this.data[key] = [];\n }\n\n if (this.data[key].indexOf(value) === -1) {\n this.data[key].push(value);\n }\n }\n\n public async smembers(key: string): Promise<string[]> {\n return this.data[key] || [];\n }\n\n public async sismember(key: string, field: string) {\n return this.data[key] && this.data[key].includes(field) ? 1 : 0;\n }\n\n public srem(key: string, value: any) {\n if (this.data[key]) {\n spliceOne(this.data[key], this.data[key].indexOf(value));\n }\n }\n\n public scard(key: string) {\n return (this.data[key] || []).length;\n }\n\n public async sinter(...keys: string[]) {\n const intersection: {[value: string]: number} = {};\n\n for (let i = 0, l = keys.length; i < l; i++) {\n (await this.smembers(keys[i])).forEach((member) => {\n if (!intersection[member]) {\n intersection[member] = 0;\n }\n\n intersection[member]++;\n });\n }\n\n return Object.keys(intersection).reduce((prev, curr) => {\n if (intersection[curr] > 1) {\n prev.push(curr);\n }\n return prev;\n }, []);\n }\n\n public hset(key: string, field: string, value: string) {\n if (!this.hash[key]) { this.hash[key] = {}; }\n this.hash[key][field] = value;\n return Promise.resolve(true);\n }\n\n public hincrby(key: string, field: string, incrBy: number) {\n if (!this.hash[key]) { this.hash[key] = {}; }\n let value = Number(this.hash[key][field] || '0');\n value += incrBy;\n this.hash[key][field] = value.toString();\n return Promise.resolve(value);\n }\n\n public hincrbyex(key: string, field: string, incrBy: number, expireInSeconds: number) {\n if (!this.hash[key]) { this.hash[key] = {}; }\n let value = Number(this.hash[key][field] || '0');\n value += incrBy;\n this.hash[key][field] = value.toString();\n\n //\n // FIXME: delete only hash[key][field]\n // (we can't use \"HEXPIRE\" in Redis because it's only available since Redis version 7.4.0+)\n //\n if (this.timeouts[key]) {\n clearTimeout(this.timeouts[key]);\n }\n this.timeouts[key] = setTimeout(() => {\n delete this.hash[key];\n delete this.timeouts[key];\n }, expireInSeconds * 1000);\n\n return Promise.resolve(value);\n }\n\n public async hget(key: string, field: string) {\n return (typeof(this.hash[key]) === 'object')\n ? this.hash[key][field] ?? null\n : null;\n }\n\n public async hgetall(key: string) {\n return this.hash[key] || {};\n }\n\n public hdel(key: string, field: any) {\n const success = this.hash?.[key]?.[field] !== undefined;\n if (success) {\n delete this.hash[key][field];\n }\n return Promise.resolve(success);\n }\n\n public async hlen(key: string) {\n return this.hash[key] && Object.keys(this.hash[key]).length || 0;\n }\n\n public async incr(key: string) {\n if (!this.keys[key]) {\n this.keys[key] = 0;\n }\n (this.keys[key] as number)++;\n return Promise.resolve(this.keys[key] as number);\n }\n\n public async decr(key: string) {\n if (!this.keys[key]) {\n this.keys[key] = 0;\n }\n (this.keys[key] as number)--;\n return Promise.resolve(this.keys[key] as number);\n }\n\n public llen(key: string) {\n return Promise.resolve((this.data[key] && this.data[key].length) || 0);\n }\n\n public rpush(key: string, ...values: string[]): Promise<number> {\n if (!this.data[key]) { this.data[key] = []; }\n\n let lastLength: number = 0;\n\n values.forEach(value => {\n lastLength = this.data[key].push(value);\n });\n\n return Promise.resolve(lastLength);\n }\n\n public lpush(key: string, ...values: string[]): Promise<number> {\n if (!this.data[key]) { this.data[key] = []; }\n\n let lastLength: number = 0;\n\n values.forEach(value => {\n lastLength = this.data[key].unshift(value);\n });\n\n return Promise.resolve(lastLength);\n }\n\n public lpop(key: string): Promise<string> {\n return Promise.resolve(Array.isArray(this.data[key])\n ? this.data[key].shift()\n : null);\n }\n\n public rpop(key: string): Promise<string | null> {\n return Promise.resolve(this.data[key].pop());\n }\n\n public brpop(...args: [...keys: string[], timeoutInSeconds: number]): Promise<[string, string] | null> {\n const keys = args.slice(0, -1) as string[];\n const timeoutInSeconds = args[args.length - 1] as number;\n\n const getFirstPopulated = (): [string, string] | null => {\n const keyWithValue = keys.find(key => this.data[key] && this.data[key].length > 0);\n if (keyWithValue) {\n return [keyWithValue, this.data[keyWithValue].pop()];\n } else {\n return null;\n }\n }\n\n const firstPopulated = getFirstPopulated();\n\n if (firstPopulated) {\n // return first populated key + item\n return Promise.resolve(firstPopulated);\n\n } else {\n // 8 retries per second\n const maxRetries = timeoutInSeconds * 8;\n\n let tries = 0;\n return new Promise((resolve) => {\n const interval = setInterval(() => {\n tries++;\n\n const firstPopulated = getFirstPopulated();\n if (firstPopulated) {\n clearInterval(interval);\n return resolve(firstPopulated);\n\n } else if (tries >= maxRetries) {\n clearInterval(interval);\n return resolve(null);\n }\n\n }, (timeoutInSeconds * 1000) / maxRetries);\n });\n }\n }\n\n public setMaxListeners(number: number) {\n this.subscriptions.setMaxListeners(number);\n }\n\n public shutdown() {\n if (isDevMode) {\n writeDevModeCache({\n data: this.data,\n hash: this.hash,\n keys: this.keys\n });\n }\n }\n\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["firstPopulated"]
|
|
7
7
|
}
|
|
@@ -16,6 +16,8 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/presence/Presence.ts
|
|
19
21
|
var Presence_exports = {};
|
|
20
22
|
__export(Presence_exports, {
|
|
21
23
|
createScopedPresence: () => createScopedPresence
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/presence/Presence.ts"],
|
|
4
4
|
"sourcesContent": ["import type { Room } from \"../Room.ts\";\n\n/**\n * When you need to scale your server on multiple processes and/or machines, you'd need to provide\n * the Presence option to the Server. The purpose of Presence is to allow communicating and\n * sharing data between different processes, specially during match-making.\n *\n * - Local presence - This is the default option. It's meant to be used when you're running Colyseus in\n * a single process.\n * - Redis presence - Use this option when you're running Colyseus on multiple processes and/or machines.\n *\n * @default Local presence\n */\nexport interface Presence {\n /**\n * Subscribes to the given topic. The callback will be triggered whenever a message is published on topic.\n *\n * @param topic - Topic name.\n * @param callback - Callback to trigger on subscribing.\n */\n subscribe(topic: string, callback: Function): Promise<this>;\n\n /**\n * Unsubscribe from given topic.\n *\n * @param topic - Topic name.\n * @param callback - Callback to trigger on topic unsubscribing.\n */\n unsubscribe(topic: string, callback?: Function);\n\n /**\n * Lists the currently active channels / subscriptions\n * @param pattern\n */\n channels(pattern?: string): Promise<string[]>;\n\n /**\n * Posts a message to given topic.\n *\n * @param topic - Topic name.\n * @param data - Message body/object.\n */\n publish(topic: string, data: any);\n\n /**\n * Returns if key exists.\n *\n * @param key\n */\n exists(key: string): Promise<boolean>;\n\n /**\n * Set key to hold the string value.\n *\n * @param key - Identifier.\n * @param value - Message body/object.\n */\n set(key: string, value: string);\n\n /**\n * Set key to hold the string value and set key to timeout after a given number of seconds.\n *\n * @param key - Identifier.\n * @param value - Message body/object.\n * @param seconds - Timeout value.\n */\n setex(key: string, value: string, seconds: number);\n\n /**\n * Expire the key in seconds.\n *\n * @param key - Identifier.\n * @param seconds - Seconds to expire the key.\n */\n expire(key: string, seconds: number);\n\n /**\n * Get the value of key.\n *\n * @param key - Identifier.\n */\n get(key: string);\n\n /**\n * Removes the specified key.\n *\n * @param key - Identifier of the object to removed.\n */\n del(key: string): void;\n\n /**\n * Add the specified members to the set stored at key. Specified members that are already\n * a member of this set are ignored. If key does not exist, a new set is created before\n * adding the specified members.\n *\n * @param key - Name/Identifier of the set.\n * @param value - Message body/object.\n */\n sadd(key: string, value: any);\n\n /**\n * Returns all the members of the set value stored at key.\n *\n * @param key - Name/Identifier of the set.\n */\n smembers(key: string): Promise<string[]>;\n\n /**\n * Returns if member is a member of the set stored at key.\n *\n * @param key - Name/Identifier of the set.\n * @param field - Key value within the set.\n * @returns `1` if the element is a member of the set else `0`.\n */\n sismember(key: string, field: string);\n\n /**\n * Remove the specified members from the set stored at key. Specified members that are not a\n * member of this set are ignored. If key does not exist, it is treated as an empty set\n * and this command returns 0.\n *\n * @param key - Name/Identifier of the set.\n * @param value - Key value within the set.\n */\n srem(key: string, value: any);\n\n /**\n * Returns the set cardinality (number of elements) of the set stored at key.\n *\n * @param key - Name/Identifier of the set.\n */\n scard(key: string);\n\n /**\n * Returns the members of the set resulting from the intersection of all the given sets.\n *\n * @param keys - Key values within the set.\n */\n sinter(...keys: string[]): Promise<string[]>;\n\n /**\n * Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created.\n * If field already exists in the hash, it is overwritten.\n */\n hset(key: string, field: string, value: string): Promise<boolean>;\n\n /**\n * Increments the number stored at field in the hash stored at key by increment. If key does not exist, a new key\n * holding a hash is created. If field does not exist the value is set to 0 before the operation is performed.\n */\n hincrby(key: string, field: string, value: number): Promise<number>;\n\n /**\n * WARNING: DO NOT USE THIS METHOD. It is meant for internal use only.\n * @private\n */\n hincrbyex(key: string, field: string, value: number, expireInSeconds: number): Promise<number>;\n\n /**\n * Returns the value associated with field in the hash stored at key.\n */\n hget(key: string, field: string): Promise<string | null>;\n\n /**\n * Returns all fields and values of the hash stored at key.\n */\n hgetall(key: string): Promise<{ [key: string]: string }>;\n\n /**\n * Removes the specified fields from the hash stored at key. Specified fields that do not exist within\n * this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0.\n */\n hdel(key: string, field: string): Promise<boolean>;\n\n /**\n * Returns the number of fields contained in the hash stored at key\n */\n hlen(key: string): Promise<number>;\n\n /**\n * Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing\n * the operation. An error is returned if the key contains a value of the wrong type or\n * contains a string that can not be represented as integer. This operation is limited to 64-bit signed integers.\n */\n incr(key: string): Promise<number>;\n\n /**\n * Decrements the number stored at key by one. If the key does not exist, it is set to 0 before performing\n * the operation. An error is returned if the key contains a value of the wrong type or contains a string\n * that can not be represented as integer. This operation is limited to 64-bit signed integers.\n */\n decr(key: string): Promise<number>;\n\n /**\n * Returns the length of the list stored at key.\n */\n llen(key: string): Promise<number>;\n\n /**\n * Adds the string value to the end of the list stored at key. If key does not exist, it is created as empty list before performing the push operation.\n */\n rpush(key: string, ...values: string[]): Promise<number>;\n\n /**\n * Adds the string value to the begginning of the list stored at key. If key does not exist, it is created as empty list before performing the push operation.\n */\n lpush(key: string, ...values: string[]): Promise<number>;\n\n /**\n * Removes and returns the last element of the list stored at key.\n */\n rpop(key: string): Promise<string | null>;\n\n /**\n * Removes and returns the first element of the list stored at key.\n */\n lpop(key: string): Promise<string | null>;\n\n /**\n * Removes and returns the last element of the list stored at key. If the list is empty, the execution is halted until an element is available or the timeout is reached.\n */\n brpop(...args: [...keys: string[], timeoutInSeconds: number]): Promise<[string, string] | null>;\n\n setMaxListeners(number: number): void;\n\n shutdown(): void;\n}\n\nexport function createScopedPresence(room: Room, presence: Presence): Presence {\n // Keep a local copy of all subscriptions made through this scoped presence\n const subscriptions: Array<{ topic: string; callback: Function }> = [];\n\n // Create a copy of the presence object\n const scopedPresence = Object.create(presence) as Presence;\n\n // Override subscribe method to track subscriptions\n scopedPresence.subscribe = async function (topic: string, callback: Function): Promise<Presence> {\n subscriptions.push({ topic, callback });\n await presence.subscribe(topic, callback);\n return scopedPresence;\n };\n\n // Override unsubscribe method to remove from tracking\n scopedPresence.unsubscribe = function (topic: string, callback?: Function) {\n const index = subscriptions.findIndex(\n (sub) => sub.topic === topic && (!callback || sub.callback === callback)\n );\n if (index !== -1) {\n subscriptions.splice(index, 1);\n }\n presence.unsubscribe(topic, callback);\n };\n\n // Clean up all subscriptions when the room is disposed\n room['_events'].on('dispose', () => {\n for (const { topic, callback } of subscriptions) {\n presence.unsubscribe(topic, callback);\n }\n subscriptions.length = 0;\n });\n\n return scopedPresence;\n}"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoOO,SAAS,qBAAqB,MAAY,UAA8B;AAE7E,QAAM,gBAA8D,CAAC;AAGrE,QAAM,iBAAiB,OAAO,OAAO,QAAQ;AAG7C,iBAAe,YAAY,eAAgB,OAAe,UAAuC;AAC/F,kBAAc,KAAK,EAAE,OAAO,SAAS,CAAC;AACtC,UAAM,SAAS,UAAU,OAAO,QAAQ;AACxC,WAAO;AAAA,EACT;AAGA,iBAAe,cAAc,SAAU,OAAe,UAAqB;AACzE,UAAM,QAAQ,cAAc;AAAA,MAC1B,CAAC,QAAQ,IAAI,UAAU,UAAU,CAAC,YAAY,IAAI,aAAa;AAAA,IACjE;AACA,QAAI,UAAU,IAAI;AAChB,oBAAc,OAAO,OAAO,CAAC;AAAA,IAC/B;AACA,aAAS,YAAY,OAAO,QAAQ;AAAA,EACtC;AAGA,OAAK,SAAS,EAAE,GAAG,WAAW,MAAM;AAClC,eAAW,EAAE,OAAO,SAAS,KAAK,eAAe;AAC/C,eAAS,YAAY,OAAO,QAAQ;AAAA,IACtC;AACA,kBAAc,SAAS;AAAA,EACzB,CAAC;AAED,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -26,15 +26,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// packages/core/src/rooms/LobbyRoom.ts
|
|
29
31
|
var LobbyRoom_exports = {};
|
|
30
32
|
__export(LobbyRoom_exports, {
|
|
31
33
|
LobbyRoom: () => LobbyRoom
|
|
32
34
|
});
|
|
33
35
|
module.exports = __toCommonJS(LobbyRoom_exports);
|
|
34
|
-
var matchMaker = __toESM(require("../MatchMaker.
|
|
35
|
-
var import_Lobby = require("../matchmaker/Lobby.
|
|
36
|
-
var import_Room = require("../Room.
|
|
37
|
-
|
|
36
|
+
var matchMaker = __toESM(require("../MatchMaker.cjs"), 1);
|
|
37
|
+
var import_Lobby = require("../matchmaker/Lobby.cjs");
|
|
38
|
+
var import_Room = require("../Room.cjs");
|
|
39
|
+
var LobbyRoom = class extends import_Room.Room {
|
|
38
40
|
constructor() {
|
|
39
41
|
super(...arguments);
|
|
40
42
|
this.rooms = [];
|
|
@@ -116,7 +118,7 @@ class LobbyRoom extends import_Room.Room {
|
|
|
116
118
|
}
|
|
117
119
|
return isAllowed;
|
|
118
120
|
}
|
|
119
|
-
}
|
|
121
|
+
};
|
|
120
122
|
// Annotate the CommonJS export names for ESM import in node:
|
|
121
123
|
0 && (module.exports = {
|
|
122
124
|
LobbyRoom
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rooms/LobbyRoom.ts"],
|
|
4
4
|
"sourcesContent": ["\nimport * as matchMaker from '../MatchMaker.ts';\nimport type { IRoomCache } from '../matchmaker/LocalDriver/LocalDriver.ts';\nimport type { Client } from '../Transport.ts';\nimport { subscribeLobby } from '../matchmaker/Lobby.ts';\nimport { Room } from '../Room.ts';\n\n// TODO: use Schema state & filters on version 1.0.0\n\n// class DummyLobbyState extends Schema { // tslint:disable-line\n// @type(\"number\") public _: number;\n// }\n\nexport interface FilterInput {\n name?: string;\n metadata?: any;\n}\n\nexport interface LobbyOptions {\n filter?: FilterInput;\n}\n\nexport class LobbyRoom extends Room {\n public rooms: IRoomCache[] = [];\n public unsubscribeLobby: () => void;\n\n public clientOptions: { [sessionId: string]: LobbyOptions } = {};\n\n public async onCreate(options: any) {\n // prevent LobbyRoom to notify itself\n this['_listing'].unlisted = true;\n\n this.unsubscribeLobby = await subscribeLobby((roomId, data) => {\n const roomIndex = this.rooms.findIndex((room) => room.roomId === roomId);\n const clients = this.clients.filter((client) => this.clientOptions[client.sessionId]);\n\n if (!data) {\n // remove room listing data\n if (roomIndex !== -1) {\n const previousData = this.rooms[roomIndex];\n\n this.rooms.splice(roomIndex, 1);\n\n clients.forEach((client) => {\n if (this.filterItemForClient(previousData, this.clientOptions[client.sessionId].filter)) {\n client.send('-', roomId);\n }\n });\n }\n\n } else if (roomIndex === -1) {\n // append room listing data\n this.rooms.push(data);\n\n clients.forEach((client) => {\n if (this.filterItemForClient(data, this.clientOptions[client.sessionId].filter)) {\n client.send('+', [roomId, data]);\n }\n });\n\n } else {\n const previousData = this.rooms[roomIndex];\n\n // replace room listing data\n this.rooms[roomIndex] = data;\n\n clients.forEach((client) => {\n const hadData = this.filterItemForClient(previousData, this.clientOptions[client.sessionId].filter);\n const hasData = this.filterItemForClient(data, this.clientOptions[client.sessionId].filter);\n\n if (hadData && !hasData) {\n client.send('-', roomId);\n\n } else if (hasData) {\n client.send('+', [roomId, data]);\n }\n });\n }\n });\n\n this.rooms = await matchMaker.query({ private: false, unlisted: false });\n\n this.onMessage('filter', (client: Client, filter: FilterInput) => {\n this.clientOptions[client.sessionId].filter = filter;\n client.send('rooms', this.filterItemsForClient(this.clientOptions[client.sessionId]));\n });\n }\n\n public onJoin(client: Client, options: LobbyOptions) {\n this.clientOptions[client.sessionId] = options || {};\n client.send('rooms', this.filterItemsForClient(this.clientOptions[client.sessionId]));\n }\n\n public onLeave(client: Client) {\n delete this.clientOptions[client.sessionId];\n }\n\n public onDispose() {\n if (this.unsubscribeLobby) {\n this.unsubscribeLobby();\n }\n }\n\n protected filterItemsForClient(options: LobbyOptions) {\n const filter = options.filter;\n\n return (filter)\n ? this.rooms.filter((room) => this.filterItemForClient(room, filter))\n : this.rooms;\n }\n\n protected filterItemForClient(room: IRoomCache, filter?: LobbyOptions['filter']) {\n if (!filter) {\n return true;\n }\n\n let isAllowed = true;\n\n if (filter.name !== room.name) {\n isAllowed = false;\n }\n\n if (filter.metadata) {\n for (const field in filter.metadata) {\n if (room.metadata[field] !== filter.metadata[field]) {\n isAllowed = false;\n break;\n }\n }\n }\n\n return isAllowed;\n }\n\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,19 +16,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/rooms/RankedQueueRoom.ts
|
|
19
21
|
var RankedQueueRoom_exports = {};
|
|
20
22
|
__export(RankedQueueRoom_exports, {
|
|
21
23
|
RankedQueueRoom: () => RankedQueueRoom
|
|
22
24
|
});
|
|
23
25
|
module.exports = __toCommonJS(RankedQueueRoom_exports);
|
|
24
26
|
var import_core = require("@colyseus/core");
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
var DEFAULT_TEAM = /* @__PURE__ */ Symbol("$default_team");
|
|
28
|
+
var DEFAULT_COMPARE = (client, matchGroup) => {
|
|
27
29
|
const diff = Math.abs(client.rank - matchGroup.averageRank);
|
|
28
30
|
const diffRatio = diff / matchGroup.averageRank;
|
|
29
31
|
return diff < 10 || diffRatio <= 2;
|
|
30
32
|
};
|
|
31
|
-
|
|
33
|
+
var RankedQueueRoom = class extends import_core.Room {
|
|
32
34
|
constructor() {
|
|
33
35
|
super(...arguments);
|
|
34
36
|
this.maxPlayers = 4;
|
|
@@ -217,7 +219,7 @@ class RankedQueueRoom extends import_core.Room {
|
|
|
217
219
|
}
|
|
218
220
|
});
|
|
219
221
|
}
|
|
220
|
-
}
|
|
222
|
+
};
|
|
221
223
|
// Annotate the CommonJS export names for ESM import in node:
|
|
222
224
|
0 && (module.exports = {
|
|
223
225
|
RankedQueueRoom
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rooms/RankedQueueRoom.ts"],
|
|
4
4
|
"sourcesContent": ["import { Room, type Client, matchMaker, type IRoomCache, debugMatchMaking, ServerError, ErrorCode } from \"@colyseus/core\";\n\nexport interface RankedQueueOptions {\n /**\n * number of players on each match\n */\n maxPlayers?: number;\n\n /**\n * name of the room to create\n */\n matchRoomName: string;\n\n /**\n * after these cycles, create a match with a bot\n */\n maxWaitingCycles?: number;\n\n /**\n * after this time, try to fit this client with a not-so-compatible group\n */\n maxWaitingCyclesForPriority?: number;\n\n /**\n * If set, teams must have the same size to be matched together\n */\n maxTeamSize?: number;\n\n /**\n * If `allowIncompleteGroups` is true, players inside an unmatched group (that\n * did not reached `maxPlayers`, and `maxWaitingCycles` has been\n * reached) will be matched together. Your room should fill the remaining\n * spots with \"bots\" on this case.\n */\n allowIncompleteGroups?: boolean;\n\n /**\n * Comparison function for matching clients to groups\n * Returns true if the client is compatible with the group\n */\n compare?: (client: ClientQueueData, matchGroup: MatchGroup) => boolean;\n\n /**\n *\n * When onGroupReady is set, the \"roomNameToCreate\" option is ignored.\n */\n onGroupReady?: (this: RankedQueueRoom, group: MatchGroup) => Promise<IRoomCache>;\n}\n\nexport interface MatchGroup {\n averageRank: number;\n clients: Array<Client<{ userData: ClientQueueData }>>,\n ready?: boolean;\n confirmed?: number;\n}\n\nexport interface MatchTeam {\n averageRank: number;\n clients: Array<Client<{ userData: ClientQueueData }>>,\n teamId: string | symbol;\n}\n\nexport interface ClientQueueData {\n /**\n * Rank of the client\n */\n rank: number;\n\n /**\n * Timestamp of when the client entered the queue\n */\n currentCycle?: number;\n\n /**\n * Optional: if matching with a team, the team ID\n */\n teamId?: string;\n\n /**\n * Additional options passed by the client when joining the room\n */\n options?: any;\n\n /**\n * Match group the client is currently in\n */\n group?: MatchGroup;\n\n /**\n * Whether the client has confirmed the connection to the room\n */\n confirmed?: boolean;\n\n /**\n * Whether the client should be prioritized in the queue\n * (e.g. for players that are waiting for a long time)\n */\n highPriority?: boolean;\n\n /**\n * The last number of clients in the queue sent to the client\n */\n lastQueueClientCount?: number;\n}\n\nconst DEFAULT_TEAM = Symbol(\"$default_team\");\nconst DEFAULT_COMPARE = (client: ClientQueueData, matchGroup: MatchGroup) => {\n const diff = Math.abs(client.rank - matchGroup.averageRank);\n const diffRatio = (diff / matchGroup.averageRank);\n // If diff ratio is too high, create a new match group\n return (diff < 10 || diffRatio <= 2);\n}\n\nexport class RankedQueueRoom extends Room {\n maxPlayers = 4;\n maxTeamSize: number;\n allowIncompleteGroups: boolean = false;\n\n maxWaitingCycles = 15;\n maxWaitingCyclesForPriority?: number = 10;\n\n /**\n * Evaluate groups for each client at interval\n */\n cycleTickInterval = 1000;\n\n /**\n * Groups of players per iteration\n */\n groups: MatchGroup[] = [];\n highPriorityGroups: MatchGroup[] = [];\n\n matchRoomName: string;\n\n protected compare = DEFAULT_COMPARE;\n protected onGroupReady = (group: MatchGroup) => matchMaker.createRoom(this.matchRoomName, {});\n\n messages = {\n confirm: (client: Client, _: unknown) => {\n const queueData = client.userData;\n\n if (queueData && queueData.group && typeof (queueData.group.confirmed) === \"number\") {\n queueData.confirmed = true;\n queueData.group.confirmed++;\n client.leave();\n }\n },\n }\n\n onCreate(options: RankedQueueOptions) {\n if (typeof(options.maxWaitingCycles) === \"number\") {\n this.maxWaitingCycles = options.maxWaitingCycles;\n }\n\n if (typeof(options.maxPlayers) === \"number\") {\n this.maxPlayers = options.maxPlayers;\n }\n\n if (typeof(options.maxTeamSize) === \"number\") {\n this.maxTeamSize = options.maxTeamSize;\n }\n\n if (typeof(options.allowIncompleteGroups) !== \"undefined\") {\n this.allowIncompleteGroups = options.allowIncompleteGroups;\n }\n\n if (typeof(options.compare) === \"function\") {\n this.compare = options.compare;\n }\n\n if (typeof(options.onGroupReady) === \"function\") {\n this.onGroupReady = options.onGroupReady;\n }\n\n if (options.matchRoomName) {\n this.matchRoomName = options.matchRoomName;\n\n } else {\n throw new ServerError(ErrorCode.APPLICATION_ERROR, \"RankedQueueRoom: 'matchRoomName' option is required.\");\n }\n\n debugMatchMaking(\"RankedQueueRoom#onCreate() maxPlayers: %d, maxWaitingCycles: %d, maxTeamSize: %d, allowIncompleteGroups: %d, roomNameToCreate: %s\", this.maxPlayers, this.maxWaitingCycles, this.maxTeamSize, this.allowIncompleteGroups, this.matchRoomName);\n\n /**\n * Redistribute clients into groups at every interval\n */\n this.setSimulationInterval(() => this.reassignMatchGroups(), this.cycleTickInterval);\n }\n\n onJoin(client: Client, options: any, auth?: unknown) {\n this.addToQueue(client, {\n rank: options.rank,\n teamId: options.teamId,\n options,\n });\n }\n\n addToQueue(client: Client, queueData: ClientQueueData) {\n if (queueData.currentCycle === undefined) {\n queueData.currentCycle = 0;\n }\n client.userData = queueData;\n\n // FIXME: reassign groups upon joining [?] (without incrementing cycle count)\n client.send(\"clients\", 1);\n }\n\n createMatchGroup() {\n const group: MatchGroup = { clients: [], averageRank: 0 };\n this.groups.push(group);\n return group;\n }\n\n reassignMatchGroups() {\n // Re-set all groups\n this.groups.length = 0;\n this.highPriorityGroups.length = 0;\n\n const sortedClients = (this.clients)\n .filter((client) => {\n // Filter out:\n // - clients that are not in the queue\n // - clients that are already in a \"ready\" group\n return (\n client.userData &&\n client.userData.group?.ready !== true\n );\n })\n .sort((a, b) => {\n //\n // Sort by rank ascending\n //\n return a.userData.rank - b.userData.rank;\n });\n\n //\n // The room either distribute by teams or by clients\n //\n if (typeof(this.maxTeamSize) === \"number\") {\n this.redistributeTeams(sortedClients);\n\n } else {\n this.redistributeClients(sortedClients);\n }\n\n this.evaluateHighPriorityGroups();\n this.processGroupsReady();\n }\n\n redistributeTeams(sortedClients: Client<{ userData: ClientQueueData }>[]) {\n const teamsByID: { [teamId: string | symbol]: MatchTeam } = {};\n\n sortedClients.forEach((client) => {\n const teamId = client.userData.teamId || DEFAULT_TEAM;\n\n // Create a new team if it doesn't exist\n if (!teamsByID[teamId]) {\n teamsByID[teamId] = { teamId: teamId, clients: [], averageRank: 0, };\n }\n\n teamsByID[teamId].averageRank += client.userData.rank;\n teamsByID[teamId].clients.push(client);\n });\n\n // Calculate average rank for each team\n let teams = Object.values(teamsByID).map((team) => {\n team.averageRank /= team.clients.length;\n return team;\n }).sort((a, b) => {\n // Sort by average rank ascending\n return a.averageRank - b.averageRank;\n });\n\n // Iterate over teams multiple times until all clients are assigned to a group\n do {\n let currentGroup: MatchGroup = this.createMatchGroup();\n teams = teams.filter((team) => {\n // Remove clients from the team and add them to the current group\n const totalRank = team.averageRank * team.clients.length;\n\n // currentGroup.averageRank = (currentGroup.averageRank === undefined)\n // ? team.averageRank\n // : (currentGroup.averageRank + team.averageRank) / ;\n currentGroup = this.redistributeClients(team.clients.splice(0, this.maxTeamSize), currentGroup, totalRank);\n\n if (team.clients.length >= this.maxTeamSize) {\n // team still has enough clients to form a group\n return true;\n }\n\n // increment cycle count for all clients in the team\n team.clients.forEach((client) => client.userData.currentCycle++);\n\n return false;\n });\n } while (teams.length >= 2);\n }\n\n redistributeClients(\n sortedClients: Client<{ userData: ClientQueueData }>[],\n currentGroup: MatchGroup = this.createMatchGroup(),\n totalRank: number = 0,\n ) {\n for (let i = 0, l = sortedClients.length; i < l; i++) {\n const client = sortedClients[i];\n const userData = client.userData;\n const currentCycle = userData.currentCycle++;\n\n if (currentGroup.averageRank > 0) {\n if (\n !this.compare(userData, currentGroup) &&\n !userData.highPriority\n ) {\n currentGroup = this.createMatchGroup();\n totalRank = 0;\n }\n }\n\n userData.group = currentGroup;\n currentGroup.clients.push(client);\n\n totalRank += userData.rank;\n currentGroup.averageRank = totalRank / currentGroup.clients.length;\n\n // Enough players in the group, mark it as ready!\n if (currentGroup.clients.length === this.maxPlayers) {\n currentGroup.ready = true;\n currentGroup = this.createMatchGroup();\n totalRank = 0;\n continue;\n }\n\n if (currentCycle >= this.maxWaitingCycles && this.allowIncompleteGroups) {\n /**\n * Match long-waiting clients with bots\n */\n if (this.highPriorityGroups.indexOf(currentGroup) === -1) {\n this.highPriorityGroups.push(currentGroup);\n }\n\n } else if (\n this.maxWaitingCyclesForPriority !== undefined &&\n currentCycle >= this.maxWaitingCyclesForPriority\n ) {\n /**\n * Force this client to join a group, even if rank is incompatible\n */\n userData.highPriority = true;\n }\n }\n\n return currentGroup;\n }\n\n evaluateHighPriorityGroups() {\n /**\n * Evaluate groups with high priority clients\n */\n this.highPriorityGroups.forEach((group) => {\n group.ready = group.clients.every((c) => {\n // Give new clients another chance to join a group that is not \"high priority\"\n return c.userData?.currentCycle > 1;\n // return c.userData?.currentCycle >= this.maxWaitingCycles;\n });\n });\n }\n\n processGroupsReady() {\n this.groups.forEach(async (group) => {\n if (group.ready) {\n group.confirmed = 0;\n\n try {\n /**\n * Create room instance in the server.\n */\n const room = await this.onGroupReady.call(this, group);\n\n /**\n * Reserve a seat for each client in the group.\n * (If one fails, force all clients to leave, re-queueing is up to the client-side logic)\n */\n await matchMaker.reserveMultipleSeatsFor(\n room,\n group.clients.map((client) => ({\n sessionId: client.sessionId,\n options: client.userData.options,\n auth: client.auth,\n })),\n );\n\n /**\n * Send room data for new WebSocket connection!\n */\n group.clients.forEach((client, i) => {\n client.send(\"seat\", matchMaker.buildSeatReservation(room, client.sessionId));\n });\n\n } catch (e: any) {\n //\n // If creating a room, or reserving a seat failed - fail all clients\n // Whether the clients retry or not is up to the client-side logic\n //\n group.clients.forEach(client => client.leave(1011, e.message));\n }\n\n } else {\n /**\n * Notify clients within the group on how many players are in the queue\n */\n group.clients.forEach((client) => {\n //\n // avoid sending the same number of clients to the client if it hasn't changed\n //\n const queueClientCount = group.clients.length;\n if (client.userData.lastQueueClientCount !== queueClientCount) {\n client.userData.lastQueueClientCount = queueClientCount;\n client.send(\"clients\", queueClientCount);\n }\n });\n }\n });\n }\n\n}"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,31 +16,33 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/rooms/RelayRoom.ts
|
|
19
21
|
var RelayRoom_exports = {};
|
|
20
22
|
__export(RelayRoom_exports, {
|
|
21
23
|
RelayRoom: () => RelayRoom
|
|
22
24
|
});
|
|
23
25
|
module.exports = __toCommonJS(RelayRoom_exports);
|
|
24
26
|
var import_schema = require("@colyseus/schema");
|
|
25
|
-
var import_Room = require("../Room.
|
|
26
|
-
var import_Protocol = require("../Protocol.
|
|
27
|
-
|
|
28
|
-
}
|
|
27
|
+
var import_Room = require("../Room.cjs");
|
|
28
|
+
var import_Protocol = require("../Protocol.cjs");
|
|
29
|
+
var Player = class extends import_schema.Schema {
|
|
30
|
+
};
|
|
29
31
|
(0, import_schema.defineTypes)(Player, {
|
|
30
32
|
connected: "boolean",
|
|
31
33
|
name: "string",
|
|
32
34
|
sessionId: "string"
|
|
33
35
|
});
|
|
34
|
-
|
|
36
|
+
var State = class extends import_schema.Schema {
|
|
35
37
|
constructor() {
|
|
36
38
|
super(...arguments);
|
|
37
39
|
this.players = new import_schema.MapSchema();
|
|
38
40
|
}
|
|
39
|
-
}
|
|
41
|
+
};
|
|
40
42
|
(0, import_schema.defineTypes)(State, {
|
|
41
43
|
players: { map: Player }
|
|
42
44
|
});
|
|
43
|
-
|
|
45
|
+
var RelayRoom = class extends import_Room.Room {
|
|
44
46
|
constructor() {
|
|
45
47
|
super(...arguments);
|
|
46
48
|
this.state = new State();
|
|
@@ -84,7 +86,7 @@ class RelayRoom extends import_Room.Room {
|
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
|
-
}
|
|
89
|
+
};
|
|
88
90
|
// Annotate the CommonJS export names for ESM import in node:
|
|
89
91
|
0 && (module.exports = {
|
|
90
92
|
RelayRoom
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rooms/RelayRoom.ts"],
|
|
4
4
|
"sourcesContent": ["import { defineTypes, MapSchema, Schema } from '@colyseus/schema';\n\nimport { Room } from '../Room.ts';\nimport type { Client } from '../Transport.ts';\nimport { CloseCode } from '../Protocol.ts';\n\nclass Player extends Schema {\n public connected: boolean;\n public name: string;\n public sessionId: string;\n}\ndefineTypes(Player, {\n connected: 'boolean',\n name: 'string',\n sessionId: 'string',\n});\n\nclass State extends Schema {\n public players = new MapSchema<Player>();\n}\ndefineTypes(State, {\n players: { map: Player },\n});\n\n/**\n * client.joinOrCreate(\"relayroom\", {\n * maxClients: 10,\n * allowReconnectionTime: 20\n * });\n */\n\nexport class RelayRoom extends Room {\n public state = new State();\n public allowReconnectionTime: number = 0;\n\n public onCreate(options: Partial<{\n maxClients: number,\n allowReconnectionTime: number,\n metadata: any,\n }>) {\n if (options.maxClients) {\n this.maxClients = options.maxClients;\n }\n\n if (options.allowReconnectionTime) {\n this.allowReconnectionTime = Math.min(options.allowReconnectionTime, 40);\n }\n\n if (options.metadata) {\n this.setMetadata(options.metadata);\n }\n\n this.onMessage('*', (client: Client, type: string | number, message: any) => {\n this.broadcast(type, [client.sessionId, message], { except: client });\n });\n }\n\n public onJoin(client: Client, options: any = {}) {\n const player = new Player();\n\n player.connected = true;\n player.sessionId = client.sessionId;\n\n if (options.name) {\n player.name = options.name;\n }\n\n this.state.players.set(client.sessionId, player);\n }\n\n public async onLeave(client: Client, code: number) {\n if (this.allowReconnectionTime > 0) {\n const player = this.state.players.get(client.sessionId);\n player.connected = false;\n\n try {\n if (code === CloseCode.CONSENTED) {\n throw new Error('consented leave');\n }\n\n await this.allowReconnection(client, this.allowReconnectionTime);\n player.connected = true;\n\n } catch (e) {\n this.state.players.delete(client.sessionId);\n }\n }\n }\n\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+C;AAE/C,kBAAqB;AAErB,sBAA0B;AAE1B,IAAM,SAAN,cAAqB,qBAAO;AAI5B;AAAA,IACA,2BAAY,QAAQ;AAAA,EAClB,WAAW;AAAA,EACX,MAAM;AAAA,EACN,WAAW;AACb,CAAC;AAED,IAAM,QAAN,cAAoB,qBAAO;AAAA,EAA3B;AAAA;AACE,SAAO,UAAU,IAAI,wBAAkB;AAAA;AACzC;AAAA,IACA,2BAAY,OAAO;AAAA,EACjB,SAAS,EAAE,KAAK,OAAO;AACzB,CAAC;AASM,IAAM,YAAN,cAAwB,iBAAK;AAAA,EAA7B;AAAA;AACL,SAAO,QAAQ,IAAI,MAAM;AACzB,SAAO,wBAAgC;AAAA;AAAA,EAEhC,SAAS,SAIZ;AACF,QAAI,QAAQ,YAAY;AACtB,WAAK,aAAa,QAAQ;AAAA,IAC5B;AAEA,QAAI,QAAQ,uBAAuB;AACjC,WAAK,wBAAwB,KAAK,IAAI,QAAQ,uBAAuB,EAAE;AAAA,IACzE;AAEA,QAAI,QAAQ,UAAU;AACpB,WAAK,YAAY,QAAQ,QAAQ;AAAA,IACnC;AAEA,SAAK,UAAU,KAAK,CAAC,QAAgB,MAAuB,YAAiB;AAC3E,WAAK,UAAU,MAAM,CAAC,OAAO,WAAW,OAAO,GAAG,EAAE,QAAQ,OAAO,CAAC;AAAA,IACtE,CAAC;AAAA,EACH;AAAA,EAEO,OAAO,QAAgB,UAAe,CAAC,GAAG;AAC/C,UAAM,SAAS,IAAI,OAAO;AAE1B,WAAO,YAAY;AACnB,WAAO,YAAY,OAAO;AAE1B,QAAI,QAAQ,MAAM;AAChB,aAAO,OAAO,QAAQ;AAAA,IACxB;AAEA,SAAK,MAAM,QAAQ,IAAI,OAAO,WAAW,MAAM;AAAA,EACjD;AAAA,EAEA,MAAa,QAAQ,QAAgB,MAAc;AACjD,QAAI,KAAK,wBAAwB,GAAG;AAClC,YAAM,SAAS,KAAK,MAAM,QAAQ,IAAI,OAAO,SAAS;AACtD,aAAO,YAAY;AAEnB,UAAI;AACF,YAAI,SAAS,0BAAU,WAAW;AAChC,gBAAM,IAAI,MAAM,iBAAiB;AAAA,QACnC;AAEA,cAAM,KAAK,kBAAkB,QAAQ,KAAK,qBAAqB;AAC/D,eAAO,YAAY;AAAA,MAErB,SAAS,GAAG;AACV,aAAK,MAAM,QAAQ,OAAO,OAAO,SAAS;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -26,6 +26,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// packages/core/src/router/default_routes.ts
|
|
29
31
|
var default_routes_exports = {};
|
|
30
32
|
__export(default_routes_exports, {
|
|
31
33
|
getDefaultRouter: () => getDefaultRouter,
|
|
@@ -33,9 +35,9 @@ __export(default_routes_exports, {
|
|
|
33
35
|
});
|
|
34
36
|
module.exports = __toCommonJS(default_routes_exports);
|
|
35
37
|
var import_better_call = require("@colyseus/better-call");
|
|
36
|
-
var matchMaker = __toESM(require("../MatchMaker.
|
|
37
|
-
var import_Utils = require("../utils/Utils.
|
|
38
|
-
|
|
38
|
+
var matchMaker = __toESM(require("../MatchMaker.cjs"), 1);
|
|
39
|
+
var import_Utils = require("../utils/Utils.cjs");
|
|
40
|
+
var postMatchmakeMethod = (0, import_better_call.createEndpoint)("/matchmake/:method/:roomName", { method: "POST" }, async (ctx) => {
|
|
39
41
|
if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {
|
|
40
42
|
throw ctx.error(503);
|
|
41
43
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/router/default_routes.ts"],
|
|
4
4
|
"sourcesContent": ["import { createEndpoint, createRouter } from \"@colyseus/better-call\";\nimport * as matchMaker from \"../MatchMaker.ts\";\nimport { getBearerToken } from \"../utils/Utils.ts\";\n\nexport const postMatchmakeMethod = createEndpoint(\"/matchmake/:method/:roomName\", { method: \"POST\" }, async (ctx) => {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.state === matchMaker.MatchMakerState.SHUTTING_DOWN) {\n throw ctx.error(503);\n }\n\n const requestHeaders = ctx.request.headers;\n const headers = Object.assign(\n {},\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders(requestHeaders)\n );\n\n const method = ctx.params.method;\n const roomName = ctx.params.roomName;\n\n Object.entries(headers).forEach(([key, value]) => {\n ctx.setHeader(key, value);\n })\n ctx.setHeader('Content-Type', 'application/json');\n\n try {\n const clientOptions = ctx.body;\n const response = await matchMaker.controller.invokeMethod(\n method,\n roomName,\n clientOptions,\n {\n token: getBearerToken(ctx.request.headers.get('authorization')),\n headers: ctx.request.headers,\n ip: requestHeaders.get('x-forwarded-for') ?? requestHeaders.get('x-client-ip') ?? requestHeaders.get('x-real-ip'),\n req: ctx.request as any,\n },\n );\n\n //\n // TODO: respond with protocol, if available\n //\n // // specify protocol, if available.\n // if (this.transport.protocol !== undefined) {\n // response.protocol = this.transport.protocol;\n // }\n\n return response;\n\n } catch (e: any) {\n throw ctx.error(e.code, { code: e.code, error: e.message, });\n }\n\n});\n\nexport function getDefaultRouter() {\n return createRouter({ postMatchmakeMethod });\n}"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAA6C;AAC7C,iBAA4B;AAC5B,mBAA+B;AAExB,IAAM,0BAAsB,mCAAe,gCAAgC,EAAE,QAAQ,OAAO,GAAG,OAAO,QAAQ;AAEnH,MAAe,qBAAqB,2BAAgB,eAAe;AACjE,UAAM,IAAI,MAAM,GAAG;AAAA,EACrB;AAEA,QAAM,iBAAiB,IAAI,QAAQ;AACnC,QAAM,UAAU,OAAO;AAAA,IACrB,CAAC;AAAA,IACU,sBAAW;AAAA,IACX,sBAAW,eAAe,cAAc;AAAA,EACrD;AAEA,QAAM,SAAS,IAAI,OAAO;AAC1B,QAAM,WAAW,IAAI,OAAO;AAE5B,SAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAChD,QAAI,UAAU,KAAK,KAAK;AAAA,EAC1B,CAAC;AACD,MAAI,UAAU,gBAAgB,kBAAkB;AAEhD,MAAI;AACF,UAAM,gBAAgB,IAAI;AAC1B,UAAM,WAAW,MAAiB,sBAAW;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAO,6BAAe,IAAI,QAAQ,QAAQ,IAAI,eAAe,CAAC;AAAA,QAC9D,SAAS,IAAI,QAAQ;AAAA,QACrB,IAAI,eAAe,IAAI,iBAAiB,KAAK,eAAe,IAAI,aAAa,KAAK,eAAe,IAAI,WAAW;AAAA,QAChH,KAAK,IAAI;AAAA,MACX;AAAA,IACF;AAUA,WAAO;AAAA,EAET,SAAS,GAAQ;AACf,UAAM,IAAI,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,QAAS,CAAC;AAAA,EAC7D;AAEF,CAAC;AAEM,SAAS,mBAAmB;AACjC,aAAO,iCAAa,EAAE,oBAAoB,CAAC;AAC7C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/router/index.cjs
CHANGED
|
@@ -16,6 +16,8 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/router/index.ts
|
|
19
21
|
var router_exports = {};
|
|
20
22
|
__export(router_exports, {
|
|
21
23
|
__globalEndpoints: () => __globalEndpoints,
|
|
@@ -38,7 +40,7 @@ function bindRouterToServer(server, router) {
|
|
|
38
40
|
server.on("request", (0, import_node.toNodeHandler)(router.handler));
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
|
-
|
|
43
|
+
var __globalEndpoints;
|
|
42
44
|
function createRouter(endpoints, config) {
|
|
43
45
|
__globalEndpoints = endpoints;
|
|
44
46
|
return (0, import_better_call.createRouter)({ ...endpoints }, config);
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/router/index.ts"],
|
|
4
4
|
"sourcesContent": ["import type { Server } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n} from \"@colyseus/better-call\";\n\nexport { type Router, toNodeHandler };\n\nexport function bindRouterToServer(server: Server, router: Router) {\n // check if the server is bound to an express app\n const expressApp: any = server.listeners('request').find((listener: Function) =>\n listener.name === \"app\" && listener['mountpath'] === '/');\n\n if (expressApp) {\n // bind the router to the express app\n expressApp.use(toNodeHandler(router.handler));\n\n } else {\n // otherwise, bind the router to the http server\n server.on('request', toNodeHandler(router.handler));\n }\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) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints, }, config);\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,yBAAsH;AACtH,kBAA8B;AAE9B,IAAAA,sBAIO;AAIA,SAAS,mBAAmB,QAAgB,QAAgB;AAEjE,QAAM,aAAkB,OAAO,UAAU,SAAS,EAAE,KAAK,CAAC,aACxD,SAAS,SAAS,SAAS,SAAS,WAAW,MAAM,GAAG;AAE1D,MAAI,YAAY;AAEd,eAAW,QAAI,2BAAc,OAAO,OAAO,CAAC;AAAA,EAE9C,OAAO;AAEL,WAAO,GAAG,eAAW,2BAAc,OAAO,OAAO,CAAC;AAAA,EACpD;AACF;AAOO,IAAI;AAEJ,SAAS,aAGd,WAAc,QAAiB;AAE/B,sBAAoB;AAEpB,aAAO,mBAAAC,cAAuB,EAAE,GAAG,UAAW,GAAG,MAAM;AACzD;",
|
|
6
6
|
"names": ["import_better_call", "createBetterCallRouter"]
|
|
7
7
|
}
|
|
@@ -16,12 +16,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/serializer/NoneSerializer.ts
|
|
19
21
|
var NoneSerializer_exports = {};
|
|
20
22
|
__export(NoneSerializer_exports, {
|
|
21
23
|
NoneSerializer: () => NoneSerializer
|
|
22
24
|
});
|
|
23
25
|
module.exports = __toCommonJS(NoneSerializer_exports);
|
|
24
|
-
|
|
26
|
+
var NoneSerializer = class {
|
|
25
27
|
constructor() {
|
|
26
28
|
this.id = "none";
|
|
27
29
|
}
|
|
@@ -33,7 +35,7 @@ class NoneSerializer {
|
|
|
33
35
|
applyPatches(clients, state) {
|
|
34
36
|
return false;
|
|
35
37
|
}
|
|
36
|
-
}
|
|
38
|
+
};
|
|
37
39
|
// Annotate the CommonJS export names for ESM import in node:
|
|
38
40
|
0 && (module.exports = {
|
|
39
41
|
NoneSerializer
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/serializer/NoneSerializer.ts"],
|
|
4
4
|
"sourcesContent": ["import type { Client } from '../Transport.ts';\nimport type { Serializer } from './Serializer.ts';\n\nexport class NoneSerializer<T= any> implements Serializer<T> {\n public id: string = 'none';\n\n public reset(data: any) {}\n\n public getFullState(client?: Client) {\n return null;\n }\n\n public applyPatches(clients: Client[], state: T): boolean {\n return false;\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,IAAM,iBAAN,MAAsD;AAAA,EAAtD;AACL,SAAO,KAAa;AAAA;AAAA,EAEb,MAAM,MAAW;AAAA,EAAC;AAAA,EAElB,aAAa,QAAiB;AACnC,WAAO;AAAA,EACT;AAAA,EAEO,aAAa,SAAmB,OAAmB;AACxD,WAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,17 +16,19 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/core/src/serializer/SchemaSerializer.ts
|
|
19
21
|
var SchemaSerializer_exports = {};
|
|
20
22
|
__export(SchemaSerializer_exports, {
|
|
21
23
|
SchemaSerializer: () => SchemaSerializer
|
|
22
24
|
});
|
|
23
25
|
module.exports = __toCommonJS(SchemaSerializer_exports);
|
|
24
|
-
var import_Transport = require("../Transport.
|
|
26
|
+
var import_Transport = require("../Transport.cjs");
|
|
25
27
|
var import_schema = require("@colyseus/schema");
|
|
26
|
-
var import_Debug = require("../Debug.
|
|
27
|
-
var import_Protocol = require("../Protocol.
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
var import_Debug = require("../Debug.cjs");
|
|
29
|
+
var import_Protocol = require("../Protocol.cjs");
|
|
30
|
+
var SHARED_VIEW = {};
|
|
31
|
+
var SchemaSerializer = class {
|
|
30
32
|
constructor() {
|
|
31
33
|
this.id = "schema";
|
|
32
34
|
this.hasFilters = false;
|
|
@@ -132,7 +134,7 @@ class SchemaSerializer {
|
|
|
132
134
|
}
|
|
133
135
|
return this.handshakeCache;
|
|
134
136
|
}
|
|
135
|
-
}
|
|
137
|
+
};
|
|
136
138
|
// Annotate the CommonJS export names for ESM import in node:
|
|
137
139
|
0 && (module.exports = {
|
|
138
140
|
SchemaSerializer
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/serializer/SchemaSerializer.ts"],
|
|
4
4
|
"sourcesContent": ["import type { Serializer } from './Serializer.ts';\nimport { type Client, ClientState } from '../Transport.ts';\n\nimport { type Iterator, Encoder, dumpChanges, Reflection, Schema, StateView } from '@colyseus/schema';\nimport { debugPatch } from '../Debug.ts';\nimport { Protocol } from '../Protocol.ts';\n\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializer<T extends Schema> implements Serializer<T> {\n public id = 'schema';\n\n protected encoder: Encoder<T>;\n protected hasFilters: boolean = false;\n\n protected handshakeCache: Uint8Array;\n\n // flag to avoid re-encoding full state if no changes were made\n protected needFullEncode: boolean = true;\n\n // TODO: make this optional. allocating a new buffer for each room may not be always necessary.\n protected fullEncodeBuffer: Uint8Array = new Uint8Array(Encoder.BUFFER_SIZE);\n protected fullEncodeCache: Uint8Array;\n protected sharedOffsetCache: Iterator = { offset: 0 };\n\n protected encodedViews: Map<StateView | typeof SHARED_VIEW, Uint8Array>;\n\n public reset(newState: T & Schema) {\n this.encoder = new Encoder(newState);\n this.hasFilters = this.encoder.context.hasFilters;\n\n // cache ROOM_STATE byte as part of the encoded buffer\n this.fullEncodeBuffer[0] = Protocol.ROOM_STATE;\n\n if (this.hasFilters) {\n this.encodedViews = new Map();\n }\n }\n\n public getFullState(client?: Client) {\n if (this.needFullEncode || this.encoder.root.changes.next !== undefined) {\n this.sharedOffsetCache = { offset: 1 };\n this.fullEncodeCache = this.encoder.encodeAll(this.sharedOffsetCache, this.fullEncodeBuffer);\n this.needFullEncode = false;\n }\n\n if (this.hasFilters && client?.view) {\n return this.encoder.encodeAllView(\n client.view,\n this.sharedOffsetCache.offset,\n { ...this.sharedOffsetCache },\n this.fullEncodeBuffer\n );\n\n } else {\n return this.fullEncodeCache;\n }\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n\n if (numClients === 0) {\n // skip patching and clear changes\n this.encoder.discardChanges();\n return false;\n }\n\n if (!this.encoder.hasChanges) {\n\n // check if views have changes (manual add() or remove() items)\n if (this.hasFilters) {\n //\n // FIXME: refactor this to avoid duplicating code.\n //\n // it's probably better to have 2 different 'applyPatches' methods.\n // (one for handling state with filters, and another for handling state without filters)\n //\n const clientsWithViewChange = clients.filter((client) => {\n return client.state === ClientState.JOINED && client.view?.changes.size > 0\n });\n\n if (clientsWithViewChange.length > 0) {\n const it: Iterator = { offset: 1 };\n\n const sharedOffset = it.offset;\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n clientsWithViewChange.forEach((client) => {\n client.raw(this.encoder.encodeView(client.view, sharedOffset, it));\n });\n }\n }\n\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n this.needFullEncode = true;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.encodedViews.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.encodedViews.set(view, encodedView);\n }\n\n client.raw(encodedView);\n }\n\n // clear views\n this.encodedViews.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake() {\n /**\n * Cache handshake to avoid encoding it for each client joining\n */\n if (!this.handshakeCache) {\n //\n // TODO: re-use handshake buffer for all rooms of same type (?)\n //\n this.handshakeCache = (this.encoder.state && Reflection.encode(this.encoder));\n }\n\n return this.handshakeCache;\n }\n\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["it"]
|
|
7
7
|
}
|
|
@@ -1,29 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
|
-
var import_fs = __toESM(require("fs"), 1);
|
|
2
|
+
|
|
3
|
+
// packages/core/src/serializer/SchemaSerializerDebug.ts
|
|
4
|
+
var import_fs = require("fs");
|
|
25
5
|
var import_schema = require("@colyseus/schema");
|
|
26
|
-
var import_SchemaSerializer = require("./SchemaSerializer.
|
|
27
|
-
var import_Transport = require("../Transport.
|
|
28
|
-
var import_Protocol = require("../Protocol.
|
|
29
|
-
var import_Debug = require("../Debug.
|
|
6
|
+
var import_SchemaSerializer = require("./SchemaSerializer.cjs");
|
|
7
|
+
var import_Transport = require("../Transport.cjs");
|
|
8
|
+
var import_Protocol = require("../Protocol.cjs");
|
|
9
|
+
var import_Debug = require("../Debug.cjs");
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/serializer/SchemaSerializerDebug.ts"],
|
|
4
4
|
"sourcesContent": ["/**\n * This serializer is a copy of SchemaSerializer,\n * but it writes debug information to a file.\n *\n * This script must be used\n */\n\nimport fs from 'fs';\nimport { Schema, dumpChanges, Iterator } from '@colyseus/schema';\nimport { SchemaSerializer } from './SchemaSerializer.ts';\nimport { Client, ClientState } from \"../Transport.ts\";\nimport { Protocol} from '../Protocol.ts';\nimport { debugPatch } from '../Debug.ts';\n\n/*\nconst SHARED_VIEW = {};\n\nexport class SchemaSerializerDebug<T> extends SchemaSerializer<T> {\n protected debugStream: fs.WriteStream;\n\n constructor(fileName: string = \"schema-debug.txt\") {\n super();\n\n try { fs.unlinkSync(fileName); } catch (e) {}\n this.debugStream = fs.createWriteStream(fileName, { flags: \"a\" });\n }\n\n public getFullState(client?: Client): Buffer {\n const buf = super.getFullState(client);\n this.debugStream.write(`state:${client.sessionId}:${Array.from(buf).slice(1).join(\",\")}\\n`);\n return buf;\n }\n\n public applyPatches(clients: Client[]) {\n let numClients = clients.length;\n\n const debugChangesDeep = Schema.debugChangesDeep(this.encoder.state);\n\n if (\n numClients == 0 ||\n (\n this.encoder.root.changes.size === 0 &&\n (!this.hasFilters || this.encoder.root.filteredChanges.size === 0)\n )\n ) {\n // skip patching state if:\n // - no clients are connected\n // - no changes were made\n // - no \"filtered changes\" were made when using filters\n return false;\n }\n\n this.needFullEncode = true;\n\n // dump changes for patch debugging\n if (debugPatch.enabled) {\n (debugPatch as any).dumpChanges = dumpChanges(this.encoder.state);\n }\n\n // get patch bytes\n const it: Iterator = { offset: 1 };\n this.encoder.sharedBuffer[0] = Protocol.ROOM_STATE_PATCH;\n\n // encode changes once, for all clients\n const encodedChanges = this.encoder.encode(it);\n\n if (!this.hasFilters) {\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n debugChangesDeep.split(\"\\n\").forEach((line) => {\n this.debugStream.write(`#${client.sessionId}:${line}\\n`);\n });\n this.debugStream.write(`patch:${client.sessionId}:${Array.from(encodedChanges).slice(1).join(\",\")}\\n`);\n\n client.raw(encodedChanges);\n }\n\n } else {\n // cache shared offset\n const sharedOffset = it.offset;\n\n // encode state multiple times, for each client\n while (numClients--) {\n const client = clients[numClients];\n\n //\n // FIXME: avoid this check for each client\n //\n if (client.state !== ClientState.JOINED) {\n continue;\n }\n\n const view = client.view || SHARED_VIEW;\n\n let encodedView = this.views.get(view);\n\n // allow to pass the same encoded view for multiple clients\n if (encodedView === undefined) {\n encodedView = (view === SHARED_VIEW)\n ? encodedChanges\n : this.encoder.encodeView(client.view, sharedOffset, it);\n this.views.set(view, encodedView);\n }\n\n debugChangesDeep.split(\"\\n\").forEach((line) => {\n this.debugStream.write(`#${client.sessionId}:${line}\\n`);\n });\n this.debugStream.write(`patch:${client.sessionId}:${Array.from(encodedView).slice(1).join(\",\")}\\n`);\n\n client.raw(encodedView);\n }\n\n // clear views\n this.views.clear();\n }\n\n // discard changes after sending\n this.encoder.discardChanges();\n\n // debug patches\n if (debugPatch.enabled) {\n debugPatch(\n '%d bytes sent to %d clients, %j',\n encodedChanges.length,\n clients.length,\n (debugPatch as any).dumpChanges,\n );\n }\n\n return true;\n }\n\n public handshake(): Buffer {\n const buf = super.handshake();\n this.debugStream.write(`handshake:${Array.from(buf).join(\",\")}\\n`);\n return buf;\n }\n}\n\n*/"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;AAOA,gBAAe;AACf,oBAA8C;AAC9C,8BAAiC;AACjC,uBAAqC;AACrC,sBAAwB;AACxB,mBAA2B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|