@dcl/ecs 7.22.2 → 7.22.3-23911510253.commit-490338c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,5 +4,5 @@ import { PutComponentMessageBody, DeleteComponentMessageBody, CrdtMessageBody }
4
4
  import { Entity } from './entity';
5
5
  export declare function incrementTimestamp(entity: Entity, timestamps: Map<Entity, number>): number;
6
6
  export declare function createDumpLwwFunctionFromCrdt(componentId: number, timestamps: Map<Entity, number>, schema: Pick<ISchema<any>, 'serialize' | 'deserialize'>, data: Map<Entity, unknown>): (buffer: ByteBuffer, filterEntity?: ((entity: Entity) => boolean) | undefined) => void;
7
- export declare function createUpdateLwwFromCrdt(componentId: number, timestamps: Map<Entity, number>, schema: Pick<ISchema<any>, 'serialize' | 'deserialize'>, data: Map<Entity, unknown>): (msg: CrdtMessageBody) => [null | PutComponentMessageBody | DeleteComponentMessageBody, any];
8
- export declare function createGetCrdtMessagesForLww(componentId: number, timestamps: Map<Entity, number>, dirtyIterator: Set<Entity>, schema: Pick<ISchema<any>, 'serialize'>, data: Map<Entity, unknown>): () => Generator<PutComponentMessageBody | DeleteComponentMessageBody, void, unknown>;
7
+ export declare function createUpdateLwwFromCrdt(componentId: number, timestamps: Map<Entity, number>, schema: Pick<ISchema<any>, 'serialize' | 'deserialize'>, data: Map<Entity, unknown>, lastSentData: Map<Entity, Uint8Array>): (msg: CrdtMessageBody) => [null | PutComponentMessageBody | DeleteComponentMessageBody, any];
8
+ export declare function createGetCrdtMessagesForLww(componentId: number, timestamps: Map<Entity, number>, dirtyIterator: Set<Entity>, schema: Pick<ISchema<any>, 'serialize'>, data: Map<Entity, unknown>, lastSentData: Map<Entity, Uint8Array>): () => Generator<PutComponentMessageBody | DeleteComponentMessageBody, void, unknown>;
@@ -30,7 +30,7 @@ export function createDumpLwwFunctionFromCrdt(componentId, timestamps, schema, d
30
30
  }
31
31
  };
32
32
  }
33
- export function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
33
+ export function createUpdateLwwFromCrdt(componentId, timestamps, schema, data, lastSentData) {
34
34
  /**
35
35
  * Process the received message only if the lamport number recieved is higher
36
36
  * than the stored one. If its lower, we spread it to the network to correct the peer.
@@ -96,9 +96,11 @@ export function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
96
96
  if (msg.type === CrdtMessageType.PUT_COMPONENT || msg.type === CrdtMessageType.PUT_COMPONENT_NETWORK) {
97
97
  const buf = new ReadWriteByteBuffer(msg.data);
98
98
  data.set(entity, schema.deserialize(buf));
99
+ lastSentData.set(entity, new Uint8Array(msg.data));
99
100
  }
100
101
  else {
101
102
  data.delete(entity);
103
+ lastSentData.delete(entity);
102
104
  }
103
105
  return [null, data.get(entity)];
104
106
  }
@@ -134,23 +136,34 @@ export function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
134
136
  return [null, data.get(entity)];
135
137
  };
136
138
  }
137
- export function createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data) {
139
+ export function createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data, lastSentData) {
138
140
  return function* () {
141
+ const writeBuffer = new ReadWriteByteBuffer();
139
142
  for (const entity of dirtyIterator) {
140
- const newTimestamp = incrementTimestamp(entity, timestamps);
141
143
  if (data.has(entity)) {
142
- const writeBuffer = new ReadWriteByteBuffer();
144
+ writeBuffer.resetBuffer();
143
145
  schema.serialize(data.get(entity), writeBuffer);
146
+ // Compare against last-sent snapshot using the zero-copy subarray view.
147
+ // Only allocate a copy when bytes actually differ.
148
+ const previousBytes = lastSentData.get(entity);
149
+ if (previousBytes && dataCompare(writeBuffer.toBinary(), previousBytes) === 0) {
150
+ continue;
151
+ }
152
+ const currentBytes = writeBuffer.toCopiedBinary();
153
+ const newTimestamp = incrementTimestamp(entity, timestamps);
154
+ lastSentData.set(entity, currentBytes);
144
155
  const msg = {
145
156
  type: CrdtMessageType.PUT_COMPONENT,
146
157
  componentId,
147
158
  entityId: entity,
148
- data: writeBuffer.toBinary(),
159
+ data: currentBytes,
149
160
  timestamp: newTimestamp
150
161
  };
151
162
  yield msg;
152
163
  }
153
164
  else {
165
+ lastSentData.delete(entity);
166
+ const newTimestamp = incrementTimestamp(entity, timestamps);
154
167
  const msg = {
155
168
  type: CrdtMessageType.DELETE_COMPONENT,
156
169
  componentId,
@@ -170,6 +183,7 @@ export function createComponentDefinitionFromSchema(componentName, componentId,
170
183
  const data = new Map();
171
184
  const dirtyIterator = new Set();
172
185
  const timestamps = new Map();
186
+ const lastSentData = new Map();
173
187
  const onChangeCallbacks = new Map();
174
188
  return {
175
189
  get componentId() {
@@ -191,12 +205,14 @@ export function createComponentDefinitionFromSchema(componentName, componentId,
191
205
  if (data.delete(entity) && markAsDirty) {
192
206
  dirtyIterator.add(entity);
193
207
  }
208
+ lastSentData.delete(entity);
194
209
  return component || null;
195
210
  },
196
211
  entityDeleted(entity, markAsDirty) {
197
212
  if (data.delete(entity) && markAsDirty) {
198
213
  dirtyIterator.add(entity);
199
214
  }
215
+ lastSentData.delete(entity);
200
216
  },
201
217
  getOrNull(entity) {
202
218
  const component = data.get(entity);
@@ -223,6 +239,7 @@ export function createComponentDefinitionFromSchema(componentName, componentId,
223
239
  const usedValue = value === undefined ? schema.create() : schema.extend ? schema.extend(value) : value;
224
240
  data.set(entity, usedValue);
225
241
  dirtyIterator.add(entity);
242
+ lastSentData.delete(entity);
226
243
  return usedValue;
227
244
  },
228
245
  getMutableOrNull(entity) {
@@ -260,8 +277,8 @@ export function createComponentDefinitionFromSchema(componentName, componentId,
260
277
  yield entity;
261
278
  }
262
279
  },
263
- getCrdtUpdates: createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data),
264
- updateFromCrdt: createUpdateLwwFromCrdt(componentId, timestamps, schema, data),
280
+ getCrdtUpdates: createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data, lastSentData),
281
+ updateFromCrdt: createUpdateLwwFromCrdt(componentId, timestamps, schema, data, lastSentData),
265
282
  dumpCrdtStateToBuffer: createDumpLwwFunctionFromCrdt(componentId, timestamps, schema, data),
266
283
  onChange(entity, cb) {
267
284
  const cbs = onChangeCallbacks.get(entity) ?? [];
@@ -4,5 +4,5 @@ import { PutComponentMessageBody, DeleteComponentMessageBody, CrdtMessageBody }
4
4
  import { Entity } from './entity';
5
5
  export declare function incrementTimestamp(entity: Entity, timestamps: Map<Entity, number>): number;
6
6
  export declare function createDumpLwwFunctionFromCrdt(componentId: number, timestamps: Map<Entity, number>, schema: Pick<ISchema<any>, 'serialize' | 'deserialize'>, data: Map<Entity, unknown>): (buffer: ByteBuffer, filterEntity?: ((entity: Entity) => boolean) | undefined) => void;
7
- export declare function createUpdateLwwFromCrdt(componentId: number, timestamps: Map<Entity, number>, schema: Pick<ISchema<any>, 'serialize' | 'deserialize'>, data: Map<Entity, unknown>): (msg: CrdtMessageBody) => [null | PutComponentMessageBody | DeleteComponentMessageBody, any];
8
- export declare function createGetCrdtMessagesForLww(componentId: number, timestamps: Map<Entity, number>, dirtyIterator: Set<Entity>, schema: Pick<ISchema<any>, 'serialize'>, data: Map<Entity, unknown>): () => Generator<PutComponentMessageBody | DeleteComponentMessageBody, void, unknown>;
7
+ export declare function createUpdateLwwFromCrdt(componentId: number, timestamps: Map<Entity, number>, schema: Pick<ISchema<any>, 'serialize' | 'deserialize'>, data: Map<Entity, unknown>, lastSentData: Map<Entity, Uint8Array>): (msg: CrdtMessageBody) => [null | PutComponentMessageBody | DeleteComponentMessageBody, any];
8
+ export declare function createGetCrdtMessagesForLww(componentId: number, timestamps: Map<Entity, number>, dirtyIterator: Set<Entity>, schema: Pick<ISchema<any>, 'serialize'>, data: Map<Entity, unknown>, lastSentData: Map<Entity, Uint8Array>): () => Generator<PutComponentMessageBody | DeleteComponentMessageBody, void, unknown>;
@@ -35,7 +35,7 @@ function createDumpLwwFunctionFromCrdt(componentId, timestamps, schema, data) {
35
35
  };
36
36
  }
37
37
  exports.createDumpLwwFunctionFromCrdt = createDumpLwwFunctionFromCrdt;
38
- function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
38
+ function createUpdateLwwFromCrdt(componentId, timestamps, schema, data, lastSentData) {
39
39
  /**
40
40
  * Process the received message only if the lamport number recieved is higher
41
41
  * than the stored one. If its lower, we spread it to the network to correct the peer.
@@ -101,9 +101,11 @@ function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
101
101
  if (msg.type === crdt_1.CrdtMessageType.PUT_COMPONENT || msg.type === crdt_1.CrdtMessageType.PUT_COMPONENT_NETWORK) {
102
102
  const buf = new ByteBuffer_1.ReadWriteByteBuffer(msg.data);
103
103
  data.set(entity, schema.deserialize(buf));
104
+ lastSentData.set(entity, new Uint8Array(msg.data));
104
105
  }
105
106
  else {
106
107
  data.delete(entity);
108
+ lastSentData.delete(entity);
107
109
  }
108
110
  return [null, data.get(entity)];
109
111
  }
@@ -140,23 +142,34 @@ function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
140
142
  };
141
143
  }
142
144
  exports.createUpdateLwwFromCrdt = createUpdateLwwFromCrdt;
143
- function createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data) {
145
+ function createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data, lastSentData) {
144
146
  return function* () {
147
+ const writeBuffer = new ByteBuffer_1.ReadWriteByteBuffer();
145
148
  for (const entity of dirtyIterator) {
146
- const newTimestamp = incrementTimestamp(entity, timestamps);
147
149
  if (data.has(entity)) {
148
- const writeBuffer = new ByteBuffer_1.ReadWriteByteBuffer();
150
+ writeBuffer.resetBuffer();
149
151
  schema.serialize(data.get(entity), writeBuffer);
152
+ // Compare against last-sent snapshot using the zero-copy subarray view.
153
+ // Only allocate a copy when bytes actually differ.
154
+ const previousBytes = lastSentData.get(entity);
155
+ if (previousBytes && (0, utils_1.dataCompare)(writeBuffer.toBinary(), previousBytes) === 0) {
156
+ continue;
157
+ }
158
+ const currentBytes = writeBuffer.toCopiedBinary();
159
+ const newTimestamp = incrementTimestamp(entity, timestamps);
160
+ lastSentData.set(entity, currentBytes);
150
161
  const msg = {
151
162
  type: crdt_1.CrdtMessageType.PUT_COMPONENT,
152
163
  componentId,
153
164
  entityId: entity,
154
- data: writeBuffer.toBinary(),
165
+ data: currentBytes,
155
166
  timestamp: newTimestamp
156
167
  };
157
168
  yield msg;
158
169
  }
159
170
  else {
171
+ lastSentData.delete(entity);
172
+ const newTimestamp = incrementTimestamp(entity, timestamps);
160
173
  const msg = {
161
174
  type: crdt_1.CrdtMessageType.DELETE_COMPONENT,
162
175
  componentId,
@@ -177,6 +190,7 @@ function createComponentDefinitionFromSchema(componentName, componentId, schema)
177
190
  const data = new Map();
178
191
  const dirtyIterator = new Set();
179
192
  const timestamps = new Map();
193
+ const lastSentData = new Map();
180
194
  const onChangeCallbacks = new Map();
181
195
  return {
182
196
  get componentId() {
@@ -198,12 +212,14 @@ function createComponentDefinitionFromSchema(componentName, componentId, schema)
198
212
  if (data.delete(entity) && markAsDirty) {
199
213
  dirtyIterator.add(entity);
200
214
  }
215
+ lastSentData.delete(entity);
201
216
  return component || null;
202
217
  },
203
218
  entityDeleted(entity, markAsDirty) {
204
219
  if (data.delete(entity) && markAsDirty) {
205
220
  dirtyIterator.add(entity);
206
221
  }
222
+ lastSentData.delete(entity);
207
223
  },
208
224
  getOrNull(entity) {
209
225
  const component = data.get(entity);
@@ -230,6 +246,7 @@ function createComponentDefinitionFromSchema(componentName, componentId, schema)
230
246
  const usedValue = value === undefined ? schema.create() : schema.extend ? schema.extend(value) : value;
231
247
  data.set(entity, usedValue);
232
248
  dirtyIterator.add(entity);
249
+ lastSentData.delete(entity);
233
250
  return usedValue;
234
251
  },
235
252
  getMutableOrNull(entity) {
@@ -267,8 +284,8 @@ function createComponentDefinitionFromSchema(componentName, componentId, schema)
267
284
  yield entity;
268
285
  }
269
286
  },
270
- getCrdtUpdates: createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data),
271
- updateFromCrdt: createUpdateLwwFromCrdt(componentId, timestamps, schema, data),
287
+ getCrdtUpdates: createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data, lastSentData),
288
+ updateFromCrdt: createUpdateLwwFromCrdt(componentId, timestamps, schema, data, lastSentData),
272
289
  dumpCrdtStateToBuffer: createDumpLwwFunctionFromCrdt(componentId, timestamps, schema, data),
273
290
  onChange(entity, cb) {
274
291
  const cbs = onChangeCallbacks.get(entity) ?? [];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dcl/ecs",
3
3
  "description": "Decentraland ECS",
4
- "version": "7.22.2",
4
+ "version": "7.22.3-23911510253.commit-490338c",
5
5
  "author": "DCL",
6
6
  "bugs": "https://github.com/decentraland/ecs/issues",
7
7
  "files": [
@@ -34,5 +34,5 @@
34
34
  "dependencies": {},
35
35
  "types": "./dist/index.d.ts",
36
36
  "typings": "./dist/index.d.ts",
37
- "commit": "5f7f8a09410c9cb0e2e0e0d669dfc3733e76a8e8"
37
+ "commit": "490338ca013e81301587cfddf37f49d6d916f454"
38
38
  }