colyseus-events
Advanced tools
Comparing version 1.1.0 to 2.0.0
import { ArraySchema, CollectionSchema, MapSchema, Schema, SetSchema } from '@colyseus/schema'; | ||
export declare type Primitive = number | string | boolean; | ||
export declare type Primitive = number | string | boolean | null | undefined; | ||
export declare type Container = Schema | ArraySchema | MapSchema | CollectionSchema | SetSchema; | ||
export declare type Colyseus = Primitive | Container; | ||
export interface Events<E = string> { | ||
emit(event: E, ...values: unknown[]): unknown; | ||
on(event: E, fn: (...values: unknown[]) => unknown): unknown; | ||
emit(eventName: E, value: Event): unknown; | ||
} | ||
export declare type Add = { | ||
op: 'add'; | ||
path: string; | ||
value: Colyseus; | ||
}; | ||
export declare type Replace = { | ||
op: 'replace'; | ||
path: string; | ||
value: Colyseus; | ||
}; | ||
export declare type Remove = { | ||
op: 'remove'; | ||
path: string; | ||
}; | ||
export declare type Event = Add | Remove | Replace; | ||
export declare function add(path: string, value: Colyseus): Add; | ||
export declare function replace(path: string, value: Colyseus): Replace; | ||
export declare function remove(path: string): Remove; | ||
/** | ||
* make every change in Colyseus state trigger an event in the EventEmitter using the provided namespace. | ||
* @param state Colyseus state to track | ||
* @param events EventsEmitter of you choice. has to support `emit()` and `on()` | ||
* @param namespace Prefix of events name to emit | ||
* @returns the provided events emitter | ||
* @param events EventsEmitter of you choice. has to at least have the method `emit(eventName, value)`. | ||
* @param namespace (optional) Prefix of json pointer | ||
* @returns the provided events emitter (2nd argument) | ||
*/ | ||
export declare function wireEvents<T extends Events>(state: Colyseus, events: T, namespace?: string): T; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.wireEvents = void 0; | ||
exports.wireEvents = exports.remove = exports.replace = exports.add = void 0; | ||
const schema_1 = require("@colyseus/schema"); | ||
@@ -10,8 +10,20 @@ const schemaKeys = Object.keys(new (class extends schema_1.Schema { | ||
} | ||
function add(path, value) { | ||
return { op: 'add', path, value }; | ||
} | ||
exports.add = add; | ||
function replace(path, value) { | ||
return { op: 'replace', path, value }; | ||
} | ||
exports.replace = replace; | ||
function remove(path) { | ||
return { op: 'remove', path }; | ||
} | ||
exports.remove = remove; | ||
/** | ||
* make every change in Colyseus state trigger an event in the EventEmitter using the provided namespace. | ||
* @param state Colyseus state to track | ||
* @param events EventsEmitter of you choice. has to support `emit()` and `on()` | ||
* @param namespace Prefix of events name to emit | ||
* @returns the provided events emitter | ||
* @param events EventsEmitter of you choice. has to at least have the method `emit(eventName, value)`. | ||
* @param namespace (optional) Prefix of json pointer | ||
* @returns the provided events emitter (2nd argument) | ||
*/ | ||
@@ -25,6 +37,5 @@ function wireEvents(state, events, namespace = '') { | ||
for (const { field, value } of changes) { | ||
const fieldNamespace = namespace ? `${namespace}.${field}` : field; | ||
events.emit(fieldNamespace, value, fieldNamespace); | ||
//@ts-ignore : the field is legal for the state | ||
wireEvents(state[field], events, fieldNamespace); | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(fieldNamespace, replace(fieldNamespace, value)); | ||
wireEvents(value, events, fieldNamespace); | ||
} | ||
@@ -34,5 +45,5 @@ }; | ||
if (!schemaKeys.includes(field) && Object.prototype.hasOwnProperty.call(state, field)) { | ||
const fieldNamespace = namespace ? `${namespace}.${field}` : field; | ||
//@ts-ignore : the field is legal for the state | ||
wireEvents(state[field], events, fieldNamespace); | ||
const fieldNamespace = `${namespace}/${field}`; | ||
const value = state[field]; | ||
wireEvents(value, events, fieldNamespace); | ||
} | ||
@@ -42,13 +53,18 @@ } | ||
else if (state instanceof schema_1.ArraySchema) { | ||
state.onAdd = state.onChange = (value, field) => { | ||
const fieldNamespace = `${namespace}[${field}]`; | ||
events.emit(fieldNamespace, value, fieldNamespace); | ||
state.onAdd = (value, field) => { | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(namespace, add(fieldNamespace, value)); | ||
wireEvents(value, events, fieldNamespace); | ||
}; | ||
state.onChange = (value, field) => { | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(fieldNamespace, replace(fieldNamespace, value)); | ||
wireEvents(value, events, fieldNamespace); | ||
}; | ||
state.onRemove = (_, field) => { | ||
const fieldNamespace = `${namespace}[${field}]`; | ||
events.emit(fieldNamespace, undefined, fieldNamespace); | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(namespace, remove(fieldNamespace)); | ||
}; | ||
for (const [field, value] of state.entries()) { | ||
const fieldNamespace = `${namespace}[${field}]`; | ||
const fieldNamespace = `${namespace}/${field}`; | ||
wireEvents(value, events, fieldNamespace); | ||
@@ -58,13 +74,18 @@ } | ||
else if (state instanceof schema_1.MapSchema) { | ||
state.onAdd = state.onChange = (value, field) => { | ||
const fieldNamespace = `${namespace}["${field}"]`; | ||
events.emit(fieldNamespace, value, fieldNamespace); | ||
state.onAdd = (value, field) => { | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(namespace, add(fieldNamespace, value)); | ||
wireEvents(value, events, fieldNamespace); | ||
}; | ||
state.onChange = (value, field) => { | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(fieldNamespace, replace(fieldNamespace, value)); | ||
wireEvents(value, events, fieldNamespace); | ||
}; | ||
state.onRemove = (_, field) => { | ||
const fieldNamespace = `${namespace}["${field}"]`; | ||
events.emit(fieldNamespace, undefined, fieldNamespace); | ||
const fieldNamespace = `${namespace}/${field}`; | ||
events.emit(namespace, remove(fieldNamespace)); | ||
}; | ||
for (const [field, value] of state.entries()) { | ||
const fieldNamespace = `${namespace}["${field}"]`; | ||
const fieldNamespace = `${namespace}/${field}`; | ||
wireEvents(value, events, fieldNamespace); | ||
@@ -71,0 +92,0 @@ } |
{ | ||
"name": "colyseus-events", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "generate notification events from colyseus state", | ||
@@ -5,0 +5,0 @@ "repository": "git@github.com:starwards/colyseus-events.git", |
# colyseus-events | ||
generate notification events from colyseus state. forked from https://github.com/amir-arad/colyseus-mobx | ||
Generate json-patch events from colyseus state. | ||
```typescript | ||
import { wireEvents } from 'colyseus-events'; | ||
const room: Room<GameState> = await client.joinOrCreate("game"); | ||
const events = wireEvents(room.state, new EventEmitter()); | ||
// `events` will emit json-patch events whenever the room state changes | ||
``` | ||
@@ -11,3 +17,3 @@ ## version support | ||
The schema types new to Colyseus 0.14 (`CollectionSchema` and `SetSchema`) are not yet supported. please open an issue if you would like to use them. | ||
The schema types new to Colyseus 0.14 (`CollectionSchema` and `SetSchema`) are not yet supported. please open an issue if you would like to see them supported. | ||
@@ -23,12 +29,41 @@ ## Installation | ||
const events = wireEvents(room.state, new EventEmitter()); | ||
// `events` will emit json-patch events whenever the room state changes | ||
``` | ||
then you can wire listeners to `events` and start triggering them. | ||
then you can wire listeners to `events` using their [JSON-pointer](https://github.com/janl/node-jsonpointer) as event name. | ||
whenever something changes in the state, an event will be emitted immediately. the name of the event will be the path of the changed property (or element). The event value will be the new value of that property or element. for convenience, the second value will be the event name. this can be helpful for listeners thatregister for more that one property. | ||
## Examples | ||
examples: | ||
when the server executes: `room.state.foo.bar = 15` event `'foo.bar'` will be emitted with values `15` and `'foo.bar'`. | ||
when the server executes: `room.state.foo.bar.push(15)` event `'foo.bar[0]'` will be emitted with values `15` and `'foo.bar[0]'`. | ||
For example, given the room state: | ||
```typescript | ||
export class Inner extends Schema { | ||
@type('uint8') public baz = 0; | ||
} | ||
export class GameState extends Schema { | ||
@type('uint8') public foo = 0; | ||
@type(Inner) public bar = new Inner(); | ||
@type(['uint8']) public numbersArray = new ArraySchema<number>(); | ||
@type({ map: 'uint8' }) public mapNumbers = new MapSchema<number>(); | ||
} | ||
``` | ||
### changing values | ||
when changing a value in Schema or collection (ArraySchema or MapSchema), an event will be emitted. The name of the event will be the [JSON-pointer](https://github.com/janl/node-jsonpointer) describing the location of the property. The event value will be a ["replace" JSON Patch](https://jsonpatch.com/#replace) corresponding with the change. | ||
For example: | ||
- when the server executes: `room.state.foo = 1` an event named `'/foo'` will be emitted with value `{ op: 'replace', path: '/foo', value: 1 }` | ||
- when the server executes: `room.numbersArray[0] = 1` (assuming numbersArray had a previous value at index 0) an event named `'/numbersArray/1'` will be emitted with value `{ op: 'replace', path: '/numbersArray/1', value: 1 }` | ||
- when the server executes: `room.mapNumbers.set('F00', 1)` (assuming mapNumbers had a previous value at key `F00`) an event named `'/mapNumbers/F00'` will be emitted with value `{ op: 'replace', path: '/mapNumbers/F00', value: 1 }` | ||
- when the server executes: `room.state.bar.baz = 1` an event named `'/bar/baz'` will be emitted with value `{ op: 'replace', path: '/bar/baz', value: 1 }` | ||
- when the server executes: `room.state.bar = new Inner()` an event named `'/bar'` will be emitted with value `{ op: 'replace', path: '/bar', value: {{the actual object in state.bar }} }` | ||
...and so on. | ||
### adding and removing elements in collections | ||
when adding or removing elements in a collection (ArraySchema or MapSchema), an event will be also be emitted. The name of the event will be the [JSON-pointer](https://github.com/janl/node-jsonpointer) describing the location of the **container**. The event value will be a ["add"](https://jsonpatch.com/#add) or ["remove"](https://jsonpatch.com/#remove) JSON Patch corresponding with the change. the `path` in the event value will point to the location of the **element** that was added or removed. | ||
For example: | ||
- when the server executes: `room.numbersArray.push(1)` an event named `'/numbersArray'` will be triggered with value `{ op: 'add', path: '/numbersArray/0', value: 1 }` | ||
- when the server executes: `room.numbersArray.pop()` an event named `'/numbersArray'` will be triggered with value `{ op: 'remove', path: '/numbersArray/0' }` | ||
- when the server executes: `room.mapNumbers.set('F00', 1)` an event named `'/mapNumbers'` will be triggered with value `{ op: 'add', path: '/mapNumbers/F00', value: 1 }` | ||
- when the server executes: `room.mapNumbers.delete('F00')` an event named `'/mapNumbers'` will be triggered with value `{ op: 'remove', path: '/mapNumbers/F00' }` | ||
...and so on. | ||
You are welcomed to explore the tests in the github repo for more examples. | ||
## Contributor instructions | ||
@@ -35,0 +70,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17951
125
100