### Implement MapSchema for Synchronized Key-Value Maps Source: https://context7.com/colyseus/schema/llms.txt Demonstrates defining a schema with MapSchema properties and performing key-based operations like set, get, delete, and iteration. ```typescript import { Schema, type, MapSchema, Encoder, Decoder } from '@colyseus/schema'; class Entity extends Schema { @type("string") type: string; @type("float32") x: number = 0; @type("float32") y: number = 0; @type("int32") health: number = 100; } class GameState extends Schema { @type({ map: Entity }) entities = new MapSchema(); @type({ map: "number" }) scores = new MapSchema(); @type({ map: "string" }) metadata = new MapSchema(); } const state = new GameState(); // Set values const player = new Entity(); player.type = "player"; player.x = 100; player.y = 200; state.entities.set("player_abc123", player); const enemy = new Entity(); enemy.type = "enemy"; state.entities.set("enemy_001", enemy); // Set primitive values state.scores.set("player_abc123", 1500); state.metadata.set("mapName", "dungeon_level_1"); // Get values const entity = state.entities.get("player_abc123"); const score = state.scores.get("player_abc123"); // Check existence if (state.entities.has("player_abc123")) { console.log("Player exists!"); } // Delete state.entities.delete("enemy_001"); // Iteration state.entities.forEach((entity, id) => { console.log(`${id}: ${entity.type} at (${entity.x}, ${entity.y})`); }); // Get keys, values, entries const entityIds = Array.from(state.entities.keys()); const allEntities = Array.from(state.entities.values()); const entries = Array.from(state.entities.entries()); // Size console.log(`Total entities: ${state.entities.size}`); // Clear all state.entities.clear(); // Clone const clonedEntities = state.entities.clone(); // Convert to JSON const json = state.entities.toJSON(); // Output: { "player_abc123": { type: "player", x: 100, y: 200, health: 100 } } ``` -------------------------------- ### Generate Bundled C# Schema Files Source: https://github.com/colyseus/schema/blob/master/README.md Generate a single bundled C# schema file for Unity projects. Use the `--bundle` option to combine all schema classes into one file. ```bash # Generate a single bundled file schema-codegen ./schemas/State.ts --output ./unity-project/ --csharp --bundle # With namespace schema-codegen ./schemas/State.ts --output ./unity-project/ --csharp --bundle --namespace MyGame.Schema ``` -------------------------------- ### Serialize and Restore Schema Instances Source: https://context7.com/colyseus/schema/llms.txt Demonstrates defining schema classes, converting instances to JSON for storage, and restoring them back into schema instances. ```typescript import { Schema, type, ArraySchema, MapSchema, ToJSON } from '@colyseus/schema'; class Item extends Schema { @type("string") id: string; @type("string") name: string; @type("uint32") stackSize: number = 1; } class Player extends Schema { @type("string") name: string; @type("int32") level: number = 1; @type("int32") experience: number = 0; @type([Item]) inventory = new ArraySchema(); @type({ map: "number" }) stats = new MapSchema(); } // Create and populate const player = new Player(); player.name = "Hero"; player.level = 10; player.experience = 5000; const sword = new Item(); sword.id = "item_001"; sword.name = "Steel Sword"; sword.stackSize = 1; player.inventory.push(sword); player.stats.set("strength", 15); player.stats.set("agility", 12); // Convert to JSON const json: ToJSON = player.toJSON(); console.log(JSON.stringify(json, null, 2)); // Output: // { // "name": "Hero", // "level": 10, // "experience": 5000, // "inventory": [ // { "id": "item_001", "name": "Steel Sword", "stackSize": 1 } // ], // "stats": { "strength": 15, "agility": 12 } // } // Save to database/file await saveToDatabase(player.toJSON()); // Restore from JSON const loadedJson = await loadFromDatabase(); const restoredPlayer = new Player(); restoredPlayer.restore(loadedJson); console.log(restoredPlayer.name); // "Hero" console.log(restoredPlayer.inventory.at(0).name); // "Steel Sword" console.log(restoredPlayer.stats.get("strength")); // 15 // Clone a schema instance const clonedPlayer = player.clone(); clonedPlayer.name = "Clone"; console.log(player.name); // "Hero" (unchanged) console.log(clonedPlayer.name); // "Clone" ``` -------------------------------- ### Initialize Decoder Source: https://github.com/colyseus/schema/blob/master/README.md Instantiate the Decoder with your state object and use it to decode incoming binary data from the server. ```typescript import { Decoder } from "@colyseus/schema"; const state = new MyState(); const decoder = new Decoder(state); decoder.decode(encodedBytes); ``` -------------------------------- ### Initialize Encoder Source: https://github.com/colyseus/schema/blob/master/README.md Instantiate the Encoder with your state object. This is the first step before encoding any state. ```typescript import { Encoder } from "@colyseus/schema"; const state = new MyState(); const encoder = new Encoder(state); ``` -------------------------------- ### Generate C/C++ Schema Files Source: https://github.com/colyseus/schema/blob/master/README.md Command to generate C/C++ schema files. Specify the input TypeScript schema and the output directory for the generated headers. ```bash # C/C++ schema-codegen ./schemas/State.ts --output ./cpp-project/ --cpp ``` -------------------------------- ### Generate C# Schema Files Source: https://github.com/colyseus/schema/blob/master/README.md Command to generate C# schema files for Unity projects from TypeScript schema definitions. Specify input and output paths. ```bash # C#/Unity schema-codegen ./schemas/State.ts --output ./unity-project/ --csharp ``` -------------------------------- ### Code Generation for Other Languages Source: https://context7.com/colyseus/schema/llms.txt Use the schema-codegen CLI to generate client-side schema classes for C#, C++, Haxe, Lua, Java, and GDScript, enabling strongly-typed state synchronization in various game engines. ```bash # Generate C# classes for Unity schema-codegen ./src/schemas/GameState.ts --output ./unity-project/Assets/Schema --csharp ``` ```bash # Generate C# with namespace schema-codegen ./src/schemas/*.ts --output ./unity-project/Assets/Schema --csharp --namespace MyGame.Schema ``` ```bash # Generate bundled single file schema-codegen ./src/schemas/GameState.ts --output ./build --csharp --bundle ``` ```bash # Generate C++ headers schema-codegen ./src/schemas/GameState.ts --output ./cpp-project/include --cpp ``` ```bash # Generate Haxe classes schema-codegen ./src/schemas/GameState.ts --output ./haxe-project/src --haxe ``` ```bash # Generate Lua modules schema-codegen ./src/schemas/GameState.ts --output ./defold-project/schema --lua ``` ```bash # Generate Java classes schema-codegen ./src/schemas/GameState.ts --output ./android-project/src --java ``` ```bash # Generate GDScript for Godot schema-codegen ./src/schemas/GameState.ts --output ./godot-project/schema --gdscript ``` -------------------------------- ### Generate Haxe Schema Files Source: https://github.com/colyseus/schema/blob/master/README.md Command to generate Haxe schema files. Specify the input TypeScript schema and the output directory for the Haxe code. ```bash # Haxe schema-codegen ./schemas/State.ts --output ./haxe-project/ --haxe ``` -------------------------------- ### Listen to State Changes with Callbacks API Source: https://context7.com/colyseus/schema/llms.txt Use the Callbacks API to listen for root property changes, collection additions/removals, and bind state to UI objects. Import necessary classes from '@colyseus/schema'. ```typescript import { Schema, type, Decoder, Callbacks, MapSchema, ArraySchema } from '@colyseus/schema'; class Player extends Schema { @type("string") name: string; @type("int32") health: number = 100; @type("float32") x: number = 0; @type("float32") y: number = 0; } class GameState extends Schema { @type("string") phase: string = "lobby"; @type({ map: Player }) players = new MapSchema(); @type(["string"]) messages = new ArraySchema(); } const state = new GameState(); const decoder = new Decoder(state); const $ = Callbacks.get(decoder); // Listen to root property changes const unsubPhase = $.listen("phase", (currentPhase, previousPhase) => { console.log(`Phase changed: ${previousPhase} -> ${currentPhase}`); }); // Listen when players are added $.onAdd("players", (player, sessionId) => { console.log(`Player ${sessionId} joined: ${player.name}`); // Listen to nested property changes $.listen(player, "health", (health, prevHealth) => { console.log(`${player.name} health: ${prevHealth} -> ${health}`); }); // Listen to any property change on the player $.onChange(player, () => { console.log(`Player ${player.name} position: (${player.x}, ${player.y})`); }); }); // Listen when players are removed $.onRemove("players", (player, sessionId) => { console.log(`Player ${sessionId} left: ${player.name}`); }); // Listen to collection changes $.onChange("messages", (index, message) => { console.log(`Message at ${index}: ${message}`); }); // Bind properties to a UI object const playerUI = { name: "", health: 0, x: 0, y: 0 }; state.players.forEach((player) => { $.bindTo(player, playerUI, ["name", "health", "x", "y"]); }); // Unsubscribe when done unsubPhase(); ``` -------------------------------- ### Schema Code Generation CLI Source: https://github.com/colyseus/schema/blob/master/README.md Command-line utility to generate client-side schema definitions for strictly typed languages like C#, C++, and Haxe. ```APIDOC ## schema-codegen ### Description Generates client-side schema files from TypeScript definitions to ensure type safety in compiled languages. ### Usage `schema-codegen [input_file] --output [directory] --[language]` ### Options - **--output**: The output directory for generated files (Required). - **--bundle**: Combines all generated classes into a single file. - **--namespace**: Defines a namespace or package for the generated code. - **--decorator**: Specifies a custom name for the @type decorator to scan. ``` -------------------------------- ### Encode Schema State and Deltas Source: https://context7.com/colyseus/schema/llms.txt Use encodeAll for initial synchronization and encode for delta patches. Always call discardChanges after broadcasting to reset tracking. ```typescript import { Schema, type, Encoder, MapSchema } from '@colyseus/schema'; class Player extends Schema { @type("string") name: string; @type("int32") score: number = 0; } class GameState extends Schema { @type("string") phase: string = "waiting"; @type({ map: Player }) players = new MapSchema(); } // Server-side encoding const state = new GameState(); const encoder = new Encoder(state); // Full encode for new client connection const fullState: Uint8Array = encoder.encodeAll(); // Send fullState to newly connected client // Make changes state.phase = "playing"; const player = new Player(); player.name = "Alice"; player.score = 100; state.players.set("session123", player); // Delta encode only the changes const deltaBuffer: Uint8Array = encoder.encode(); // Send deltaBuffer to all connected clients // Discard tracked changes after broadcasting encoder.discardChanges(); // More changes player.score = 150; state.players.get("session123").score = 200; // Next delta patch const nextDelta: Uint8Array = encoder.encode(); encoder.discardChanges(); // Check if there are pending changes if (encoder.hasChanges) { const changes = encoder.encode(); // broadcast changes encoder.discardChanges(); } ``` -------------------------------- ### Implement ArraySchema for Synchronized Arrays Source: https://context7.com/colyseus/schema/llms.txt Demonstrates defining a schema with ArraySchema properties and performing standard array operations like push, pop, shift, and move. ```typescript import { Schema, type, ArraySchema, Encoder, Decoder } from '@colyseus/schema'; class Item extends Schema { @type("string") name: string; @type("uint32") quantity: number = 1; } class Inventory extends Schema { @type([Item]) items = new ArraySchema(); @type(["string"]) tags = new ArraySchema(); @type(["number"]) scores = new ArraySchema(); } const inventory = new Inventory(); // Push items const sword = new Item(); sword.name = "Sword"; sword.quantity = 1; inventory.items.push(sword); const shield = new Item(); shield.name = "Shield"; inventory.items.push(shield); // Push primitives inventory.tags.push("rare", "legendary"); inventory.scores.push(100, 200, 300); // Array operations inventory.items.pop(); // Remove last inventory.items.shift(); // Remove first inventory.items.unshift(sword); // Add to beginning inventory.items.splice(0, 1, shield); // Remove and insert // Access items const firstItem = inventory.items.at(0); const lastItem = inventory.items.at(-1); // Iteration inventory.items.forEach((item, index) => { console.log(`${index}: ${item.name} x${item.quantity}`); }); const itemNames = inventory.items.map(item => item.name); const rareItems = inventory.items.filter(item => item.quantity > 1); const hasWeapon = inventory.items.some(item => item.name === "Sword"); // Sorting inventory.scores.sort((a, b) => b - a); // Descending // Move items (efficient reordering) inventory.items.move((items) => { [items[0], items[1]] = [items[1], items[0]]; // Swap positions }); // Shuffle inventory.items.shuffle(); // Clear all inventory.items.clear(); // Clone const clonedItems = inventory.items.clone(); // Convert to JSON const json = inventory.items.toJSON(); ``` -------------------------------- ### Dynamic Schema Discovery with Reflection Source: https://context7.com/colyseus/schema/llms.txt Use Reflection to encode schema definitions, allowing clients to decode state without pre-defined schema classes. This is useful for dynamic content or debugging tools. ```typescript import { Schema, type, Reflection, Encoder, Decoder, MapSchema } from '@colyseus/schema'; class Player extends Schema { @type("string") name: string; @type("int32") level: number = 1; @type("float32") x: number = 0; @type("float32") y: number = 0; } class GameState extends Schema { @type("string") roomName: string = "default"; @type({ map: Player }) players = new MapSchema(); } // Server: Encode reflection + state const state = new GameState(); state.roomName = "Arena"; const player = new Player(); player.name = "Hero"; player.level = 5; state.players.set("p1", player); const encoder = new Encoder(state); // Encode schema reflection (type definitions) const reflectionBytes = Reflection.encode(encoder); // Encode full state const stateBytes = encoder.encodeAll(); // Client: Decode without knowing schema classes function onConnect(reflectionData: Uint8Array, stateData: Uint8Array) { // Decode reflection to create dynamic decoder const decoder = Reflection.decode(reflectionData); // Decode state into dynamically created schema instances decoder.decode(stateData); // Access state dynamically const dynamicState = decoder.state as any; console.log("Room:", dynamicState.roomName); dynamicState.players.forEach((player: any, id: string) => { console.log(`Player ${id}: ${player.name} (level ${player.level})`); }); } // Send reflection first, then state onConnect(reflectionBytes, stateBytes); ``` -------------------------------- ### Join Room Message Structure Source: https://github.com/colyseus/schema/blob/master/SPEC.md Defines the binary structure of the message sent when a client joins a room. ```text Join Room Message { Header (uint8) = 10, ReconnectionTokenLength (uint8), ReconnectionToken (string), SerializerIdLength (uint8), SerializerId (string), Handshake Payload (...all bytes until the end of the message), } ``` -------------------------------- ### Filter State with StateView API Source: https://context7.com/colyseus/schema/llms.txt Use the StateView API with the `@view()` decorator to filter state per client. This allows server-side control over what each client can see. Import necessary classes from '@colyseus/schema'. ```typescript import { Schema, type, view, Encoder, StateView, MapSchema } from '@colyseus/schema'; class Card extends Schema { @type("string") suit: string; @type("uint8") value: number; @view() @type("boolean") faceUp: boolean = false; // Only visible when added to view } class Player extends Schema { @type("string") name: string; @view() @type([Card]) hand = new ArraySchema(); // Private hand @type("uint8") cardCount: number = 0; // Public info } class GameState extends Schema { @type({ map: Player }) players = new MapSchema(); @type([Card]) discardPile = new ArraySchema(); } // Server-side with views const state = new GameState(); const encoder = new Encoder(state); // Create views for each client const player1View = new StateView(); const player2View = new StateView(); // Add player1's hand to their view (they can see their own cards) const player1 = new Player(); player1.name = "Alice"; state.players.set("p1", player1); player1View.add(player1); const player2 = new Player(); player2.name = "Bob"; state.players.set("p2", player2); player2View.add(player2); // Deal cards const card = new Card(); card.suit = "hearts"; card.value = 10; player1.hand.push(card); player1.cardCount = player1.hand.length; // Encode for each client const it = { offset: 0 }; encoder.encodeAll(it); const sharedOffset = it.offset; // Player 1 sees their own hand const p1FullEncode = encoder.encodeAllView(player1View, sharedOffset, it); // Player 2 doesn't see player 1's hand details it.offset = sharedOffset; const p2FullEncode = encoder.encodeAllView(player2View, sharedOffset, it); // For delta patches with views const deltaIt = { offset: 0 }; encoder.encode(deltaIt); const deltaSharedOffset = deltaIt.offset; const p1Delta = encoder.encodeView(player1View, deltaSharedOffset, deltaIt); const p2Delta = encoder.encodeView(player2View, deltaSharedOffset, deltaIt); encoder.discardChanges(); ``` -------------------------------- ### Callbacks API Source: https://context7.com/colyseus/schema/llms.txt The Callbacks API allows developers to listen for property changes, collection modifications, and bind state properties to UI objects. ```APIDOC ## Callbacks API ### Description Provides methods to listen for property changes, collection additions/removals, and bind state to UI objects. ### Methods - **listen(property, callback)**: Listen to root or nested property changes. - **onAdd(collection, callback)**: Triggered when an item is added to a collection. - **onRemove(collection, callback)**: Triggered when an item is removed from a collection. - **onChange(collection, callback)**: Triggered when an item in a collection changes. - **bindTo(source, target, properties)**: Bind specific properties from a Schema instance to a target object. ### Request Example const $ = Callbacks.get(decoder); $.listen("phase", (current, prev) => { ... }); $.onAdd("players", (player, sessionId) => { ... }); ``` -------------------------------- ### Generate C# Schema from TypeScript Source: https://context7.com/colyseus/schema/llms.txt Use schema-codegen to generate C# schema files from TypeScript definitions. Specify output directory and target language. ```bash schema-codegen ./src/schemas/*.ts --output ./build --csharp --decorator sync ``` -------------------------------- ### Encode and Decode Schema via Reflection Source: https://github.com/colyseus/schema/blob/master/README.md Use Reflection to serialize and deserialize schema definitions dynamically. ```typescript import { Schema, type, Reflection } from "@colyseus/schema"; class MyState extends Schema { @type("string") currentTurn: string; // ... more definitions } // send `encodedStateSchema` across the network const encodedStateSchema = Reflection.encode(new MyState()); // instantiate `MyState` in the client-side, without having its definition: const myState = Reflection.decode(encodedStateSchema); ``` -------------------------------- ### Manual Change Tracking with setDirty() Source: https://context7.com/colyseus/schema/llms.txt Implement manual change tracking for schema properties using the @type decorator with { manual: true } and the setDirty() method. This is useful for batching updates or forcing re-encoding. ```typescript import { Schema, type, Encoder } from '@colyseus/schema'; class Transform extends Schema { // Manual tracking - changes won't auto-trigger encoding @type("float32", { manual: true }) x: number = 0; @type("float32", { manual: true }) y: number = 0; @type("float32", { manual: true }) rotation: number = 0; // Auto tracking (default) @type("boolean") visible: boolean = true; setPosition(x: number, y: number) { this.x = x; this.y = y; // Manually mark properties as dirty after batch update this.setDirty("x"); this.setDirty("y"); } rotate(angle: number) { this.rotation += angle; this.setDirty("rotation"); } } class Entity extends Schema { @type(Transform) transform = new Transform(); @type("int32") health: number = 100; // Force re-encoding without value change (e.g., for interpolation reset) forceSync() { this.setDirty("health"); this.transform.setDirty("x"); this.transform.setDirty("y"); } } const entity = new Entity(); const encoder = new Encoder(entity); // Batch position updates without triggering individual encodes entity.transform.setPosition(100.5, 200.3); entity.transform.rotate(45); // Now encode all marked changes at once const patch = encoder.encode(); encoder.discardChanges(); ``` -------------------------------- ### Decoder API Source: https://github.com/colyseus/schema/blob/master/README.md The Decoder class processes binary data received from the server to update the local state instance. ```APIDOC ## Decoder ### Description The Decoder class deserializes binary buffers back into the schema-defined state structure. ### Methods - **decode(encodedBytes)**: Decodes the provided binary buffer and applies updates to the associated state instance. ``` -------------------------------- ### Declare Array of Schema Structures Source: https://github.com/colyseus/schema/blob/master/README.md Wrap the class reference in an array to define a collection of schema instances. ```typescript @type([ Player ]) arrayOfPlayers: ArraySchema; ``` -------------------------------- ### Define Schema Functionally with schema() Source: https://context7.com/colyseus/schema/llms.txt Use the schema() function as a decorator-free alternative for defining schemas. Supports default values, method definitions, and inheritance via .extends(). Automatically initializes collection types and provides type inference. ```typescript import { Schema, schema, SchemaType, ArraySchema, MapSchema } from '@colyseus/schema'; // Define schema without decorators const Vector3 = schema({ x: "float32", y: "float32", z: "float32", }); type Vector3 = SchemaType; const Entity = schema({ id: "string", position: Vector3, velocity: Vector3, health: { type: "int32", default: 100 }, tags: ["string"], // Methods are supported takeDamage(amount: number) { this.health = Math.max(0, this.health - amount); }, // Initialize method for complex setup initialize(props: { id: string; x: number; y: number }) { this.id = props.id; this.position.x = props.x; this.position.y = props.y; } }); type Entity = SchemaType; // Inheritance with .extends() const Player = Entity.extends({ name: "string", score: "uint32", inventory: { map: "string" }, initialize(props: { id: string; name: string }) { this.id = props.id; this.name = props.name; } }, "Player"); type Player = SchemaType; // Usage const entity = new Entity({ id: "e1", x: 100, y: 200 }); entity.takeDamage(25); console.log(entity.health); // 75 const player = new Player({ id: "p1", name: "Alice" }); player.score = 1500; player.inventory.set("slot1", "magic_sword"); ``` -------------------------------- ### StateView API Source: https://context7.com/colyseus/schema/llms.txt StateView enables server-side filtering of data, allowing developers to control which properties or collections are visible to specific clients. ```APIDOC ## StateView API ### Description Enables server-side filtering of what each client can see. Use the @view() decorator to mark properties as filterable. ### Methods - **add(instance)**: Adds a Schema instance to the view, making its @view() properties visible. - **remove(instance)**: Removes a Schema instance from the view. - **encodeAllView(view, offset, it)**: Encodes the full state filtered by the provided view. - **encodeView(view, offset, it)**: Encodes delta patches filtered by the provided view. ### Request Example const player1View = new StateView(); player1View.add(player1); const p1Delta = encoder.encodeView(player1View, deltaSharedOffset, deltaIt); ``` -------------------------------- ### Decode Schema State and Patches Source: https://context7.com/colyseus/schema/llms.txt The Decoder reconstructs state from binary data and tracks references. It supports both full state initialization and incremental delta updates. ```typescript import { Schema, type, Decoder, MapSchema } from '@colyseus/schema'; class Player extends Schema { @type("string") name: string; @type("int32") score: number; } class GameState extends Schema { @type("string") phase: string; @type({ map: Player }) players = new MapSchema(); } // Client-side decoding const state = new GameState(); const decoder = new Decoder(state); // Receive full state from server (on connect) function onFullState(bytes: Uint8Array) { const changes = decoder.decode(bytes); console.log("Full state received, changes:", changes.length); console.log("Current phase:", state.phase); console.log("Players:", state.players.size); } // Receive delta patch from server function onPatch(bytes: Uint8Array) { const changes = decoder.decode(bytes); // changes array contains DataChange objects changes.forEach(change => { console.log({ ref: change.ref.constructor.name, field: change.field, operation: change.op, value: change.value, previousValue: change.previousValue }); }); } // Example WebSocket integration const ws = new WebSocket("ws://localhost:3000"); ws.binaryType = "arraybuffer"; ws.onmessage = (event) => { const bytes = new Uint8Array(event.data); const messageType = bytes[0]; const payload = bytes.slice(1); if (messageType === 1) { // Full state onFullState(payload); } else if (messageType === 2) { // Patch onPatch(payload); } }; ``` -------------------------------- ### Room State Message Structure Source: https://github.com/colyseus/schema/blob/master/SPEC.md Defines the binary structure of the message sent by the server containing the full room state. ```text Room State Message { Header (uint8) = 14, Encoded State (...all bytes until the end of the message), } ``` -------------------------------- ### Declare Map of Schema Structures Source: https://github.com/colyseus/schema/blob/master/README.md Use an object with a map key to define a map of schema instances. ```typescript @type({ map: Player }) mapOfPlayers: MapSchema; ``` -------------------------------- ### Define Schema Classes Source: https://github.com/colyseus/schema/blob/master/README.md Use the Schema class and @type decorators to define synchronized state structures. ```typescript import { Schema, type, ArraySchema, MapSchema } from '@colyseus/schema'; export class Player extends Schema { @type("string") name: string; @type("number") x: number; @type("number") y: number; } export class MyState extends Schema { @type('string') fieldString: string; @type('number') fieldNumber: number; @type(Player) player: Player; @type([ Player ]) arrayOfPlayers: ArraySchema; @type({ map: Player }) mapOfPlayers: MapSchema; } ``` -------------------------------- ### Define Game State Schema with Decorators Source: https://context7.com/colyseus/schema/llms.txt Use the @type() decorator to annotate properties for serialization. Supports primitives, nested schemas, ArraySchema, MapSchema, SetSchema, and CollectionSchema. Properties are automatically tracked for changes. ```typescript import { Schema, type, ArraySchema, MapSchema } from '@colyseus/schema'; // Define nested schema class Position extends Schema { @type("float32") x: number = 0; @type("float32") y: number = 0; @type("float32") z: number = 0; } class Player extends Schema { @type("string") name: string = ""; @type("uint8") level: number = 1; @type("int32") health: number = 100; @type("boolean") isAlive: boolean = true; @type(Position) position: Position = new Position(); @type(["string"]) inventory: ArraySchema = new ArraySchema(); } class GameState extends Schema { @type("string") roomName: string = "default"; @type("uint8") maxPlayers: number = 10; @type({ map: Player }) players: MapSchema = new MapSchema(); @type([Position]) waypoints: ArraySchema = new ArraySchema(); } // Usage const state = new GameState(); state.roomName = "Battle Arena"; const player = new Player(); player.name = "Hero"; player.position.x = 10.5; player.inventory.push("sword", "shield"); state.players.set("player1", player); ``` -------------------------------- ### Filter Properties with StateView Source: https://github.com/colyseus/schema/blob/master/README.md Use @view() to restrict property visibility and add instances to a StateView. ```typescript import { Schema, type, view } from "@colyseus/schema"; class Player extends Schema { @view() @type("string") secret: string; @type("string") notSecret: string; } class MyState extends Schema { @type({ map: Player }) players = new MapSchema(); } ``` ```typescript const view = new StateView(); view.add(player); ``` -------------------------------- ### Encoder API Source: https://github.com/colyseus/schema/blob/master/README.md The Encoder class handles the serialization of state objects into binary buffers for network transmission. ```APIDOC ## Encoder ### Description The Encoder class is used to serialize the state of a schema-defined object. It supports full state encoding, incremental changes, and view-based filtering. ### Methods - **encodeAll()**: Encodes the entire state of the object. - **encode()**: Encodes only the changes made to the state since the last sync. - **encodeAllView(view, offset, it)**: Encodes the full state filtered by a specific view. - **encodeView(view, offset, it)**: Encodes state changes filtered by a specific view. - **discardChanges()**: Clears the internal change tracking buffer. ``` -------------------------------- ### Encode Full State with Views Source: https://github.com/colyseus/schema/blob/master/README.md Encode the full state, accounting for multiple views. A shared full encode is used, and each view adds its own changes. ```typescript // shared buffer iterator const it = { offset: 0 }; // shared full encode encoder.encodeAll(it); const sharedOffset = it.offset; // view 1 const fullEncode1 = encoder.encodeAllView(view1, sharedOffset, it); // ... send "fullEncode1" to client1 and decode it // view 2 const fullEncode2 = encoder.encodeAllView(view2, sharedOffset, it); // ... send "fullEncode" to client2 and decode it ``` -------------------------------- ### Encode Full State Source: https://github.com/colyseus/schema/blob/master/README.md Encode the entire current state of your application. This is typically sent to new clients upon connection. ```typescript const fullEncode = encoder.encodeAll(); // ... send "fullEncode" to client and decode it ``` -------------------------------- ### TypeScript Schema Definition Source: https://context7.com/colyseus/schema/llms.txt Define game state using Colyseus Schema, including nested schemas like Vector3 and Player, and collections like ArraySchema and MapSchema. ```typescript import { Schema, type, ArraySchema, MapSchema } from '@colyseus/schema'; export class Vector3 extends Schema { @type("float32") x: number = 0; @type("float32") y: number = 0; @type("float32") z: number = 0; } export class Player extends Schema { @type("string") sessionId: string; @type("string") name: string; @type(Vector3) position = new Vector3(); @type("int32") health: number = 100; } export class GameState extends Schema { @type({ map: Player }) players = new MapSchema(); @type([Vector3]) spawnPoints = new ArraySchema(); } ``` -------------------------------- ### Declare Child Schema Structures Source: https://github.com/colyseus/schema/blob/master/README.md Use the class reference as the argument for the @type decorator. ```typescript @type(Player) player: Player; ``` -------------------------------- ### Declare Primitive Types Source: https://github.com/colyseus/schema/blob/master/README.md Annotate class properties with primitive type strings. ```typescript @type("string") name: string; @type("int32") name: number; ``` -------------------------------- ### Backwards/Forwards Compatibility with @deprecated Source: https://context7.com/colyseus/schema/llms.txt Use the @deprecated() decorator to mark fields as obsolete while maintaining wire compatibility. Deprecated fields are skipped during encoding but can still be decoded from older encoders. ```typescript import { Schema, type, deprecated, Encoder, Decoder } from '@colyseus/schema'; // Version 1 schema class PlayerV1 extends Schema { @type("string") name: string; @type("int32") score: number; } // Version 2 schema - evolved with backwards compatibility class PlayerV2 extends Schema { @type("string") name: string; @deprecated() @type("int32") score: number; // Old field, kept for compatibility @type("int32") totalScore: number = 0; // New field @type("int32") matchesWon: number = 0; // New field } // Old server encoding V1 const oldPlayer = new PlayerV1(); oldPlayer.name = "Alice"; oldPlayer.score = 100; const oldEncoder = new Encoder(oldPlayer); const v1Bytes = oldEncoder.encodeAll(); // New client can decode V1 data (forward compatibility) const newPlayer = new PlayerV2(); const newDecoder = new Decoder(newPlayer); newDecoder.decode(v1Bytes); console.log(newPlayer.name); // "Alice" // newPlayer.score throws error (deprecated) console.log(newPlayer.totalScore); // 0 (default, not in V1) console.log(newPlayer.matchesWon); // 0 (default, not in V1) // New server encoding V2 const serverPlayer = new PlayerV2(); serverPlayer.name = "Bob"; serverPlayer.totalScore = 500; serverPlayer.matchesWon = 10; const newEncoder = new Encoder(serverPlayer); const v2Bytes = newEncoder.encodeAll(); // Old client can decode V2 data (backward compatibility) const clientPlayer = new PlayerV1(); const clientDecoder = new Decoder(clientPlayer); clientDecoder.decode(v2Bytes); console.log(clientPlayer.name); // "Bob" console.log(clientPlayer.score); // 0 (field deprecated in V2, not encoded) ``` -------------------------------- ### Encode Changes with Views Source: https://github.com/colyseus/schema/blob/master/README.md Encode changes specific to each view, after a shared changes encode. Ensure to discard changes after encoding. ```typescript // shared buffer iterator const it = { offset: 0 }; // shared changes encode encoder.encode(it); const sharedOffset = it.offset; // view 1 const view1Encoded = this.encoder.encodeView(view1, sharedOffset, it); // ... send "view1Encoded" to client1 and decode it // view 2 const view2Encoded = this.encoder.encodeView(view2, sharedOffset, it); // ... send "view2Encoded" to client2 and decode it // discard all changes after encoding is done. encoder.discardChanges(); ``` -------------------------------- ### Encode State Changes Source: https://github.com/colyseus/schema/blob/master/README.md Encode only the changes that have occurred since the last encoding. This is more efficient for subsequent updates. ```typescript const changesBuffer = encoder.encode(); // ... send "changesBuffer" to client and decode it ``` -------------------------------- ### Declare Array of Primitive Types Source: https://github.com/colyseus/schema/blob/master/README.md Define arrays of primitive types. Note that mixed types are not supported. ```typescript @type([ "number" ]) arrayOfNumbers: ArraySchema; @type([ "string" ]) arrayOfStrings: ArraySchema; ``` -------------------------------- ### Declare Map of Primitive Types Source: https://github.com/colyseus/schema/blob/master/README.md Define maps of primitive types. Note that mixed types are not supported. ```typescript @type({ map: "number" }) mapOfNumbers: MapSchema; @type({ map: "string" }) mapOfStrings: MapSchema; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.