@dcl/ecs 7.0.6-4177592674.commit-39cdc99 → 7.0.6-4180146485.commit-9a7dde9

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.
Files changed (44) hide show
  1. package/dist/components/extended/Animator.d.ts +3 -2
  2. package/dist/components/extended/Material.d.ts +2 -2
  3. package/dist/components/extended/MeshCollider.d.ts +2 -2
  4. package/dist/components/extended/MeshRenderer.d.ts +2 -2
  5. package/dist/components/generated/global.gen.d.ts +26 -26
  6. package/dist/components/generated/index.gen.d.ts +32 -31
  7. package/dist/components/generated/index.gen.js +4 -1
  8. package/dist/components/generated/pb/decentraland/sdk/components/pointer_events_result.gen.d.ts +1 -9
  9. package/dist/components/generated/pb/decentraland/sdk/components/pointer_events_result.gen.js +2 -36
  10. package/dist/components/index.d.ts +9 -9
  11. package/dist/components/index.js +1 -1
  12. package/dist/components/{legacy → manual}/Transform.d.ts +2 -2
  13. package/dist/components/{legacy → manual}/Transform.js +0 -0
  14. package/dist/components/types.d.ts +1 -1
  15. package/dist/engine/component.d.ts +74 -27
  16. package/dist/engine/component.js +7 -240
  17. package/dist/engine/grow-only-value-set-component-definition.d.ts +8 -0
  18. package/dist/engine/grow-only-value-set-component-definition.js +132 -0
  19. package/dist/engine/index.d.ts +1 -2
  20. package/dist/engine/index.js +18 -1
  21. package/dist/engine/input.d.ts +3 -3
  22. package/dist/engine/input.js +75 -68
  23. package/dist/engine/lww-element-set-component-definition.d.ts +6 -0
  24. package/dist/engine/lww-element-set-component-definition.js +229 -0
  25. package/dist/engine/readonly.d.ts +2 -2
  26. package/dist/engine/types.d.ts +20 -9
  27. package/dist/engine/types.js +1 -1
  28. package/dist/runtime/invariant.d.ts +1 -0
  29. package/dist/runtime/invariant.js +6 -1
  30. package/dist/runtime/types.d.ts +1 -2
  31. package/dist/runtime/types.js +0 -1
  32. package/dist/schemas/ISchema.d.ts +3 -2
  33. package/dist/schemas/Map.d.ts +0 -1
  34. package/dist/serialization/crdt/appendValue.d.ts +1 -0
  35. package/dist/serialization/crdt/appendValue.js +49 -0
  36. package/dist/serialization/crdt/index.d.ts +1 -0
  37. package/dist/serialization/crdt/index.js +1 -0
  38. package/dist/serialization/crdt/message.js +4 -0
  39. package/dist/serialization/crdt/types.d.ts +24 -3
  40. package/dist/serialization/crdt/types.js +2 -1
  41. package/dist/systems/crdt/index.d.ts +1 -1
  42. package/dist/systems/crdt/index.js +21 -8
  43. package/dist/systems/events.d.ts +2 -2
  44. package/package.json +3 -3
@@ -0,0 +1,6 @@
1
+ import { ISchema } from '../schemas';
2
+ import { PutComponentMessageBody, DeleteComponentMessageBody, CrdtMessageBody } from '../serialization/crdt';
3
+ import { Entity } from './entity';
4
+ export declare function incrementTimestamp(entity: Entity, timestamps: Map<Entity, number>): number;
5
+ 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];
6
+ 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>;
@@ -0,0 +1,229 @@
1
+ import { ReadWriteByteBuffer } from '../serialization/ByteBuffer';
2
+ import { ProcessMessageResultType, CrdtMessageType } from '../serialization/crdt';
3
+ import { dataCompare } from '../systems/crdt/utils';
4
+ import { deepReadonly } from './readonly';
5
+ export function incrementTimestamp(entity, timestamps) {
6
+ const newTimestamp = (timestamps.get(entity) || 0) + 1;
7
+ timestamps.set(entity, newTimestamp);
8
+ return newTimestamp;
9
+ }
10
+ export function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
11
+ /**
12
+ * Process the received message only if the lamport number recieved is higher
13
+ * than the stored one. If its lower, we spread it to the network to correct the peer.
14
+ * If they are equal, the bigger raw data wins.
15
+
16
+ * Returns the recieved data if the lamport number was bigger than ours.
17
+ * If it was an outdated message, then we return void
18
+ * @public
19
+ */
20
+ function crdtRuleForCurrentState(message) {
21
+ const { entityId, timestamp } = message;
22
+ const currentTimestamp = timestamps.get(entityId);
23
+ // The received message is > than our current value, update our state.components.
24
+ if (currentTimestamp === undefined || currentTimestamp < timestamp) {
25
+ return ProcessMessageResultType.StateUpdatedTimestamp;
26
+ }
27
+ // Outdated Message. Resend our state message through the wire.
28
+ if (currentTimestamp > timestamp) {
29
+ // console.log('2', currentTimestamp, timestamp)
30
+ return ProcessMessageResultType.StateOutdatedTimestamp;
31
+ }
32
+ // Deletes are idempotent
33
+ if (message.type === CrdtMessageType.DELETE_COMPONENT && !data.has(entityId)) {
34
+ return ProcessMessageResultType.NoChanges;
35
+ }
36
+ let currentDataGreater = 0;
37
+ if (data.has(entityId)) {
38
+ const writeBuffer = new ReadWriteByteBuffer();
39
+ schema.serialize(data.get(entityId), writeBuffer);
40
+ currentDataGreater = dataCompare(writeBuffer.toBinary(), message.data || null);
41
+ }
42
+ else {
43
+ currentDataGreater = dataCompare(null, message.data);
44
+ }
45
+ // Same data, same timestamp. Weirdo echo message.
46
+ // console.log('3', currentDataGreater, writeBuffer.toBinary(), (message as any).data || null)
47
+ if (currentDataGreater === 0) {
48
+ return ProcessMessageResultType.NoChanges;
49
+ }
50
+ else if (currentDataGreater > 0) {
51
+ // Current data is greater
52
+ return ProcessMessageResultType.StateOutdatedData;
53
+ }
54
+ else {
55
+ // Curent data is lower
56
+ return ProcessMessageResultType.StateUpdatedData;
57
+ }
58
+ }
59
+ return (msg) => {
60
+ /* istanbul ignore next */
61
+ if (msg.type !== CrdtMessageType.PUT_COMPONENT && msg.type !== CrdtMessageType.DELETE_COMPONENT)
62
+ /* istanbul ignore next */
63
+ return [null, data.get(msg.entityId)];
64
+ const action = crdtRuleForCurrentState(msg);
65
+ const entity = msg.entityId;
66
+ switch (action) {
67
+ case ProcessMessageResultType.StateUpdatedData:
68
+ case ProcessMessageResultType.StateUpdatedTimestamp: {
69
+ timestamps.set(entity, msg.timestamp);
70
+ if (msg.type === CrdtMessageType.PUT_COMPONENT) {
71
+ const buf = new ReadWriteByteBuffer(msg.data);
72
+ data.set(entity, schema.deserialize(buf));
73
+ }
74
+ else {
75
+ data.delete(entity);
76
+ }
77
+ return [null, data.get(entity)];
78
+ }
79
+ case ProcessMessageResultType.StateOutdatedTimestamp:
80
+ case ProcessMessageResultType.StateOutdatedData: {
81
+ if (data.has(entity)) {
82
+ const writeBuffer = new ReadWriteByteBuffer();
83
+ schema.serialize(data.get(entity), writeBuffer);
84
+ return [
85
+ {
86
+ type: CrdtMessageType.PUT_COMPONENT,
87
+ componentId,
88
+ data: writeBuffer.toBinary(),
89
+ entityId: entity,
90
+ timestamp: timestamps.get(entity)
91
+ },
92
+ data.get(entity)
93
+ ];
94
+ }
95
+ else {
96
+ return [
97
+ {
98
+ type: CrdtMessageType.DELETE_COMPONENT,
99
+ componentId,
100
+ entityId: entity,
101
+ timestamp: timestamps.get(entity)
102
+ },
103
+ undefined
104
+ ];
105
+ }
106
+ }
107
+ }
108
+ return [null, data.get(entity)];
109
+ };
110
+ }
111
+ export function createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data) {
112
+ return function* () {
113
+ for (const entity of dirtyIterator) {
114
+ const newTimestamp = incrementTimestamp(entity, timestamps);
115
+ if (data.has(entity)) {
116
+ const writeBuffer = new ReadWriteByteBuffer();
117
+ schema.serialize(data.get(entity), writeBuffer);
118
+ const msg = {
119
+ type: CrdtMessageType.PUT_COMPONENT,
120
+ componentId,
121
+ entityId: entity,
122
+ data: writeBuffer.toBinary(),
123
+ timestamp: newTimestamp
124
+ };
125
+ yield msg;
126
+ }
127
+ else {
128
+ const msg = {
129
+ type: CrdtMessageType.DELETE_COMPONENT,
130
+ componentId,
131
+ entityId: entity,
132
+ timestamp: newTimestamp
133
+ };
134
+ yield msg;
135
+ }
136
+ }
137
+ dirtyIterator.clear();
138
+ };
139
+ }
140
+ /**
141
+ * @internal
142
+ */
143
+ export function createComponentDefinitionFromSchema(componentName, componentId, schema) {
144
+ const data = new Map();
145
+ const dirtyIterator = new Set();
146
+ const timestamps = new Map();
147
+ return {
148
+ get componentId() {
149
+ return componentId;
150
+ },
151
+ get componentName() {
152
+ return componentName;
153
+ },
154
+ get componentType() {
155
+ // a getter is used here to prevent accidental changes
156
+ return 0 /* ComponentType.LastWriteWinElementSet */;
157
+ },
158
+ schema,
159
+ has(entity) {
160
+ return data.has(entity);
161
+ },
162
+ deleteFrom(entity, markAsDirty = true) {
163
+ const component = data.get(entity);
164
+ if (data.delete(entity) && markAsDirty) {
165
+ dirtyIterator.add(entity);
166
+ }
167
+ return component || null;
168
+ },
169
+ entityDeleted(entity, markAsDirty) {
170
+ if (data.delete(entity) && markAsDirty) {
171
+ dirtyIterator.add(entity);
172
+ }
173
+ },
174
+ getOrNull(entity) {
175
+ const component = data.get(entity);
176
+ return component ? deepReadonly(component) : null;
177
+ },
178
+ get(entity) {
179
+ const component = data.get(entity);
180
+ if (!component) {
181
+ throw new Error(`[getFrom] Component ${componentName} for entity #${entity} not found`);
182
+ }
183
+ return deepReadonly(component);
184
+ },
185
+ create(entity, value) {
186
+ const component = data.get(entity);
187
+ if (component) {
188
+ throw new Error(`[create] Component ${componentName} for ${entity} already exists`);
189
+ }
190
+ const usedValue = value === undefined ? schema.create() : schema.extend ? schema.extend(value) : value;
191
+ data.set(entity, usedValue);
192
+ dirtyIterator.add(entity);
193
+ return usedValue;
194
+ },
195
+ createOrReplace(entity, value) {
196
+ const usedValue = value === undefined ? schema.create() : schema.extend ? schema.extend(value) : value;
197
+ data.set(entity, usedValue);
198
+ dirtyIterator.add(entity);
199
+ return usedValue;
200
+ },
201
+ getMutableOrNull(entity) {
202
+ const component = data.get(entity);
203
+ if (!component) {
204
+ return null;
205
+ }
206
+ dirtyIterator.add(entity);
207
+ return component;
208
+ },
209
+ getMutable(entity) {
210
+ const component = this.getMutableOrNull(entity);
211
+ if (component === null) {
212
+ throw new Error(`[mutable] Component ${componentName} for ${entity} not found`);
213
+ }
214
+ return component;
215
+ },
216
+ *iterator() {
217
+ for (const [entity, component] of data) {
218
+ yield [entity, component];
219
+ }
220
+ },
221
+ *dirtyIterator() {
222
+ for (const entity of dirtyIterator) {
223
+ yield entity;
224
+ }
225
+ },
226
+ getCrdtUpdates: createGetCrdtMessagesForLww(componentId, timestamps, dirtyIterator, schema, data),
227
+ updateFromCrdt: createUpdateLwwFromCrdt(componentId, timestamps, schema, data)
228
+ };
229
+ }
@@ -2,7 +2,7 @@ import { ComponentDefinition } from './component';
2
2
  /**
3
3
  * @public
4
4
  */
5
- export type DeepReadonlyMap<K, V> = ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>;
5
+ export type DeepReadonlyMap<K, V> = ReadonlyMap<K, DeepReadonly<V>>;
6
6
  /**
7
7
  * @public
8
8
  */
@@ -26,4 +26,4 @@ export type ReadonlyComponentSchema<T extends [ComponentDefinition<unknown>, ...
26
26
  /**
27
27
  * @public
28
28
  */
29
- export type DeepReadonly<T> = T extends ReadonlyPrimitive ? T : T extends Map<infer K, infer V> ? DeepReadonlyMap<K, V> : T extends Set<infer M> ? DeepReadonlySet<M> : DeepReadonlyObject<T>;
29
+ export type DeepReadonly<T> = T extends ReadonlyPrimitive ? T : T extends Array<infer K> ? ReadonlyArray<DeepReadonly<K>> : T extends Map<infer K, infer V> ? DeepReadonlyMap<K, V> : T extends Set<infer M> ? DeepReadonlySet<M> : DeepReadonlyObject<T>;
@@ -1,25 +1,22 @@
1
1
  import type { ISchema } from '../schemas/ISchema';
2
2
  import { MapResult, Spec } from '../schemas/Map';
3
3
  import { Transport } from '../systems/crdt/types';
4
- import { ComponentDefinition } from './component';
4
+ import { ComponentDefinition, GrowOnlyValueSetComponentDefinition, LastWriteWinElementSetComponentDefinition } from './component';
5
5
  import { Entity, EntityState } from './entity';
6
+ import { ValueSetOptions } from './grow-only-value-set-component-definition';
6
7
  import { ReadonlyComponentSchema } from './readonly';
7
8
  import { SystemFn } from './systems';
9
+ export * from './component';
10
+ export { ValueSetOptions };
8
11
  /**
9
12
  * @public
10
13
  */
11
14
  export type Unpacked<T> = T extends (infer U)[] ? U : T;
12
- /**
13
- * @public
14
- */
15
- export type ComponentSchema<T extends [ComponentDefinition<any>, ...ComponentDefinition<any>[]]> = {
16
- [K in keyof T]: T[K] extends ComponentDefinition<any> ? ReturnType<T[K]['getMutable']> : never;
17
- };
18
15
  /**
19
16
  * @public
20
17
  * Overrides component definition to support partial default values
21
18
  */
22
- export interface MapComponentDefinition<T> extends ComponentDefinition<T> {
19
+ export interface MapComponentDefinition<T> extends LastWriteWinElementSetComponentDefinition<T> {
23
20
  /**
24
21
  * Add the current component to an entity, throw an error if the component already exists (use `createOrReplace` instead).
25
22
  * - Internal comment: This method adds the &lt;entity,component&gt; to the list to be reviewed next frame
@@ -128,7 +125,21 @@ export interface IEngine {
128
125
  * const StateComponent = engine.defineComponentFromSchema("my-lib::VisibleComponent", Schemas.Bool)
129
126
  * ```
130
127
  */
131
- defineComponentFromSchema<T>(componentName: string, spec: ISchema<T>): ComponentDefinition<T>;
128
+ defineComponentFromSchema<T>(componentName: string, spec: ISchema<T>): LastWriteWinElementSetComponentDefinition<T>;
129
+ /**
130
+ * @public
131
+ * Defines a value set component.
132
+ * @param componentName - unique name to identify the component, a hash is calculated for it, it will fail if the hash has collisions.
133
+ * @param spec - An object with schema fields
134
+ * @returns The component definition
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * const StateComponentId = 10023
139
+ * const StateComponent = engine.defineValueSetComponentFromSchema("my-lib::VisibleComponent", Schemas.Int)
140
+ * ```
141
+ */
142
+ defineValueSetComponentFromSchema<T>(componentName: string, spec: ISchema<T>, options: ValueSetOptions<T>): GrowOnlyValueSetComponentDefinition<T>;
132
143
  /**
133
144
  * @public
134
145
  * Get the component definition from the component id.
@@ -1 +1 @@
1
- export {};
1
+ export * from './component';
@@ -1,3 +1,4 @@
1
1
  type K = unknown | Promise<unknown>;
2
+ export declare const __DEV__: boolean;
2
3
  export declare function checkNotThenable<T extends K>(t: T, error: string): T;
3
4
  export {};
@@ -1,5 +1,10 @@
1
+ /* istanbul ignore file */
2
+ export const __DEV__ = (typeof DEBUG === 'boolean' && DEBUG) ||
3
+ (typeof process === 'object' &&
4
+ (process.env?.NODE_ENV !== 'production' || process.env?.NODE_ENV === 'development')) ||
5
+ false;
1
6
  export function checkNotThenable(t, error) {
2
- if (globalThis.DEBUG) {
7
+ if (__DEV__) {
3
8
  if (t && typeof t === 'object' && typeof t.then === 'function') {
4
9
  throw new Error(error);
5
10
  }
@@ -1,7 +1,6 @@
1
1
  export type { SystemFn } from '../engine/systems';
2
2
  export type { TransportMessage, ReceiveMessage, Transport } from '../systems/crdt/types';
3
- export { TransformType, TransformComponent } from '../components/legacy/Transform';
3
+ export { TransformType, TransformComponent } from '../components/manual/Transform';
4
4
  export * from '../engine/component';
5
5
  export * from '../schemas/typing';
6
6
  export type { MapResult, Spec } from '../schemas/Map';
7
- export * from '../engine/component';
@@ -1,3 +1,2 @@
1
1
  export * from '../engine/component';
2
2
  export * from '../schemas/typing';
3
- export * from '../engine/component';
@@ -1,10 +1,11 @@
1
+ import { DeepReadonly } from '../engine/readonly';
1
2
  import { ByteBuffer } from '../serialization/ByteBuffer';
2
3
  /**
3
4
  * @public
4
5
  */
5
6
  export interface ISchema<T = any> {
6
- serialize(value: T, builder: ByteBuffer): void;
7
+ serialize(value: DeepReadonly<T>, builder: ByteBuffer): void;
7
8
  deserialize(reader: ByteBuffer): T;
8
9
  create(): T;
9
- extend?: (base?: T) => T;
10
+ extend?: (base: Partial<DeepReadonly<T>> | undefined) => T;
10
11
  }
@@ -18,4 +18,3 @@ export type MapResult<T extends Spec> = ToOptional<{
18
18
  export type MapResultWithOptional<T extends Spec> = ToOptional<{
19
19
  [K in keyof T]?: T[K] extends ISchema ? ReturnType<T[K]['deserialize']> : T[K] extends Spec ? MapResult<T[K]> : never;
20
20
  }>;
21
- export type MapSchemaType<T extends Spec> = ISchema<MapResult<T>>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ import { CrdtMessageProtocol } from './crdtMessageProtocol';
2
+ import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
3
+ /**
4
+ * @internal
5
+ */
6
+ export var AppendValueOperation;
7
+ (function (AppendValueOperation) {
8
+ AppendValueOperation.MESSAGE_HEADER_LENGTH = 16;
9
+ /**
10
+ * Call this function for an optimal writing data passing the ByteBuffer
11
+ * already allocated
12
+ */
13
+ function write(entity, timestamp, componentId, data, buf) {
14
+ // reserve the beginning
15
+ const startMessageOffset = buf.incrementWriteOffset(CRDT_MESSAGE_HEADER_LENGTH + AppendValueOperation.MESSAGE_HEADER_LENGTH);
16
+ // write body
17
+ buf.writeBuffer(data, false);
18
+ const messageLength = buf.currentWriteOffset() - startMessageOffset;
19
+ // Write CrdtMessage header
20
+ buf.setUint32(startMessageOffset, messageLength);
21
+ buf.setUint32(startMessageOffset + 4, CrdtMessageType.APPEND_VALUE);
22
+ // Write ComponentOperation header
23
+ buf.setUint32(startMessageOffset + 8, entity);
24
+ buf.setUint32(startMessageOffset + 12, componentId);
25
+ buf.setUint32(startMessageOffset + 16, timestamp);
26
+ const newLocal = messageLength - AppendValueOperation.MESSAGE_HEADER_LENGTH - CRDT_MESSAGE_HEADER_LENGTH;
27
+ buf.setUint32(startMessageOffset + 20, newLocal);
28
+ }
29
+ AppendValueOperation.write = write;
30
+ function read(buf) {
31
+ const header = CrdtMessageProtocol.readHeader(buf);
32
+ /* istanbul ignore if */
33
+ if (!header) {
34
+ return null;
35
+ }
36
+ /* istanbul ignore if */
37
+ if (header.type !== CrdtMessageType.APPEND_VALUE) {
38
+ throw new Error('AppendValueOperation tried to read another message type.');
39
+ }
40
+ return {
41
+ ...header,
42
+ entityId: buf.readUint32(),
43
+ componentId: buf.readUint32(),
44
+ timestamp: buf.readUint32(),
45
+ data: buf.readBuffer()
46
+ };
47
+ }
48
+ AppendValueOperation.read = read;
49
+ })(AppendValueOperation || (AppendValueOperation = {}));
@@ -1,4 +1,5 @@
1
1
  export * from './deleteComponent';
2
+ export * from './appendValue';
2
3
  export * from './deleteEntity';
3
4
  export * from './putComponent';
4
5
  export * from './types';
@@ -1,4 +1,5 @@
1
1
  export * from './deleteComponent';
2
+ export * from './appendValue';
2
3
  export * from './deleteEntity';
3
4
  export * from './putComponent';
4
5
  export * from './types';
@@ -3,6 +3,7 @@ import { CrdtMessageType } from './types';
3
3
  import { PutComponentOperation } from './putComponent';
4
4
  import { DeleteComponent } from './deleteComponent';
5
5
  import { DeleteEntity } from './deleteEntity';
6
+ import { AppendValueOperation } from './appendValue';
6
7
  export function readMessage(buf) {
7
8
  const header = CrdtMessageProtocol.getHeader(buf);
8
9
  if (!header)
@@ -13,6 +14,9 @@ export function readMessage(buf) {
13
14
  else if (header.type === CrdtMessageType.DELETE_COMPONENT) {
14
15
  return DeleteComponent.read(buf);
15
16
  }
17
+ else if (header.type === CrdtMessageType.APPEND_VALUE) {
18
+ return AppendValueOperation.read(buf);
19
+ }
16
20
  else if (header.type === CrdtMessageType.DELETE_ENTITY) {
17
21
  return DeleteEntity.read(buf);
18
22
  }
@@ -7,7 +7,8 @@ export declare enum CrdtMessageType {
7
7
  PUT_COMPONENT = 1,
8
8
  DELETE_COMPONENT = 2,
9
9
  DELETE_ENTITY = 3,
10
- MAX_MESSAGE_TYPE = 4
10
+ APPEND_VALUE = 4,
11
+ MAX_MESSAGE_TYPE = 5
11
12
  }
12
13
  /**
13
14
  * Min length = 8 bytes
@@ -40,6 +41,22 @@ export type PutComponentMessageBody = {
40
41
  timestamp: number;
41
42
  data: Uint8Array;
42
43
  };
44
+ /**
45
+ * Min. length = header (8 bytes) + 16 bytes = 24 bytes
46
+ *
47
+ * @param entity - Uint32 number of the entity
48
+ * @param componentId - Uint32 number of id
49
+ * @param timestamp - Uint32 timestamp
50
+ * @param data - Uint8[] data of component => length(4 bytes) + block of bytes[0..length-1]
51
+ * @public
52
+ */
53
+ export type AppendValueMessageBody = {
54
+ type: CrdtMessageType.APPEND_VALUE;
55
+ entityId: Entity;
56
+ componentId: number;
57
+ timestamp: number;
58
+ data: Uint8Array;
59
+ };
43
60
  /**
44
61
  * @param entity - Uint32 number of the entity
45
62
  * @param componentId - Uint32 number of id
@@ -60,6 +77,10 @@ export type DeleteEntityMessageBody = {
60
77
  type: CrdtMessageType.DELETE_ENTITY;
61
78
  entityId: Entity;
62
79
  };
80
+ /**
81
+ * @public
82
+ */
83
+ export type AppendValueMessage = CrdtMessageHeader & AppendValueMessageBody;
63
84
  /**
64
85
  * @public
65
86
  */
@@ -75,11 +96,11 @@ export type DeleteEntityMessage = CrdtMessageHeader & DeleteEntityMessageBody;
75
96
  /**
76
97
  * @public
77
98
  */
78
- export type CrdtMessage = PutComponentMessage | DeleteComponentMessage | DeleteEntityMessage;
99
+ export type CrdtMessage = PutComponentMessage | DeleteComponentMessage | DeleteEntityMessage | AppendValueMessage;
79
100
  /**
80
101
  * @public
81
102
  */
82
- export type CrdtMessageBody = PutComponentMessageBody | DeleteComponentMessageBody | DeleteEntityMessageBody;
103
+ export type CrdtMessageBody = PutComponentMessageBody | DeleteComponentMessageBody | DeleteEntityMessageBody | AppendValueMessageBody;
83
104
  export declare enum ProcessMessageResultType {
84
105
  /**
85
106
  * Typical message and new state set.
@@ -8,7 +8,8 @@ export var CrdtMessageType;
8
8
  CrdtMessageType[CrdtMessageType["PUT_COMPONENT"] = 1] = "PUT_COMPONENT";
9
9
  CrdtMessageType[CrdtMessageType["DELETE_COMPONENT"] = 2] = "DELETE_COMPONENT";
10
10
  CrdtMessageType[CrdtMessageType["DELETE_ENTITY"] = 3] = "DELETE_ENTITY";
11
- CrdtMessageType[CrdtMessageType["MAX_MESSAGE_TYPE"] = 4] = "MAX_MESSAGE_TYPE";
11
+ CrdtMessageType[CrdtMessageType["APPEND_VALUE"] = 4] = "APPEND_VALUE";
12
+ CrdtMessageType[CrdtMessageType["MAX_MESSAGE_TYPE"] = 5] = "MAX_MESSAGE_TYPE";
12
13
  })(CrdtMessageType || (CrdtMessageType = {}));
13
14
  /**
14
15
  * @public
@@ -4,4 +4,4 @@ import { CrdtMessageType } from '../../serialization/crdt/types';
4
4
  /**
5
5
  * @public
6
6
  */
7
- export type OnChangeFunction = (entity: Entity, operation: CrdtMessageType, component?: ComponentDefinition<any>) => void;
7
+ export type OnChangeFunction = (entity: Entity, operation: CrdtMessageType, component?: ComponentDefinition<any>, componentValue?: any) => void;
@@ -1,6 +1,6 @@
1
1
  import { EntityState } from '../../engine/entity';
2
2
  import { ReadWriteByteBuffer } from '../../serialization/ByteBuffer';
3
- import { CrdtMessageProtocol } from '../../serialization/crdt';
3
+ import { AppendValueOperation, CrdtMessageProtocol } from '../../serialization/crdt';
4
4
  import { DeleteComponent } from '../../serialization/crdt/deleteComponent';
5
5
  import { DeleteEntity } from '../../serialization/crdt/deleteEntity';
6
6
  import { PutComponentOperation } from '../../serialization/crdt/putComponent';
@@ -35,7 +35,6 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
35
35
  if (header.type === CrdtMessageType.DELETE_COMPONENT) {
36
36
  const message = DeleteComponent.read(buffer);
37
37
  receivedMessages.push({
38
- ...header,
39
38
  ...message,
40
39
  transportId,
41
40
  messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
@@ -44,7 +43,6 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
44
43
  else if (header.type === CrdtMessageType.PUT_COMPONENT) {
45
44
  const message = PutComponentOperation.read(buffer);
46
45
  receivedMessages.push({
47
- ...header,
48
46
  ...message,
49
47
  transportId,
50
48
  messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
@@ -53,7 +51,14 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
53
51
  else if (header.type === CrdtMessageType.DELETE_ENTITY) {
54
52
  const message = DeleteEntity.read(buffer);
55
53
  receivedMessages.push({
56
- ...header,
54
+ ...message,
55
+ transportId,
56
+ messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
57
+ });
58
+ }
59
+ else if (header.type === CrdtMessageType.APPEND_VALUE) {
60
+ const message = AppendValueOperation.read(buffer);
61
+ receivedMessages.push({
57
62
  ...message,
58
63
  transportId,
59
64
  messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
@@ -99,13 +104,13 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
99
104
  }
100
105
  const component = engine.getComponentOrNull(msg.componentId);
101
106
  if (component) {
102
- const [conflictMessage] = component.updateFromCrdt(msg);
107
+ const [conflictMessage, value] = component.updateFromCrdt(msg);
103
108
  if (conflictMessage) {
104
109
  const offset = bufferForOutdated.currentWriteOffset();
105
110
  if (conflictMessage.type === CrdtMessageType.PUT_COMPONENT) {
106
111
  PutComponentOperation.write(msg.entityId, conflictMessage.timestamp, conflictMessage.componentId, conflictMessage.data, bufferForOutdated);
107
112
  }
108
- else {
113
+ else if (conflictMessage.type === CrdtMessageType.DELETE_COMPONENT) {
109
114
  DeleteComponent.write(msg.entityId, component.componentId, conflictMessage.timestamp, bufferForOutdated);
110
115
  }
111
116
  outdatedMessages.push({
@@ -116,7 +121,7 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
116
121
  else {
117
122
  // Add message to transport queue to be processed by others transports
118
123
  broadcastMessages.push(msg);
119
- onProcessEntityComponentChange && onProcessEntityComponentChange(msg.entityId, msg.type, component);
124
+ onProcessEntityComponentChange && onProcessEntityComponentChange(msg.entityId, msg.type, component, value);
120
125
  }
121
126
  }
122
127
  }
@@ -155,11 +160,19 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
155
160
  else if (message.type === CrdtMessageType.DELETE_COMPONENT) {
156
161
  DeleteComponent.write(message.entityId, component.componentId, message.timestamp, buffer);
157
162
  }
163
+ else if (message.type === CrdtMessageType.APPEND_VALUE) {
164
+ AppendValueOperation.write(message.entityId, message.timestamp, message.componentId, message.data, buffer);
165
+ }
158
166
  crdtMessages.push({
159
167
  ...message,
160
168
  messageBuffer: buffer.buffer().subarray(offset, buffer.currentWriteOffset())
161
169
  });
162
- onProcessEntityComponentChange && onProcessEntityComponentChange(message.entityId, message.type, component);
170
+ if (onProcessEntityComponentChange) {
171
+ const rawValue = message.type === CrdtMessageType.PUT_COMPONENT || message.type === CrdtMessageType.APPEND_VALUE
172
+ ? component.get(message.entityId)
173
+ : undefined;
174
+ onProcessEntityComponentChange(message.entityId, message.type, component, rawValue);
175
+ }
163
176
  }
164
177
  }
165
178
  }
@@ -1,10 +1,10 @@
1
1
  import { InputAction } from '../components/generated/pb/decentraland/sdk/components/common/input_action.gen';
2
- import { PBPointerEventsResult_PointerCommand } from '../components/generated/pb/decentraland/sdk/components/pointer_events_result.gen';
2
+ import { PBPointerEventsResult } from '../components/generated/pb/decentraland/sdk/components/pointer_events_result.gen';
3
3
  import { Entity } from '../engine/entity';
4
4
  /**
5
5
  * @public
6
6
  */
7
- export type EventSystemCallback = (event: PBPointerEventsResult_PointerCommand) => void;
7
+ export type EventSystemCallback = (event: PBPointerEventsResult) => void;
8
8
  /**
9
9
  * @public
10
10
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl/ecs",
3
- "version": "7.0.6-4177592674.commit-39cdc99",
3
+ "version": "7.0.6-4180146485.commit-9a7dde9",
4
4
  "description": "Decentraland ECS",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@dcl/js-runtime": "file:../js-runtime",
31
- "@dcl/protocol": "1.0.0-4114477251.commit-ccb88d6"
31
+ "@dcl/protocol": "1.0.0-4177500465.commit-247c87f"
32
32
  },
33
33
  "files": [
34
34
  "dist",
@@ -40,5 +40,5 @@
40
40
  "displayName": "ECS",
41
41
  "tsconfig": "./tsconfig.json"
42
42
  },
43
- "commit": "39cdc99ea857c63f707ec9188836116d838fa10e"
43
+ "commit": "9a7dde903f381c1778ec3c7519e4f312ab9b2ee3"
44
44
  }