Migrating to version 0.15 (from 0.14)¶
See version 0.15 release announcement.
@colyseus/arena
has been renamed to@colyseus/tools
- Schema's
.triggerAll()
has been deprecated. - Schema callbacks API change
- Schema's
onChange
behaviour change MapSchema
is now strict on property accessorsclient.reconnect()
API slightly changedallowReconnection()
: second argument is now mandatory@colyseus/loadtest
has been reworked!@colyseus/command
typings update- Built-in
client.auth
is gone!@colyseus/social
fully deprecated
@colyseus/arena
has been renamed to @colyseus/tools
¶
You can remove @colyseus/arena
and install @colyseus/tools
:
You can also rename the arena.config.ts
file to app.config.ts
for consistency.
Schema's .triggerAll()
has been deprecated¶
Now, whenever you register an onAdd()
callback, it is called immediately for already existing items - thus, making the usage of .triggerAll()
not necessary anymore.
You can prevent the onAdd()
callback from being triggered automatically, though, if necessary.
By providing false
in the second argument, the onAdd()
callback is not going to be triggered for already existing items.
Schema callbacks API slightly changed¶
Now, instead of assigning a single callback per onAdd
/onChange
/onRemove
, you attach them by calling as a method instead. You can attach more than one callback this way.
See example below:
// 0.14 (old)
state.players.onAdd = function(value, key) {/* do stuff */};
state.players.onChange = function(value, key) {/* do stuff */};
state.players.onRemove = function(value, key) {/* do stuff */};
// 0.15 (new)
state.players.onAdd(function(value, key) {/* do stuff */});
state.players.onChange(function(value, key) {/* do stuff */});
state.players.onRemove(function(value, key) {/* do stuff */});
// 0.14 (old)
state.players.OnAdd += (key, value) => {/* do stuff */};
state.players.OnChange += (key, value) => {/* do stuff */};
state.players.OnRemove += (key, value) => {/* do stuff */};
// 0.15 (new)
state.players.OnAdd((key, value) => {/* do stuff */})
state.players.OnChange((key, value) => {/* do stuff */})
state.players.OnRemove((key, value) => {/* do stuff */})
-- 0.14 (old)
state.players.on_add = function(value, key) --[[ do stuff ]] end
state.players.on_change = function(value, key) --[[ do stuff ]] end
state.players.on_remove = function(value, key) --[[ do stuff ]] end
-- 0.15 (new)
-- ATTENTION: this is a method call. make sure to use `:` instead of `.` here.
state.players:on_add(function(value, key) --[[ do stuff ]] end)
state.players:on_change(function(value, key) --[[ do stuff ]] end)
state.players:on_remove(function(value, key) --[[ do stuff ]] end)
// 0.14 (old)
state.players.onAdd = function(value, key) {/* do stuff */};
state.players.onChange = function(value, key) {/* do stuff */};
state.players.onRemove = function(value, key) {/* do stuff */};
// 0.15 (new)
state.players.onAdd(function(value, key) {/* do stuff */});
state.players.onChange(function(value, key) {/* do stuff */});
state.players.onRemove(function(value, key) {/* do stuff */});
The return value of onAdd()
/onChange()
/onRemove()
is a function that can detach the callback that have been added.
Schema's onChange
behaviour change¶
Previously, the onChange
callback wouldn't be fired during onAdd
and onRemove
when attached to a collection of items (MapSchema
, ArraySchema
, etc).
Now, onChange
is triggered alongside with onAdd
and onRemove
.
MapSchema
is now strict on property accessors¶
Only JavaScript/TypeScript is affected. If you use a client-side SDK other than JavaScript/TypeScript, no change is needed on the client-side for you.
// 0.14 (old)
this.state.players[client.sessionId] = new Player();
// 0.15 (new)
this.state.players.set(client.sessionId, new Player());
Reasoning:
MapSchema
used to be treated as a regular JavaScript object in the early days. Since version 0.14MapSchema
uses a realMap
internally, with a "proxy" compatibility layer in order to avoid breaking existing projects. Now the "proxy" layer has been removed, improving the performance slightly.
client.reconnect()
API slightly changed¶
The previous reconnection implementation had a security vulnerability, although very unlikely to be explored, we had to update its implementation to make it secure.
// 0.14 (old)
client.reconnect(cachedRoomId, cachedSessionId)
// 0.15 (new)
client.reconnect(cachedReconnectionToken)
Insterad of providing the previously active room.roomId
and room.sessionId
for reconnection, you only provide the room.reconnectionToken
instead.
Reconnection tokens are unique and private for each client.
allowReconnection()
: second argument is now mandatory¶
Previously, by omitting the second argument of allowReconnection()
, you were in control over when to cancel the possibility for reconnection.
To make this intent more explicit, it is now mandatory to provide the second argument either as "manual"
, or the number of seconds to wait for reconnection:
async onLeave (client: Client, consented: boolean) {
// ...
try {
if (consented) { throw new Error("consented leave"); }
//
// Get reconnection token
// NOTE: do not use `await` here yet!
//
const reconnection = this.allowReconnection(client, "manual");
//
// here is the custom logic for rejecting the reconnection.
// for demonstration purposes of the API, an interval is created
// rejecting the reconnection if the player has missed 2 rounds,
// (assuming he's playing a turn-based game)
//
// in a real scenario, you would store the `reconnection` in
// your Player instance, for example, and perform this check during your
// game loop logic
//
const currentRound = this.state.currentRound;
const interval = setInterval(() => {
if ((this.state.currentRound - currentRound) > 2) {
// manually reject the client reconnection
reconnection.reject();
clearInterval(interval);
}
}, 1000);
// now it's time to `await` for the reconnection
await reconnection;
// client returned! let's re-activate it.
// ...
} catch (e) {
// reconnection has been rejected. let's remove the client.
// ...
}
}
@colyseus/loadtest
has been reworked!¶
The loadtest tool has been reworked to allow for more complex scripting, so your loadtest scripts will need to be slightly rewritten, as the new format looks like this:
import { Client, Room } from "colyseus.js";
import { cli, Options } from "@colyseus/loadtest";
async function main(options: Options) {
const client = new Client(options.endpoint);
const room: Room = await client.joinOrCreate(options.roomName, {/*
your join options here...
*/});
console.log("joined successfully!");
room.onMessage("message-type", (payload) => {
// logic
});
room.onStateChange((state) => {
console.log("state change:", state);
});
room.onLeave((code) => {
console.log("left");
});
}
// execute
cli(main);
@colyseus/command
typings update¶
On latest version of @colyseus/command
(0.2.0
), instead of providing the state as a generic when extending the Command
, you now provide your whole Room
type:
import { Command } from "@colyseus/command";
export class MyRoom extends Room<State> {/* ... */}
-export class MyCommand extends Command<State> {/* ... */}
+export class MyCommand extends Command<MyRoom> {/* ... */}
Built-in client.auth
is gone! @colyseus/social
fully deprecated.¶
The documentation has been discouraging the use of @colyseus/social
since version 0.14.
Now @colyseus/social
has been officially deprecated. If you really rely on it please reach out to the devs on Discord on how to proceed if you still need to use it.