@dcl/ecs 7.0.6-3824930139.commit-9bd6c05 → 7.0.6-3830539086.commit-6152fbd

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.
@@ -17,7 +17,7 @@ export declare const AMOUNT_VERSION_AVAILABLE: number;
17
17
  * Convertion from its compound numbers to entity:
18
18
  * entity = (entityNumber & MAX_U16) | ((entityVersion & MAX_U16) << 16)
19
19
  */
20
- export declare type Entity = uint32 & {
20
+ export declare type Entity = number & {
21
21
  __entity_type: '';
22
22
  };
23
23
  /**
@@ -28,12 +28,41 @@ export declare const RESERVED_STATIC_ENTITIES = 512;
28
28
  * @public
29
29
  */
30
30
  export declare const MAX_ENTITY_NUMBER = 65535;
31
- export declare function EntityContainer(): {
31
+ export declare namespace EntityUtils {
32
+ /**
33
+ * @returns [entityNumber, entityVersion]
34
+ */
35
+ function fromEntityId(entityId: Entity): [number, number];
36
+ /**
37
+ * @returns compound number from entityNumber and entityVerison
38
+ */
39
+ function toEntityId(entityNumber: number, entityVersion: number): Entity;
40
+ }
41
+ /**
42
+ * @public
43
+ */
44
+ export declare enum EntityState {
45
+ Unknown = 0,
46
+ /**
47
+ * The entity was generated and added to the usedEntities set
48
+ */
49
+ UsedEntity = 1,
50
+ /**
51
+ * The entity was removed from current engine or remotely
52
+ */
53
+ Removed = 2,
54
+ /**
55
+ * The entity is reserved number.
56
+ */
57
+ Reserved = 3
58
+ }
59
+ export declare type EntityContainer = {
32
60
  generateEntity(): Entity;
33
61
  removeEntity(entity: Entity): boolean;
34
- entityExists(entity: Entity): boolean;
62
+ getEntityState(entity: Entity): EntityState;
35
63
  getExistingEntities(): Set<Entity>;
36
- entityVersion: (entity: Entity) => number;
37
- entityNumber: (entity: Entity) => number;
38
- entityId: (entityNumber: number, entityVersion: number) => Entity;
64
+ releaseRemovedEntities(): Entity[];
65
+ updateRemovedEntity(entity: Entity): boolean;
66
+ updateUsedEntity(entity: Entity): boolean;
39
67
  };
68
+ export declare function EntityContainer(): EntityContainer;
@@ -1,6 +1,8 @@
1
+ import { createGSet } from '@dcl/crdt/dist/gset';
1
2
  export const MAX_U16 = 0xffff;
2
3
  export const MASK_UPPER_16_ON_32 = 0xffff0000;
3
4
  export const AMOUNT_VERSION_AVAILABLE = MAX_U16 + 1;
5
+ // This type matches with @dcl/crdt entity type.
4
6
  /**
5
7
  * @public This first 512 entities are reserved by the renderer
6
8
  */
@@ -9,64 +11,151 @@ export const RESERVED_STATIC_ENTITIES = 512;
9
11
  * @public
10
12
  */
11
13
  export const MAX_ENTITY_NUMBER = MAX_U16;
12
- export function EntityContainer() {
13
- let entityCounter = RESERVED_STATIC_ENTITIES;
14
- const usedEntities = new Set();
15
- const removedEntities = new Map();
16
- function entityVersion(entity) {
17
- return (((entity & MASK_UPPER_16_ON_32) >> 16) & MAX_U16) >>> 0;
18
- }
19
- function entityNumber(entity) {
20
- return (entity & MAX_U16) >>> 0;
14
+ export var EntityUtils;
15
+ (function (EntityUtils) {
16
+ /**
17
+ * @returns [entityNumber, entityVersion]
18
+ */
19
+ function fromEntityId(entityId) {
20
+ return [
21
+ (entityId & MAX_U16) >>> 0,
22
+ (((entityId & MASK_UPPER_16_ON_32) >> 16) & MAX_U16) >>> 0
23
+ ];
21
24
  }
22
- function entityId(entityNumber, entityVersion) {
25
+ EntityUtils.fromEntityId = fromEntityId;
26
+ /**
27
+ * @returns compound number from entityNumber and entityVerison
28
+ */
29
+ function toEntityId(entityNumber, entityVersion) {
23
30
  return (((entityNumber & MAX_U16) | ((entityVersion & MAX_U16) << 16)) >>>
24
31
  0);
25
32
  }
33
+ EntityUtils.toEntityId = toEntityId;
34
+ })(EntityUtils || (EntityUtils = {}));
35
+ /**
36
+ * @public
37
+ */
38
+ export var EntityState;
39
+ (function (EntityState) {
40
+ EntityState[EntityState["Unknown"] = 0] = "Unknown";
41
+ /**
42
+ * The entity was generated and added to the usedEntities set
43
+ */
44
+ EntityState[EntityState["UsedEntity"] = 1] = "UsedEntity";
45
+ /**
46
+ * The entity was removed from current engine or remotely
47
+ */
48
+ EntityState[EntityState["Removed"] = 2] = "Removed";
49
+ /**
50
+ * The entity is reserved number.
51
+ */
52
+ EntityState[EntityState["Reserved"] = 3] = "Reserved";
53
+ })(EntityState || (EntityState = {}));
54
+ export function EntityContainer() {
55
+ let entityCounter = RESERVED_STATIC_ENTITIES;
56
+ const usedEntities = new Set();
57
+ let toRemoveEntities = [];
58
+ const removedEntities = createGSet();
26
59
  function generateNewEntity() {
27
60
  if (entityCounter > MAX_ENTITY_NUMBER - 1) {
28
61
  throw new Error(`It fails trying to generate an entity out of range ${MAX_ENTITY_NUMBER}.`);
29
62
  }
30
- const entity = entityCounter++;
63
+ const entityNumber = entityCounter++;
64
+ const entityVersion = removedEntities.getMap().has(entityNumber)
65
+ ? removedEntities.getMap().get(entityNumber) + 1
66
+ : 0;
67
+ const entity = EntityUtils.toEntityId(entityNumber, entityVersion);
31
68
  usedEntities.add(entity);
32
69
  return entity;
33
70
  }
34
71
  function generateEntity() {
72
+ // If all entities until `entityCounter` are being used, we need to generate another one
35
73
  if (usedEntities.size + RESERVED_STATIC_ENTITIES >= entityCounter) {
36
74
  return generateNewEntity();
37
75
  }
38
- for (const [number, version] of removedEntities) {
76
+ for (const [number, version] of removedEntities.getMap()) {
39
77
  if (version < MAX_U16) {
40
- const entity = entityId(number, version + 1);
41
- usedEntities.add(entity);
42
- removedEntities.delete(number);
43
- return entity;
78
+ const entity = EntityUtils.toEntityId(number, version + 1);
79
+ // If the entity is not being used, we can re-use it
80
+ // If the entity was removed in this tick, we're not counting for the usedEntities, but we have it in the toRemoveEntityArray
81
+ if (!usedEntities.has(entity) && !toRemoveEntities.includes(entity)) {
82
+ usedEntities.add(entity);
83
+ return entity;
84
+ }
44
85
  }
45
86
  }
46
87
  return generateNewEntity();
47
88
  }
48
89
  function removeEntity(entity) {
49
- const deleted = usedEntities.delete(entity);
50
- if (deleted) {
51
- removedEntities.set(entityNumber(entity), entityVersion(entity));
90
+ if (entity < RESERVED_STATIC_ENTITIES)
91
+ return false;
92
+ if (usedEntities.has(entity)) {
93
+ usedEntities.delete(entity);
94
+ toRemoveEntities.push(entity);
95
+ }
96
+ else {
97
+ updateRemovedEntity(entity);
52
98
  }
53
- return deleted;
99
+ return true;
100
+ }
101
+ function releaseRemovedEntities() {
102
+ const arr = toRemoveEntities;
103
+ toRemoveEntities = [];
104
+ for (const entity of arr) {
105
+ const [n, v] = EntityUtils.fromEntityId(entity);
106
+ removedEntities.addTo(n, v);
107
+ }
108
+ return arr;
109
+ }
110
+ function updateRemovedEntity(entity) {
111
+ const [n, v] = EntityUtils.fromEntityId(entity);
112
+ // Update the removed entities map
113
+ removedEntities.addTo(n, v);
114
+ // Remove the usedEntities if exist
115
+ for (let i = 0; i <= v; i++) {
116
+ usedEntities.delete(EntityUtils.toEntityId(n, i));
117
+ }
118
+ return true;
119
+ }
120
+ function updateUsedEntity(entity) {
121
+ const [n, v] = EntityUtils.fromEntityId(entity);
122
+ const removedVersion = removedEntities.getMap().get(n);
123
+ if (removedVersion !== undefined && removedVersion >= v) {
124
+ return false;
125
+ }
126
+ // Update
127
+ if (v > 0) {
128
+ for (let i = 0; i <= v - 1; i++) {
129
+ usedEntities.delete(EntityUtils.toEntityId(n, i));
130
+ }
131
+ removedEntities.addTo(n, v - 1);
132
+ }
133
+ usedEntities.add(entity);
134
+ return true;
135
+ }
136
+ function getEntityState(entity) {
137
+ const [n, v] = EntityUtils.fromEntityId(entity);
138
+ if (n < RESERVED_STATIC_ENTITIES) {
139
+ return EntityState.Reserved;
140
+ }
141
+ if (usedEntities.has(entity)) {
142
+ return EntityState.UsedEntity;
143
+ }
144
+ const removedVersion = removedEntities.getMap().get(n);
145
+ if (removedVersion !== undefined && removedVersion >= v) {
146
+ return EntityState.Removed;
147
+ }
148
+ return EntityState.Unknown;
54
149
  }
55
150
  return {
56
- generateEntity() {
57
- return generateEntity();
58
- },
59
- removeEntity(entity) {
60
- return removeEntity(entity);
61
- },
62
- entityExists(entity) {
63
- return entity < RESERVED_STATIC_ENTITIES || usedEntities.has(entity);
64
- },
151
+ generateEntity,
152
+ removeEntity,
65
153
  getExistingEntities() {
66
154
  return new Set(usedEntities);
67
155
  },
68
- entityVersion,
69
- entityNumber,
70
- entityId
156
+ getEntityState,
157
+ releaseRemovedEntities,
158
+ updateRemovedEntity,
159
+ updateUsedEntity
71
160
  };
72
161
  }
@@ -22,9 +22,6 @@ function preEngine() {
22
22
  const entity = entityContainer.generateEntity();
23
23
  return entity;
24
24
  }
25
- function entityExists(entity) {
26
- return entityContainer.entityExists(entity);
27
- }
28
25
  function removeEntity(entity) {
29
26
  for (const [, component] of componentsDefinition) {
30
27
  if (component.has(entity)) {
@@ -131,8 +128,6 @@ function preEngine() {
131
128
  }
132
129
  }
133
130
  return {
134
- entityExists,
135
- componentsDefinition,
136
131
  addEntity,
137
132
  removeEntity,
138
133
  addSystem,
@@ -146,6 +141,7 @@ function preEngine() {
146
141
  removeComponentDefinition,
147
142
  removeEntityWithChildren,
148
143
  registerCustomComponent,
144
+ entityContainer,
149
145
  componentsIter
150
146
  };
151
147
  }
@@ -162,8 +158,9 @@ export function Engine(options) {
162
158
  checkNotThenable(ret, `A system (${system.name || 'anonymous'}) returned a thenable. Systems cannot be async functions. Documentation: https://dcl.gg/sdk/sync-systems`);
163
159
  }
164
160
  const dirtyEntities = crdtSystem.updateState();
165
- await crdtSystem.sendMessages(dirtyEntities);
166
- for (const [_componentId, definition] of engine.componentsDefinition) {
161
+ const deletedEntites = engine.entityContainer.releaseRemovedEntities();
162
+ await crdtSystem.sendMessages(dirtyEntities, deletedEntites);
163
+ for (const definition of engine.componentsIter()) {
167
164
  definition.clearDirty();
168
165
  }
169
166
  }
@@ -185,9 +182,9 @@ export function Engine(options) {
185
182
  RootEntity: 0,
186
183
  PlayerEntity: 1,
187
184
  CameraEntity: 2,
188
- entityExists: engine.entityExists,
185
+ getEntityState: engine.entityContainer.getEntityState,
189
186
  addTransport: crdtSystem.addTransport,
190
187
  getCrdtState: crdtSystem.getCrdt,
191
- componentsDefinition: engine.componentsDefinition
188
+ entityContainer: engine.entityContainer
192
189
  };
193
190
  }
@@ -2,7 +2,7 @@ import type { ISchema } from '../schemas/ISchema';
2
2
  import { MapResult, Spec } from '../schemas/Map';
3
3
  import { Transport } from '../systems/crdt/types';
4
4
  import { ComponentDefinition } from './component';
5
- import { Entity } from './entity';
5
+ import { Entity, EntityContainer, EntityState } from './entity';
6
6
  import { ReadonlyComponentSchema } from './readonly';
7
7
  import { SystemFn } from './systems';
8
8
  export { ISchema } from '../schemas/ISchema';
@@ -53,11 +53,11 @@ export declare type IEngine = {
53
53
  */
54
54
  removeEntityWithChildren(firstEntity: Entity): void;
55
55
  /**
56
- * Check if an entity exists in the engine
56
+ * Check the state of an entityin the engine
57
57
  * @param entity - the entity to validate
58
- * @returns true if the entity exists in the engine
58
+ * @returns known enum value
59
59
  */
60
- entityExists(entity: Entity): boolean;
60
+ getEntityState(entity: Entity): EntityState;
61
61
  /**
62
62
  * Add the system to the engine. It will be called every tick updated.
63
63
  * @param system - function that receives the delta time between last tick and current one.
@@ -173,6 +173,10 @@ export declare type IEngine = {
173
173
  * @param transport - transport which changes its onmessage to process CRDT messages
174
174
  */
175
175
  addTransport(transport: Transport): void;
176
+ /**
177
+ * Entity continaer
178
+ */
179
+ entityContainer: EntityContainer;
176
180
  /**
177
181
  * Iterator of registered components
178
182
  */
package/dist/index.d.ts CHANGED
@@ -14,3 +14,4 @@ export declare const MeshRenderer: import("./components/types").MeshRendererComp
14
14
  export declare const MeshCollider: import("./components/types").MeshColliderComponentDefinitionExtended;
15
15
  export * from './components/generated/global.gen';
16
16
  export * from './components/generated/types.gen';
17
+ export * from './serialization/crdt';
package/dist/index.js CHANGED
@@ -22,3 +22,4 @@ import { engine } from './runtime/initialization';
22
22
  // export components for global engine
23
23
  export * from './components/generated/global.gen';
24
24
  export * from './components/generated/types.gen';
25
+ export * from './serialization/crdt';
@@ -1,6 +1,5 @@
1
1
  export type { SystemFn } from '../engine/systems';
2
2
  export type { TransportMessage, ReceiveMessage, Transport } from '../systems/crdt/types';
3
- export type { WireMessage } from '../serialization/wireMessage';
4
3
  export { TransformType, TransformComponent } from '../components/legacy/Transform';
5
4
  export * from '../engine/component';
6
5
  export * from '../schemas/typing';
@@ -0,0 +1,11 @@
1
+ import { Entity } from '../../engine/entity';
2
+ import { ByteBuffer } from '../ByteBuffer';
3
+ import { DeleteComponentMessage } from './types';
4
+ export declare namespace DeleteComponent {
5
+ const MESSAGE_HEADER_LENGTH = 20;
6
+ /**
7
+ * Write DeleteComponent message
8
+ */
9
+ function write(entity: Entity, componentId: number, timestamp: number, buf: ByteBuffer): void;
10
+ function read(buf: ByteBuffer): DeleteComponentMessage | null;
11
+ }
@@ -0,0 +1,45 @@
1
+ import CrdtMessageProtocol from '.';
2
+ import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
3
+ export var DeleteComponent;
4
+ (function (DeleteComponent) {
5
+ // TODO: change timestamp to 32 bit and remove buffer length (-8 bytes)
6
+ DeleteComponent.MESSAGE_HEADER_LENGTH = 20;
7
+ /**
8
+ * Write DeleteComponent message
9
+ */
10
+ function write(entity, componentId, timestamp, buf) {
11
+ // reserve the beginning
12
+ const messageLength = CRDT_MESSAGE_HEADER_LENGTH + DeleteComponent.MESSAGE_HEADER_LENGTH;
13
+ const startMessageOffset = buf.incrementWriteOffset(messageLength);
14
+ // Write CrdtMessage header
15
+ buf.setUint32(startMessageOffset, messageLength);
16
+ buf.setUint32(startMessageOffset + 4, CrdtMessageType.DELETE_COMPONENT);
17
+ // Write ComponentOperation header
18
+ buf.setUint32(startMessageOffset + 8, entity);
19
+ buf.setUint32(startMessageOffset + 12, componentId);
20
+ // TODO: change timestamp to 32bit (-4 bytes)
21
+ buf.setUint64(startMessageOffset + 16, BigInt(timestamp));
22
+ // TODO: remove buffer length (-4 bytes)
23
+ buf.setUint32(startMessageOffset + 24, 0);
24
+ }
25
+ DeleteComponent.write = write;
26
+ function read(buf) {
27
+ const header = CrdtMessageProtocol.readHeader(buf);
28
+ if (!header) {
29
+ return null;
30
+ }
31
+ if (header.type !== CrdtMessageType.DELETE_COMPONENT) {
32
+ throw new Error('DeleteComponentOperation tried to read another message type.');
33
+ }
34
+ const msg = {
35
+ ...header,
36
+ entityId: buf.readUint32(),
37
+ componentId: buf.readInt32(),
38
+ timestamp: Number(buf.readUint64())
39
+ };
40
+ // TODO: remove buffer length
41
+ buf.incrementReadOffset(4);
42
+ return msg;
43
+ }
44
+ DeleteComponent.read = read;
45
+ })(DeleteComponent || (DeleteComponent = {}));
@@ -0,0 +1,8 @@
1
+ import { Entity } from '../../engine/entity';
2
+ import { ByteBuffer } from '../ByteBuffer';
3
+ import { DeleteEntityMessage } from './types';
4
+ export declare namespace DeleteEntity {
5
+ const MESSAGE_HEADER_LENGTH = 4;
6
+ function write(entity: Entity, buf: ByteBuffer): void;
7
+ function read(buf: ByteBuffer): DeleteEntityMessage | null;
8
+ }
@@ -0,0 +1,28 @@
1
+ import CrdtMessageProtocol from '.';
2
+ import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
3
+ export var DeleteEntity;
4
+ (function (DeleteEntity) {
5
+ DeleteEntity.MESSAGE_HEADER_LENGTH = 4;
6
+ function write(entity, buf) {
7
+ // Write CrdtMessage header
8
+ buf.writeUint32(CRDT_MESSAGE_HEADER_LENGTH + 4);
9
+ buf.writeUint32(CrdtMessageType.DELETE_ENTITY);
10
+ // body
11
+ buf.writeUint32(entity);
12
+ }
13
+ DeleteEntity.write = write;
14
+ function read(buf) {
15
+ const header = CrdtMessageProtocol.readHeader(buf);
16
+ if (!header) {
17
+ return null;
18
+ }
19
+ if (header.type !== CrdtMessageType.DELETE_ENTITY) {
20
+ throw new Error('DeleteComponentOperation tried to read another message type.');
21
+ }
22
+ return {
23
+ ...header,
24
+ entityId: buf.readUint32()
25
+ };
26
+ }
27
+ DeleteEntity.read = read;
28
+ })(DeleteEntity || (DeleteEntity = {}));
@@ -0,0 +1,32 @@
1
+ import { ByteBuffer } from '../ByteBuffer';
2
+ import { CrdtMessageHeader } from './types';
3
+ export * from './types';
4
+ export * from './deleteComponent';
5
+ export * from './putComponent';
6
+ export * from './deleteEntity';
7
+ export declare namespace CrdtMessageProtocol {
8
+ /**
9
+ * Validate if the message incoming is completed
10
+ * @param buf - ByteBuffer
11
+ */
12
+ function validate(buf: ByteBuffer): boolean;
13
+ /**
14
+ * Get the current header, consuming the bytes involved.
15
+ * @param buf - ByteBuffer
16
+ * @returns header or null if there is no validated message
17
+ */
18
+ function readHeader(buf: ByteBuffer): CrdtMessageHeader | null;
19
+ /**
20
+ * Get the current header, without consuming the bytes involved.
21
+ * @param buf - ByteBuffer
22
+ * @returns header or null if there is no validated message
23
+ */
24
+ function getHeader(buf: ByteBuffer): CrdtMessageHeader | null;
25
+ /**
26
+ * Consume the incoming message without processing it.
27
+ * @param buf - ByteBuffer
28
+ * @returns true in case of success or false if there is no valid message.
29
+ */
30
+ function consumeMessage(buf: ByteBuffer): boolean;
31
+ }
32
+ export default CrdtMessageProtocol;
@@ -0,0 +1,70 @@
1
+ import { CRDT_MESSAGE_HEADER_LENGTH } from './types';
2
+ export * from './types';
3
+ export * from './deleteComponent';
4
+ export * from './putComponent';
5
+ export * from './deleteEntity';
6
+ export var CrdtMessageProtocol;
7
+ (function (CrdtMessageProtocol) {
8
+ /**
9
+ * Validate if the message incoming is completed
10
+ * @param buf - ByteBuffer
11
+ */
12
+ function validate(buf) {
13
+ const rem = buf.remainingBytes();
14
+ if (rem < CRDT_MESSAGE_HEADER_LENGTH) {
15
+ return false;
16
+ }
17
+ const messageLength = buf.getUint32(buf.currentReadOffset());
18
+ if (rem < messageLength) {
19
+ return false;
20
+ }
21
+ return true;
22
+ }
23
+ CrdtMessageProtocol.validate = validate;
24
+ /**
25
+ * Get the current header, consuming the bytes involved.
26
+ * @param buf - ByteBuffer
27
+ * @returns header or null if there is no validated message
28
+ */
29
+ function readHeader(buf) {
30
+ if (!validate(buf)) {
31
+ return null;
32
+ }
33
+ return {
34
+ length: buf.readUint32(),
35
+ type: buf.readUint32()
36
+ };
37
+ }
38
+ CrdtMessageProtocol.readHeader = readHeader;
39
+ /**
40
+ * Get the current header, without consuming the bytes involved.
41
+ * @param buf - ByteBuffer
42
+ * @returns header or null if there is no validated message
43
+ */
44
+ function getHeader(buf) {
45
+ if (!validate(buf)) {
46
+ return null;
47
+ }
48
+ const currentOffset = buf.currentReadOffset();
49
+ return {
50
+ length: buf.getUint32(currentOffset),
51
+ type: buf.getUint32(currentOffset + 4)
52
+ };
53
+ }
54
+ CrdtMessageProtocol.getHeader = getHeader;
55
+ /**
56
+ * Consume the incoming message without processing it.
57
+ * @param buf - ByteBuffer
58
+ * @returns true in case of success or false if there is no valid message.
59
+ */
60
+ function consumeMessage(buf) {
61
+ const header = getHeader(buf);
62
+ if (!header) {
63
+ return false;
64
+ }
65
+ buf.incrementReadOffset(header.length);
66
+ return true;
67
+ }
68
+ CrdtMessageProtocol.consumeMessage = consumeMessage;
69
+ })(CrdtMessageProtocol || (CrdtMessageProtocol = {}));
70
+ export default CrdtMessageProtocol;
@@ -0,0 +1,3 @@
1
+ import { ByteBuffer } from '../ByteBuffer';
2
+ import { CrdtMessage } from './types';
3
+ export declare function readMessage(buf: ByteBuffer): CrdtMessage | null;
@@ -0,0 +1,17 @@
1
+ import CrdtMessageProtocol, { DeleteComponent, DeleteEntity, PutComponentOperation } from '.';
2
+ import { CrdtMessageType } from './types';
3
+ export function readMessage(buf) {
4
+ const header = CrdtMessageProtocol.getHeader(buf);
5
+ if (!header)
6
+ return null;
7
+ if (header.type === CrdtMessageType.PUT_COMPONENT) {
8
+ return PutComponentOperation.read(buf);
9
+ }
10
+ else if (header.type === CrdtMessageType.DELETE_COMPONENT) {
11
+ return DeleteComponent.read(buf);
12
+ }
13
+ else if (header.type === CrdtMessageType.DELETE_ENTITY) {
14
+ return DeleteEntity.read(buf);
15
+ }
16
+ return null;
17
+ }
@@ -0,0 +1,13 @@
1
+ import { ComponentDefinition } from '../../engine/component';
2
+ import { Entity } from '../../engine/entity';
3
+ import { ByteBuffer } from '../ByteBuffer';
4
+ import { PutComponentMessage } from './types';
5
+ export declare namespace PutComponentOperation {
6
+ const MESSAGE_HEADER_LENGTH = 20;
7
+ /**
8
+ * Call this function for an optimal writing data passing the ByteBuffer
9
+ * already allocated
10
+ */
11
+ function write(entity: Entity, timestamp: number, componentDefinition: ComponentDefinition<unknown>, buf: ByteBuffer): void;
12
+ function read(buf: ByteBuffer): PutComponentMessage | null;
13
+ }
@@ -0,0 +1,44 @@
1
+ import CrdtMessageProtocol from '.';
2
+ import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
3
+ export var PutComponentOperation;
4
+ (function (PutComponentOperation) {
5
+ PutComponentOperation.MESSAGE_HEADER_LENGTH = 20;
6
+ /**
7
+ * Call this function for an optimal writing data passing the ByteBuffer
8
+ * already allocated
9
+ */
10
+ function write(entity, timestamp, componentDefinition, buf) {
11
+ // reserve the beginning
12
+ const startMessageOffset = buf.incrementWriteOffset(CRDT_MESSAGE_HEADER_LENGTH + PutComponentOperation.MESSAGE_HEADER_LENGTH);
13
+ // write body
14
+ componentDefinition.writeToByteBuffer(entity, buf);
15
+ const messageLength = buf.size() - startMessageOffset;
16
+ // Write CrdtMessage header
17
+ buf.setUint32(startMessageOffset, messageLength);
18
+ buf.setUint32(startMessageOffset + 4, CrdtMessageType.PUT_COMPONENT);
19
+ // Write ComponentOperation header
20
+ buf.setUint32(startMessageOffset + 8, entity);
21
+ buf.setUint32(startMessageOffset + 12, componentDefinition._id);
22
+ buf.setUint64(startMessageOffset + 16, BigInt(timestamp));
23
+ const newLocal = messageLength - PutComponentOperation.MESSAGE_HEADER_LENGTH - CRDT_MESSAGE_HEADER_LENGTH;
24
+ buf.setUint32(startMessageOffset + 24, newLocal);
25
+ }
26
+ PutComponentOperation.write = write;
27
+ function read(buf) {
28
+ const header = CrdtMessageProtocol.readHeader(buf);
29
+ if (!header) {
30
+ return null;
31
+ }
32
+ if (header.type !== CrdtMessageType.PUT_COMPONENT) {
33
+ throw new Error('PutComponentOperation tried to read another message type.');
34
+ }
35
+ return {
36
+ ...header,
37
+ entityId: buf.readUint32(),
38
+ componentId: buf.readInt32(),
39
+ timestamp: Number(buf.readUint64()),
40
+ data: buf.readBuffer()
41
+ };
42
+ }
43
+ PutComponentOperation.read = read;
44
+ })(PutComponentOperation || (PutComponentOperation = {}));