Storage Property
A StorageProperty is one value kept in sync across the session: a score, a
position, a game phase, a player's ready flag. You group them into a
StoragePropertySet and hand that to a Sync Entity.
Properties come in two kinds. Manual properties are ones you set yourself. Automatic properties read from a getter and write through a setter, so the framework detects changes for you.
Manual versus automatic
import { StorageProperty } from 'ConnectedFramework.lspkg/Core/StorageProperty';
import { StorageTypes } from 'ConnectedFramework.lspkg/Core/StorageTypes';
@component
export class Example extends BaseScriptComponent {
private currentHealth = 100;
// Manual: you call setPendingValue when the value changes.
private score = StorageProperty.manualInt('score', 0);
// Automatic: the framework reads the getter and applies remote
// values through the setter.
private health = StorageProperty.auto<number>(
'health',
StorageTypes.int,
() => this.currentHealth,
(value) => {
this.currentHealth = value;
}
);
scorePoint() {
this.score.setPendingValue((this.score.currentOrPendingValue ?? 0) + 1);
}
}
Use manual when writes happen at discrete moments, such as scoring. Use automatic when the value lives somewhere else already and changes continuously.
Reading a value
Three members hold a value, and picking the wrong one is the most common source of confusion:
| Name | Type | Description |
|---|---|---|
currentValue | Type | null | The value believed to be synced across the network. In most cases this is what you want to read. |
pendingValue | Type | null | The local value that may be sent at the next opportunity. May differ from currentValue. |
currentOrPendingValue | Type | null | The most recently changed local value, whether current or pending. Read this when you want the most up-to-date local value. |
The distinction matters when sendsPerSecondLimit is set: currentValue only
updates when the value is actually sent to the network, so a value changing every
frame will look stale there while currentOrPendingValue stays fresh.
Members
| Name | Type | Description |
|---|---|---|
sendsPerSecondLimit | number | If zero or greater, limits how often updates are sent. Useful to avoid rate limiting when a value changes every frame. Defaults to -1, meaning unlimited. |
equalsCheck | (a, b) => boolean | Comparison used to detect a change. Should return true when two values are equal or reasonably close. Defaults to strict equality. |
needToSendUpdate | boolean | Whether a change is waiting to be sent. |
markedDirty | boolean | Set to force a send and skip the equality check. |
getterFunc | (() => Type) | null | Getter, for automatic properties. |
setterFunc | ((val: Type) => void) | null | Setter, for automatic properties. |
| Name (signature) | Description |
|---|---|
setPendingValue(newValue: Type): void | Sets the local value, to be sent at the next opportunity. |
Events
| Name | Called with | Description |
|---|---|---|
onAnyChange | newValue, oldValue, updateInfo | null | currentValue changed, by any client. |
onRemoteChange | newValue, oldValue, updateInfo | currentValue changed by a remote client. |
onLocalChange | newValue, oldValue | currentValue changed by the local client. |
onPendingValueChange | newValue, oldValue | The pending value changed. |
Use onRemoteChange when the local client already knows about its own change
and only needs to react to others. Use onAnyChange for UI that should reflect
the value regardless of who set it.
Factories
Manual
StorageProperty.manual<T>(key, propertyType, startingValue?, smoothingOptions?)
is the general form, where propertyType is a StorageTypes value from
ConnectedFramework.lspkg/Core/StorageTypes. Typed shorthands avoid passing a StorageTypes value:
manualString, manualBool, manualInt, manualFloat, manualDouble,
manualQuat, and the array variants manualBoolArray, manualStringArray,
manualIntArray, manualFloatArray, manualDoubleArray, manualQuatArray.
Automatic
StorageProperty.auto<T>(key, propertyType, getterFunc, setterFunc, smoothingOptions?)
is the general form, with the same shorthands: autoBool, autoString,
autoInt, autoFloat, autoDouble, autoQuat, and the array variants
autoStringArray, autoBoolArray, autoFloatArray, autoDoubleArray,
autoIntArray, autoQuatArray.
Bound to scene state
These wire a property directly to something in the scene, so you do not write a getter and setter yourself:
| Name (signature) | Description |
|---|---|
forTransform(transform, positionType, rotationType, scaleType, smoothingOptions?) | Syncs a transform. This is what Sync Transform uses. |
forPosition(transform, ...) | Syncs position only. |
forRotation(transform, ...) | Syncs rotation only. |
forScale(transform, ...) | Syncs scale only. |
forTextText(text: Text) | Syncs a Text component's string. |
forMaterialProperty<T>(...) | Syncs a named material property. Used by Sync Materials. |
forMeshVisualProperty<T>(...) | Syncs a named mesh visual property. |
forMeshVisualBaseColor(...) | Syncs a mesh visual's base color. |
wrapProperty(...) | Wraps an arbitrary object property. |
getStoreValueDynamic<T>(...) | Reads a store value whose type is decided at runtime. |
Smoothing
Every factory takes optional smoothing options. With smoothing on, remote values are interpolated rather than snapped, which matters for anything visibly moving. Sync Transform exposes this as a checkbox plus an interpolation target.
Usage
import { StorageProperty } from 'ConnectedFramework.lspkg/Core/StorageProperty';
import { StoragePropertySet } from 'ConnectedFramework.lspkg/Core/StoragePropertySet';
import { SyncEntity } from 'ConnectedFramework.lspkg/Core/SyncEntity';
@component
export class RoundPhase extends BaseScriptComponent {
@input
phaseLabel!: Text;
private phase = StorageProperty.manualString('phase', 'waiting');
private syncEntity = new SyncEntity(this, {
propertySet: new StoragePropertySet([this.phase]),
});
onAwake() {
this.phase.onAnyChange.add((newValue) => {
this.phaseLabel.text = newValue;
});
}
startRound() {
if (this.syncEntity.canIModifyStore()) {
this.phase.setPendingValue('playing');
}
}
}
Related
- Sync Entity
- Sync Transform
- Sync Helpers:
DisplayStoragePropertyrenders a property into aText.