0.1.15
Performance
- Dropped the per-decode
objectToRefIdreverse-lookupMaprebuild. The decoder already tags every Schema/ArraySchema/MapSchema instance with~refId, andDataChangecarriesrefIddirectly — both are used instead. Eliminates ~137 KB/op of garbage per decode on a 200-player state. - Unified
previousResultsByRefId/currentResultsByRefIdinto a single persistent cache plus a reusedvisitedThisPassset. Removes a per-renderMapallocation and copy loop inuseColyseusState. - Memoized
getSchemaFieldNamesper Schema constructor (wasObject.values(metadata).map(...)on every visit). - Replaced
Object.keys(prev).length !== Object.keys(next).lengthMapSchema size check with a count vsnode.sizecomparison (no array allocations). - Parent-chain dirty walk now short-circuits once it hits an already-dirty ancestor.
Measured on a synthetic "50 of 200 players mutate each tick" benchmark: ~25% faster, ~99% less allocation per tick.
Tests
- +60 tests covering: selectors, primitive
ArraySchema/MapSchema,Schemareference reassignment,MapSchema.clear(), multiple hooks sharing a subscription, late-binding state/decoder,useRoomMessage,useLobbyRoom,useQueueRoom,createRoomContext,createLobbyContext, and coexistence withgetDecoderStateCallbacks(onAdd/onRemove/onChange/listen). - New opt-in microbenchmark at
src/tests/bench.test.ts(BENCH=1 NODE_OPTIONS=--expose-gc npx vitest run src/tests/bench.test.ts).