@rbxts/charm
Advanced tools
Comparing version 0.4.0 to 0.5.0
{ | ||
"name": "@rbxts/charm", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Atomic state management for Roblox", | ||
@@ -25,3 +25,2 @@ "main": "src/init.lua", | ||
"src", | ||
"default.project.json", | ||
"!src/__tests__" | ||
@@ -28,0 +27,0 @@ ], |
@@ -337,5 +337,5 @@ <p align="center"> | ||
### `sync.client(options)` | ||
### `sync.server(options)` | ||
Call `sync.client` to create a client sync object. The object will sync the client's copy of the state with the server's state. | ||
Call `sync.server` to create a server sync object. The object handles sending state updates to clients at a specified interval, and hydrating clients with the initial state. | ||
@@ -345,9 +345,15 @@ ```ts | ||
const client = sync.client({ atoms: atomsToSync }); | ||
const server = sync.server({ | ||
atoms: atomsToSync, | ||
interval: 0, | ||
preserveHistory: false, | ||
}); | ||
remotes.syncState.connect((payload) => { | ||
client.sync(payload); | ||
server.connect((player, ...payloads) => { | ||
remotes.syncState.fire(player, ...payloads); | ||
}); | ||
remotes.requestState.fire(); | ||
remotes.requestState.connect((player) => { | ||
server.hydrate(player); | ||
}); | ||
``` | ||
@@ -357,21 +363,29 @@ | ||
- `options`: An object to configure the client syncer. | ||
- `options`: An object to configure the server syncer. | ||
- `atoms`: An object containing the atoms to sync. The keys should match the keys on the server. | ||
- `atoms`: An object containing the atoms to sync. The keys should match the keys on the client. | ||
- **optional** `interval`: The interval at which to send state updates to clients. Defaults to `0`, meaning updates are sent on the next frame. | ||
- **optional** `preserveHistory`: Whether to sync an exhaustive history of changes made to the atoms since the last sync event. If `true`, the server sends multiple payloads instead of one. Defaults to `false` for performance reasons. | ||
#### Returns | ||
`sync.client` returns a client sync object. The sync object has the following methods: | ||
`sync.server` returns a server sync object. The sync object has the following methods: | ||
- `client.sync(payload)` applies a state update from the server. | ||
- `server.connect(callback)` registers a callback to send state updates to clients. The callback will receive the player and the payload to send, and should send the payload to the client. The payload should not be mutated, so changes should be applied to a copy of the payload. | ||
- `server.hydrate(player)` sends the initial state to a player. This calls the function passed to `connect` with a payload containing the initial state. | ||
#### Caveats | ||
- The client sync object does not handle network communication. You must implement your own network layer to send and receive state updates. This includes requesting the initial state, which is implemented via `requestState` in the example above. | ||
- By default, Charm omits the individual changes made to atoms between sync events (i.e. a `counterAtom` set to `1` and then `2` will only send the final state of `2`). If you need to preserve a history of changes, set `preserveHistory` to `true`. | ||
- The server sync object does not handle network communication. You must implement your own network layer to send and receive state updates. This includes sending the initial state, which is implemented via `requestState` in the example above. | ||
--- | ||
### `sync.server(options)` | ||
### `sync.client(options)` | ||
Call `sync.server` to create a server sync object. The object handles sending state updates to clients at a specified interval, and hydrating clients with the initial state. | ||
Call `sync.client` to create a client sync object. The object will sync the client's copy of the state with the server's state. | ||
@@ -381,11 +395,9 @@ ```ts | ||
const server = sync.server({ atoms: atomsToSync }); | ||
const client = sync.client({ atoms: atomsToSync }); | ||
server.connect((player, payload) => { | ||
remotes.syncState.fire(player, payload); | ||
remotes.syncState.connect((...payloads) => { | ||
client.sync(...payloads); | ||
}); | ||
remotes.requestState.connect((player) => { | ||
server.hydrate(player); | ||
}); | ||
remotes.requestState.fire(); | ||
``` | ||
@@ -395,19 +407,15 @@ | ||
- `options`: An object to configure the server syncer. | ||
- `options`: An object to configure the client syncer. | ||
- `atoms`: An object containing the atoms to sync. The keys should match the keys on the client. | ||
- `atoms`: An object containing the atoms to sync. The keys should match the keys on the server. | ||
- **optional** `interval`: The interval at which to send state updates to clients. Defaults to `0`, meaning updates are sent on the next frame. | ||
#### Returns | ||
`sync.server` returns a server sync object. The sync object has the following methods: | ||
`sync.client` returns a client sync object. The sync object has the following methods: | ||
- `server.connect(callback)` registers a callback to send state updates to clients. The callback will receive the player and the payload to send, and should send the payload to the client. The payload should not be mutated, so changes should be applied to a copy of the payload. | ||
- `client.sync(...payloads)` applies a state update from the server. | ||
- `server.hydrate(player)` sends the initial state to a player. This calls the function passed to `connect` with a payload containing the initial state. | ||
#### Caveats | ||
- The server sync object does not handle network communication. You must implement your own network layer to send and receive state updates. This includes sending the initial state, which is implemented via `requestState` in the example above. | ||
- The client sync object does not handle network communication. You must implement your own network layer to send and receive state updates. This includes requesting the initial state, which is implemented via `requestState` in the example above. | ||
@@ -499,2 +507,4 @@ --- | ||
Note that if `preserveHistory` is `true`, the server will send multiple payloads to the client, so the callback passed to `connect` should accept a `...payloads` parameter. Otherwise, you only need to handle a single `payload` parameter. | ||
```ts | ||
@@ -508,4 +518,4 @@ import { sync } from "@rbxts/charm"; | ||
// Broadcast a state update to a specific player | ||
server.connect((player, payload) => { | ||
remotes.syncState.fire(player, payload); | ||
server.connect((player, ...payloads) => { | ||
remotes.syncState.fire(player, ...payloads); | ||
}); | ||
@@ -529,4 +539,4 @@ | ||
// Listen for incoming state changes from the server | ||
remotes.syncState.connect((payload) => { | ||
client.sync(payload); | ||
remotes.syncState.connect((...payloads) => { | ||
client.sync(...payloads); | ||
}); | ||
@@ -533,0 +543,0 @@ |
@@ -257,7 +257,9 @@ export = Charm; | ||
? ReadonlyMap<K, SyncPatch<V> | None> | ||
: State extends readonly (infer T)[] | ||
? readonly (SyncPatch<T> | None | undefined)[] | ||
: State extends object | ||
? { readonly [P in keyof State]?: SyncPatch<State[P]> } | ||
: State); | ||
: State extends Set<infer T> | ReadonlySet<infer T> | ||
? ReadonlyMap<T, true | None> | ||
: State extends readonly (infer T)[] | ||
? readonly (SyncPatch<T> | None | undefined)[] | ||
: State extends object | ||
? { readonly [P in keyof State]?: SyncPatch<State[P]> } | ||
: State); | ||
@@ -290,2 +292,12 @@ /** | ||
interval?: number; | ||
/** | ||
* Whether the history of state changes since the client's last update | ||
* should be preserved. This is useful for values that change multiple times | ||
* per frame, where each individual change is important. Defaults to `false`. | ||
* | ||
* If `true`, the broadcaster will send a list of payloads to the client | ||
* instead of a single payload. The client will apply each payload in order | ||
* to reconstruct the state's changes over time. | ||
*/ | ||
preserveHistory?: boolean; | ||
} | ||
@@ -298,5 +310,5 @@ | ||
* | ||
* @param payload The patch or hydration payload to apply. | ||
* @param payloads The patches or hydration payloads to apply. | ||
*/ | ||
sync(payload: SyncPayload<Atoms>): void; | ||
sync(...payloads: SyncPayload<Atoms>[]): void; | ||
} | ||
@@ -308,6 +320,6 @@ | ||
* the client whenever the state changes. When a change occurs, the `callback` | ||
* is called with the player and the payload to send. | ||
* is called with the player and the payloads to send. | ||
* | ||
* Note that the `payload` object should not be mutated. If you need to | ||
* modify the payload, apply the changes to a copy of the object. | ||
* Note that a `payload` object should not be mutated. If you need to modify | ||
* a payload, apply the changes to a copy of the object. | ||
* | ||
@@ -317,3 +329,3 @@ * @param callback The function to call when the state changes. | ||
*/ | ||
connect(callback: (player: Player, payload: SyncPayload<Atoms>) => void): Cleanup; | ||
connect(callback: (player: Player, ...payloads: SyncPayload<Atoms>[]) => void): Cleanup; | ||
/** | ||
@@ -320,0 +332,0 @@ * Hydrates the client's state with the server's state. This should be |
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
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
59392
302
551
25