colyseus.js
Advanced tools
Comparing version 0.5.2 to 0.6.0-alpha.0
@@ -17,11 +17,12 @@ "use strict"; | ||
if (options === void 0) { options = {}; } | ||
_super.call(this, url, protocols, options); | ||
this.rooms = {}; | ||
var _this = _super.call(this, url, protocols, options) || this; | ||
_this.rooms = {}; | ||
// signals | ||
this.onOpen = new signals_js_1.Signal(); | ||
this.onMessage = new signals_js_1.Signal(); | ||
this.onClose = new signals_js_1.Signal(); | ||
this.onError = new signals_js_1.Signal(); | ||
this._enqueuedCalls = []; | ||
this.binaryType = "arraybuffer"; | ||
_this.onOpen = new signals_js_1.Signal(); | ||
_this.onMessage = new signals_js_1.Signal(); | ||
_this.onClose = new signals_js_1.Signal(); | ||
_this.onError = new signals_js_1.Signal(); | ||
_this._enqueuedCalls = []; | ||
_this.binaryType = "arraybuffer"; | ||
return _this; | ||
} | ||
@@ -28,0 +29,0 @@ Client.prototype.onOpenCallback = function (event) { |
// Use codes between 0~127 for lesser throughput (1 byte) | ||
"use strict"; | ||
var Protocol; | ||
(function (Protocol) { | ||
@@ -15,3 +16,2 @@ // User-related (0~10) | ||
Protocol[Protocol["BAD_REQUEST"] = 50] = "BAD_REQUEST"; | ||
})(exports.Protocol || (exports.Protocol = {})); | ||
var Protocol = exports.Protocol; | ||
})(Protocol = exports.Protocol || (exports.Protocol = {})); |
import { Signal } from "signals.js"; | ||
import Clock = require("clock.js"); | ||
import { DeltaContainer } from "delta-listener"; | ||
import { Client } from "./Client"; | ||
@@ -7,11 +8,6 @@ export declare class Room<T> { | ||
name: string; | ||
client: Client; | ||
state: T & any; | ||
private _previousState; | ||
lastPatchTime: number; | ||
ping: number; | ||
state: DeltaContainer<T & any>; | ||
clock: Clock; | ||
remoteClock: Clock; | ||
onJoin: Signal; | ||
onPatch: Signal; | ||
onUpdate: Signal; | ||
@@ -21,2 +17,6 @@ onData: Signal; | ||
onLeave: Signal; | ||
ping: number; | ||
private lastPatchTime; | ||
private client; | ||
private _previousState; | ||
constructor(client: Client, name: string); | ||
@@ -23,0 +23,0 @@ setState(state: T, remoteCurrentTime?: number, remoteElapsedTime?: number): void; |
"use strict"; | ||
var signals_js_1 = require("signals.js"); | ||
var Clock = require("clock.js"); | ||
var jsonpatch = require("fast-json-patch"); | ||
var delta_listener_1 = require("delta-listener"); | ||
var msgpack = require("msgpack-lite"); | ||
@@ -11,5 +11,7 @@ var fossilDelta = require("fossil-delta"); | ||
var _this = this; | ||
this.state = new delta_listener_1.DeltaContainer({}); | ||
this.clock = new Clock(); | ||
this.remoteClock = new Clock(); | ||
// Public signals | ||
this.onJoin = new signals_js_1.Signal(); | ||
this.onPatch = new signals_js_1.Signal(); | ||
this.onUpdate = new signals_js_1.Signal(); | ||
@@ -21,3 +23,2 @@ this.onData = new signals_js_1.Signal(); | ||
_this.onJoin.removeAll(); | ||
_this.onPatch.removeAll(); | ||
_this.onUpdate.removeAll(); | ||
@@ -27,2 +28,3 @@ _this.onData.removeAll(); | ||
_this.onLeave.removeAll(); | ||
_this.state.removeAllListeners(); | ||
}; | ||
@@ -32,12 +34,7 @@ this.id = null; | ||
this.name = name; | ||
this.state = {}; | ||
this.clock = new Clock(); | ||
this.remoteClock = new Clock(); | ||
this.lastPatchTime = null; | ||
this.ping = null; | ||
this.onLeave.add(this.removeAllListeners); | ||
} | ||
Room.prototype.setState = function (state, remoteCurrentTime, remoteElapsedTime) { | ||
this.state = state; | ||
this._previousState = msgpack.encode(this.state); | ||
this.state.set(state); | ||
this._previousState = msgpack.encode(state); | ||
// set remote clock properties | ||
@@ -61,11 +58,7 @@ if (remoteCurrentTime && remoteElapsedTime) { | ||
this.clock.tick(); | ||
// | ||
// apply patch | ||
// | ||
this._previousState = fossilDelta.apply(this._previousState, binaryPatch); | ||
var newState = msgpack.decode(this._previousState); | ||
var patches = jsonpatch.compare(this.state, newState); | ||
this.onPatch.dispatch(patches); | ||
this.state = newState; | ||
this.onUpdate.dispatch(this.state, patches); | ||
// trigger state callbacks | ||
this.state.set(msgpack.decode(this._previousState)); | ||
this.onUpdate.dispatch(this.state.data); | ||
}; | ||
@@ -72,0 +65,0 @@ Room.prototype.leave = function () { |
{ | ||
"name": "colyseus.js", | ||
"version": "0.5.2", | ||
"description": "JavaScript client for Colyseus Multiplayer Game Server", | ||
"version": "0.6.0-alpha.0", | ||
"description": "Multiplayer Game Client for the Browser", | ||
"keywords": [ | ||
@@ -30,3 +30,3 @@ "multiplayer", | ||
"clock.js": "^1.1.0", | ||
"fast-json-patch": "^1.0.0", | ||
"delta-listener": "^1.0.0-alpha.4", | ||
"fossil-delta": "^0.2.5", | ||
@@ -36,3 +36,3 @@ "msgpack-lite": "^0.1.20", | ||
"tiny-emitter": "^1.1.0", | ||
"websocket.js": "^0.1.4" | ||
"websocket.js": "^0.1.7" | ||
}, | ||
@@ -50,3 +50,3 @@ "devDependencies": { | ||
"ts-loader": "^0.9.5", | ||
"typescript": "^2.0.6", | ||
"typescript": "^2.1.4", | ||
"uglify-js": "^2.6.1", | ||
@@ -53,0 +53,0 @@ "watchify": "^3.6.1", |
@@ -1,3 +0,3 @@ | ||
colyseus.js for the browser | ||
=== | ||
#  | ||
> Colyseus.js - Multiplayer Game Client for the Browser. | ||
@@ -8,44 +8,88 @@ [](https://gitter.im/gamestdio/colyseus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
JavaScript/TypeScript client for | ||
[Colyseus](https://github.com/gamestdio/colyseus) - a Minimalist Multiplayer | ||
Game Server for Node.js. | ||
[Colyseus](https://github.com/gamestdio/colyseus) Multiplayer Game Server. | ||
**The version 0.6.0 is still in beta. Expect some changes before the final | ||
release.** | ||
## Usage | ||
```javascript | ||
### Connecting to server: | ||
```ts | ||
import * as Colyseus from "colyseus.js"; | ||
var client = new Colyseus.Client('ws://localhost:2657'); | ||
var roomName = "room_name" | ||
var room = client.join(roomName) | ||
``` | ||
// successfully joined the room | ||
### Joining to a room: | ||
```ts | ||
var room = client.join("room_name"); | ||
room.onJoin.add(function() { | ||
console.log(client.id, "joined", roomName) | ||
}) | ||
console.log(client.id, "joined", room.name); | ||
}); | ||
``` | ||
// patches comming from the server | ||
room.onUpdate.add(function(patches) { | ||
console.log(roomName, "patches comming:", patches) | ||
}) | ||
### Listening to room state change: | ||
// patches comming from the server | ||
room.onPatch.add(function(patches) { | ||
console.log(roomName, "will apply these changes:", patches) | ||
Here comes the most powerful feature of the client. You can listen to every state update in the server-side, and bind them into client-side functions. | ||
The first parameter is the path of the variable you want to listen to. When you provide placeholders (such as `:number`, `:id`, `:string`) to the path, they will populate the function with the value found on it. See examples below. | ||
Listening to entities being added in the room: | ||
```ts | ||
room.state.listen("entities/:id", "add", (entityId: string, value: any) => { | ||
console.log(`new entity ${entityId}`, value); | ||
}); | ||
``` | ||
Listening to entity attributes being replaced: | ||
```ts | ||
room.state.listen("entities/:id/:attribute", "replace", (entityId: string, attribute: string, value: any) => { | ||
console.log(`entity ${entityId} changed attribute ${attribute} to ${value}`); | ||
}); | ||
``` | ||
Listening to entities being removed: | ||
```ts | ||
room.state.listen("entities/:id", "remove", (entityId: string, value: any) => { | ||
console.log(`entity ${entityId} has been removed`); | ||
}); | ||
``` | ||
### Other room events | ||
Room state has been updated: | ||
```ts | ||
room.onUpdate.add(function(state) { | ||
console.log(room.name, "has new state:", state) | ||
}) | ||
``` | ||
// the server sent data directly for this client | ||
Data coming from server directly to this client: | ||
```ts | ||
room.onData.add(function(data) { | ||
console.log(client.id, "received on", roomName, data) | ||
}) | ||
console.log(client.id, "received on", room.name, data) | ||
}); | ||
``` | ||
// oops, some error happened in the server! | ||
Server error occurred: | ||
```ts | ||
room.onError.add(function() { | ||
console.log(client.id, "couldn't join", roomName) | ||
}) | ||
console.log(client.id, "couldn't join", room.name) | ||
}); | ||
``` | ||
// client left the room. | ||
The client left the room: | ||
```ts | ||
room.onLeave.add(function() { | ||
console.log(client.id, "left", roomName) | ||
}) | ||
console.log(client.id, "left", room.name) | ||
}); | ||
``` | ||
@@ -52,0 +96,0 @@ |
import { Signal } from "signals.js"; | ||
import Clock = require("clock.js"); | ||
import * as jsonpatch from "fast-json-patch"; | ||
import { DeltaContainer } from "delta-listener"; | ||
import * as msgpack from "msgpack-lite"; | ||
@@ -12,42 +12,34 @@ import * as fossilDelta from "fossil-delta"; | ||
export class Room<T> { | ||
id: number; | ||
name: string; | ||
public id: number; | ||
public name: string; | ||
client: Client; | ||
state: T & any; | ||
private _previousState: any; | ||
public state: DeltaContainer<T & any> = new DeltaContainer<T & any>({}); | ||
lastPatchTime: number; | ||
ping: number; | ||
public clock: Clock = new Clock(); | ||
public remoteClock: Clock = new Clock(); | ||
clock: Clock; | ||
remoteClock: Clock; | ||
// Public signals | ||
onJoin: Signal = new Signal(); | ||
onPatch: Signal = new Signal(); | ||
onUpdate: Signal = new Signal(); | ||
onData: Signal = new Signal(); | ||
onError: Signal = new Signal(); | ||
onLeave: Signal = new Signal(); | ||
public onJoin: Signal = new Signal(); | ||
public onUpdate: Signal = new Signal(); | ||
public onData: Signal = new Signal(); | ||
public onError: Signal = new Signal(); | ||
public onLeave: Signal = new Signal(); | ||
public ping: number; | ||
private lastPatchTime: number; | ||
private client: Client; | ||
private _previousState: any; | ||
constructor (client: Client, name: string) { | ||
this.id = null; | ||
this.client = client; | ||
this.name = name; | ||
this.state = {}; | ||
this.clock = new Clock(); | ||
this.remoteClock = new Clock(); | ||
this.lastPatchTime = null; | ||
this.ping = null; | ||
this.onLeave.add( this.removeAllListeners ); | ||
} | ||
setState ( state: T, remoteCurrentTime?: number, remoteElapsedTime?: number ) { | ||
this.state = state | ||
this._previousState = msgpack.encode( this.state ) | ||
setState ( state: T, remoteCurrentTime?: number, remoteElapsedTime?: number ): void { | ||
this.state.set(state); | ||
this._previousState = msgpack.encode( state ) | ||
@@ -79,16 +71,12 @@ // set remote clock properties | ||
// | ||
// apply patch | ||
// | ||
this._previousState = fossilDelta.apply( this._previousState, binaryPatch ); | ||
let newState = msgpack.decode( this._previousState ); | ||
let patches = jsonpatch.compare( this.state, newState ); | ||
this.onPatch.dispatch(patches); | ||
// trigger state callbacks | ||
this.state.set( msgpack.decode( this._previousState ) ); | ||
this.state = newState; | ||
this.onUpdate.dispatch(this.state, patches); | ||
this.onUpdate.dispatch(this.state.data); | ||
} | ||
leave () { | ||
public leave (): void { | ||
if (this.id >= 0) { | ||
@@ -99,9 +87,8 @@ this.client.send([ Protocol.LEAVE_ROOM, this.id ]); | ||
send (data) { | ||
public send (data): void { | ||
this.client.send([ Protocol.ROOM_DATA, this.id, data ]); | ||
} | ||
removeAllListeners = () => { | ||
public removeAllListeners = (): void => { | ||
this.onJoin.removeAll(); | ||
this.onPatch.removeAll(); | ||
this.onUpdate.removeAll(); | ||
@@ -111,4 +98,5 @@ this.onData.removeAll(); | ||
this.onLeave.removeAll(); | ||
this.state.removeAllListeners(); | ||
} | ||
} |
@@ -1,9 +0,9 @@ | ||
var assert = require('chai').assert; | ||
var Room = require('../lib/Room').Room; | ||
const assert = require('chai').assert; | ||
const Room = require('../lib/Room').Room; | ||
var fossilDelta = require('fossil-delta'); | ||
var msgpack = require('msgpack-lite'); | ||
const fossilDelta = require('fossil-delta'); | ||
const msgpack = require('msgpack-lite'); | ||
describe("Room", function() { | ||
var room = null; | ||
let room = null; | ||
@@ -16,3 +16,3 @@ beforeEach(function() { | ||
assert.equal(room.name, "chat") | ||
assert.deepEqual(room.state, {}) | ||
assert.deepEqual(room.state.data, {}) | ||
}); | ||
@@ -30,3 +30,3 @@ | ||
it("should patch room state", function(done) { | ||
var state = { | ||
let state = { | ||
players: { | ||
@@ -40,5 +40,5 @@ 'one': { hp: 100, lvl: 1, position: {x: 0, y: 0} }, | ||
// get previous state encoded | ||
var previousState = msgpack.encode(state); | ||
let previousState = msgpack.encode(state); | ||
// change state and encode it | ||
var nextState = msgpack.encode({ | ||
let nextState = msgpack.encode({ | ||
players: { | ||
@@ -49,12 +49,26 @@ 'one': { hp: 40, lvl: 1, position: {x: 0, y: 100} }, | ||
}); | ||
var delta = fossilDelta.create(previousState, nextState); | ||
let delta = fossilDelta.create(previousState, nextState); | ||
room.onPatch.add(function(patches) { | ||
assert.equal(patches.length, 2) | ||
done(); | ||
let patchCount = 0; | ||
room.state.listen("players/:id/:attribute", "replace", (id, attribute, value) => { | ||
patchCount++ | ||
assert.equal(id, "one"); | ||
assert.equal(attribute, "hp"); | ||
assert.equal(value, 40); | ||
}) | ||
room.state.listen("players/:id/position/:axis", "replace", (id, axis, value) => { | ||
patchCount++ | ||
assert.equal(id, "one"); | ||
assert.equal(axis, "y"); | ||
assert.equal(value, 100); | ||
}) | ||
room.patch(delta); | ||
setTimeout(() => { | ||
if (patchCount === 2) done(); | ||
}, 1); | ||
}); | ||
}); |
1438460
48
1377
99
+ Addeddelta-listener@1.1.1(transitive)
- Removedfast-json-patch@^1.0.0
- Removedfast-json-patch@1.2.2(transitive)
Updatedwebsocket.js@^0.1.7