![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@colyseus/schema
Advanced tools
An incremental binary state serializer with delta encoding for games.
Made for Colyseus, yet can be used standalone.
@colyseus/schema
uses type annotations to define types of synchronized properties.
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<Player>;
@type({ map: Player }) mapOfPlayers: MapSchema<Player>;
}
Type | Description | Limitation |
---|---|---|
string | utf8 strings | maximum byte size of 4294967295 |
number | auto-detects int or float type. (extra byte on output) | 0 to 18446744073709551615 |
boolean | true or false | 0 or 1 |
int8 | signed 8-bit integer | -128 to 127 |
uint8 | unsigned 8-bit integer | 0 to 255 |
int16 | signed 16-bit integer | -32768 to 32767 |
uint16 | unsigned 16-bit integer | 0 to 65535 |
int32 | signed 32-bit integer | -2147483648 to 2147483647 |
uint32 | unsigned 32-bit integer | 0 to 4294967295 |
int64 | signed 64-bit integer | -9223372036854775808 to 9223372036854775807 |
uint64 | unsigned 64-bit integer | 0 to 18446744073709551615 |
float32 | single-precision floating-point number | -3.40282347e+38 to 3.40282347e+38 |
float64 | double-precision floating-point number | -1.7976931348623157e+308 to 1.7976931348623157e+308 |
string
, number
, boolean
, etc)@type("string")
name: string;
@type("int32")
name: number;
Schema
structures@type(Player)
player: Player;
Schema
structure@type([ Player ])
arrayOfPlayers: ArraySchema<Player>;
You can't mix types inside arrays.
@type([ "number" ])
arrayOfNumbers: ArraySchema<number>;
@type([ "string" ])
arrayOfStrings: ArraySchema<string>;
Schema
structure@type({ map: Player })
mapOfPlayers: MapSchema<Player>;
You can't mix primitive types inside maps.
@type({ map: "number" })
mapOfNumbers: MapSchema<number>;
@type({ map: "string" })
mapOfStrings: MapSchema<string>;
The Schema definitions can encode itself through Reflection
. You can have the
definition implementation in the server-side, and just send the encoded
reflection to the client-side, for example:
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);
StateView
/ @view()
You can use @view()
to filter properties that should be sent only to StateView
's that have access to it.
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<Player>();
}
Using the StateView
const view = new StateView();
view.add(player);
There are 3 major features of the Encoder
class:
@view()
tag)import { Encoder } from "@colyseus/schema";
const state = new MyState();
const encoder = new Encoder(state);
New clients must receive the full state on their first connection:
const fullEncode = encoder.encodeAll();
// ... send "fullEncode" to client and decode it
Further state changes must be sent in order:
const changesBuffer = encoder.encode();
// ... send "changesBuffer" to client and decode it
When using @view()
and StateView
's, a single "full encode" must be used for multiple views. Each view also must add its own changes.
// 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
Encoding changes per views:
// 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();
The Decoder
class is used to decode the binary data received from the server.
import { Decoder } from "@colyseus/schema";
const state = new MyState();
const decoder = new Decoder(state);
decoder.decode(encodedBytes);
Backwards/fowards compatibility is possible by declaring new fields at the
end of existing structures, and earlier declarations to not be removed, but
be marked @deprecated()
when needed.
This is particularly useful for native-compiled targets, such as C#, C++, Haxe, etc - where the client-side can potentially not have the most up-to-date version of the schema definitions.
Schema
structure can hold up to 64
fields. If you need more fields, use nested structures.NaN
or null
numbers are encoded as 0
null
strings are encoded as ""
Infinity
numbers are encoded as Number.MAX_SAFE_INTEGER
@colyseus/schema
encodes only field values in the specified order.
If you're using JavaScript or LUA, there's no need to bother about this. Interpreted programming languages are able to re-build the Schema locally through the use of
Reflection
.
You can generate the client-side schema files based on the TypeScript schema definitions automatically.
# C#/Unity
schema-codegen ./schemas/State.ts --output ./unity-project/ --csharp
# C/C++
schema-codegen ./schemas/State.ts --output ./cpp-project/ --cpp
# Haxe
schema-codegen ./schemas/State.ts --output ./haxe-project/ --haxe
Scenario | @colyseus/schema | msgpack + fossil-delta |
---|---|---|
Initial state size (100 entities) | 2671 | 3283 |
Updating x/y of 1 entity after initial state | 9 | 26 |
Updating x/y of 50 entities after initial state | 342 | 684 |
Updating x/y of 100 entities after initial state | 668 | 1529 |
Each Colyseus SDK has its own decoder implementation of the @colyseus/schema
protocol:
Initial thoghts/assumptions, for Colyseus:
Practical Colyseus issues this should solve:
MIT
FAQs
Binary state serializer with delta encoding for games
The npm package @colyseus/schema receives a total of 3,001 weekly downloads. As such, @colyseus/schema popularity was classified as popular.
We found that @colyseus/schema demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.