{
  "version": 3,
  "sources": ["../../src/serializer/SchemaSerializer.ts"],
  "sourcesContent": ["import { Protocol } from '@colyseus/shared-types';\n\nimport 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';\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      if (this.encoder.hasChanges) {\n        // if there are changes but no clients, we need to encode full state on next patch\n        this.needFullEncode = true;\n      }\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"],
  "mappings": "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",
  "names": ["it"]
}
