Skip to content

Migrating to version 0.14 (from 0.13)

As a result from colyseus/schema#75 - the Colyseus version 0.14 introduces a few breaking changes on the usage of MapSchema, and schema callbacks on the client-side, as both the Schema encoder and decoder have been reworked.

New feature @filterChildren(), and better @filter() support! Read more about how filters work here.

Upgrading the server:

npm install colyseus@^0.14.0 --save

Upgrading the client:

npm install colyseus.js@^0.14.0 --save

If you're using Unity or other client, please check on its respective repository on GitHub. If you have questions feel free to ask on Discord

Use .assign({}) instead of constructor()

If you're sharing your concrete schema implementation with the client-side and have the constructor() implemented, some error may happen because the decoder is not going to provide any arguments during initialization of that structure.

With the addition of the .assign({}) method, it is recommended to use it instead of providing arguments to constructor() for setting initial data in your structures:

const player = new Player().assign({ x: 10, y: 10 });

MapSchema breaking changes

MapSchema used to be treated as a plain JavaScript object ({}). Now, it uses the built-in Map internally.

By using the built-in Map, issues regarding the order of map keys are gone (#51 and #70).

There are a few breaking changes, which you should fix in your project, though.

Iterating through all items

Previous version:

for (const key in yourMap) {
    key // map key
    yourMap[key] // map value
}

New version:

yourMap.forEach((value, key) => {
    key // map key
    value // map value
});

Alternatively, you may iterate through the map's keys, or values alone, by using the iterators map.keys() or map.values().

Getting the total number of items

Previous version:

const size = Object.keys(this.state.players).length;
console.log("Number of items =>", size);

New version:

const size = this.state.players.size;
console.log("Number of items =>", size);

Getting the keys of a MapSchema

Previous version:

Object.keys(map)

New version:

Array.from(map.keys())

Getting and setting on MapSchema

This is not a breaking change! You can still use the bracket accessors to get and set values on MapSchema. It is recommended to use the new Map-like methods instead, though.

Previous version:

// get with bracket accessor
// (the type of "entry" here is "any")
const entry = yourMap["key"];

// set with bracket accessor
yourMap["key"] = "value";

New version:

// get with .get() method
// (the type of "entry" matches the type definition)
const entry = yourMap.get("key");

// set with .set() method
yourMap.set("key", "value");

Client-side: Schema callbacks

TLDR: Double-check all your onChange callbacks in the client-side. You may need to add more onChange callbacks for children structures.

onChange on Schema references

Previous version: Whenever a change happens on deeper children, the field of the parent container is triggered as a change.

// Server-side
state.player.position.x = 10;

// Client-side
state.player.onChange = function(changes) {
    changes[0].field // "position" is here!
}

New version: Now, changes are not propagated to parent Schema instances anymore. If you need to listen for a change on player.position (and .position is of type of Schema), you need to attach a onChange callback to the .position instance as well.

// Server-side
state.player.position.x = 10;

// Client-side
state.player.position.onChange = function(changes) {
    changes[0].field // "x" is here!
}

onChange on collections (ArraySchema, MapSchema, etc.)

Similarly as on the previous example, onChange is not triggered anymore if the children of the collection is an Schema instance. onChange is only triggered for primitive values.

Previous version:

state.arrayOfSchemas.onChange = function(value, key) {
    console.log(value, "has changed at", key);
}

state.arrayOfPrimitives.onChange = function(value, key) {
    console.log(value, "has changed at", key);
}

New version:

state.arrayOfSchemas.onAdd = function(value, key) {
    value.onChange = function(changes) {
        console.log("List of changes", changes);
    }
}
state.arrayOfSchemas.onChange = function(value, key) {
    // you can remove this callback, as it is never going to be called.
}

state.arrayOfPrimitives.onChange = function(value, key) {
    // here remains the same for primitive values (string, number, boolean)
    console.log(value, "has changed at", key);
}