@dcl/ecs 7.0.6-3824930139.commit-9bd6c05 → 7.0.6-3832097301.commit-4e46b20

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.
@@ -1,4 +1,4 @@
1
- import { createByteBuffer } from '../serialization/ByteBuffer';
1
+ import { ReadWriteByteBuffer } from '../serialization/ByteBuffer';
2
2
  import { deepReadonly } from './readonly';
3
3
  export function defineComponent(componentId, spec
4
4
  // meta: { syncFlags }
@@ -92,7 +92,7 @@ export function defineComponent(componentId, spec
92
92
  if (!component) {
93
93
  throw new Error(`[toBinary] Component ${componentId} for ${entity} not found`);
94
94
  }
95
- const writeBuffer = createByteBuffer();
95
+ const writeBuffer = new ReadWriteByteBuffer();
96
96
  spec.serialize(component, writeBuffer);
97
97
  return writeBuffer;
98
98
  },
@@ -101,7 +101,7 @@ export function defineComponent(componentId, spec
101
101
  if (!component) {
102
102
  return null;
103
103
  }
104
- const writeBuffer = createByteBuffer();
104
+ const writeBuffer = new ReadWriteByteBuffer();
105
105
  spec.serialize(component, writeBuffer);
106
106
  return writeBuffer;
107
107
  },
@@ -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';
@@ -1,29 +1,3 @@
1
- /**
2
- * @param writing - writing option, see object specs.
3
- * @param reading - reading option, see object specs.
4
- * @param initialCapacity - Initial capacity of buffer to allocate, ignored if you use writing or reading options
5
- */
6
- export interface CreateByteBufferOptions {
7
- /**
8
- * @param buffer - a buffer already allocated to read from there.
9
- * @param currentOffset - set the cursor where begins to read. Default 0
10
- * @param length - delimite where the valid data ends. Default: buffer.length
11
- */
12
- reading?: {
13
- buffer: Uint8Array;
14
- length?: number;
15
- currentOffset: number;
16
- };
17
- /**
18
- * @param buffer - a buffer already allocated to write there.
19
- * @param currentOffset - set the cursor to not start writing from the begin of it. Default 0
20
- */
21
- writing?: {
22
- buffer: Uint8Array;
23
- currentOffset?: number;
24
- };
25
- initialCapacity?: number;
26
- }
27
1
  /**
28
2
  * ByteBuffer is a wrapper of DataView which also adds a read and write offset.
29
3
  * Also in a write operation it resizes the buffer is being used if it needs.
@@ -31,7 +5,73 @@ export interface CreateByteBufferOptions {
31
5
  * - Use read and write function to generate or consume data.
32
6
  * - Use set and get only if you are sure that you're doing.
33
7
  */
34
- export declare function createByteBuffer(options?: CreateByteBufferOptions): ByteBuffer;
8
+ export declare class ReadWriteByteBuffer implements ByteBuffer {
9
+ #private;
10
+ _buffer: Uint8Array;
11
+ view: DataView;
12
+ woffset: number;
13
+ roffset: number;
14
+ /**
15
+ * @param buffer - The initial buffer, provide a buffer if you need to set "initial capacity"
16
+ * @param readingOffset - Set the cursor where begins to read. Default 0
17
+ * @param writingOffset - Set the cursor to not start writing from the begin of it. Defaults to the buffer size
18
+ */
19
+ constructor(buffer?: Uint8Array | undefined, readingOffset?: number | undefined, writingOffset?: number | undefined);
20
+ buffer(): Uint8Array;
21
+ bufferLength(): number;
22
+ resetBuffer(): void;
23
+ currentReadOffset(): number;
24
+ currentWriteOffset(): number;
25
+ incrementReadOffset(amount: number): number;
26
+ remainingBytes(): number;
27
+ readFloat32(): number;
28
+ readFloat64(): number;
29
+ readInt8(): number;
30
+ readInt16(): number;
31
+ readInt32(): number;
32
+ readInt64(): bigint;
33
+ readUint8(): number;
34
+ readUint16(): number;
35
+ readUint32(): number;
36
+ readUint64(): bigint;
37
+ readBuffer(): Uint8Array;
38
+ readUtf8String(): string;
39
+ incrementWriteOffset(amount: number): number;
40
+ toBinary(): Uint8Array;
41
+ toCopiedBinary(): Uint8Array;
42
+ writeBuffer(value: Uint8Array, writeLength?: boolean): void;
43
+ writeUtf8String(value: string, writeLength?: boolean): void;
44
+ writeFloat32(value: number): void;
45
+ writeFloat64(value: number): void;
46
+ writeInt8(value: number): void;
47
+ writeInt16(value: number): void;
48
+ writeInt32(value: number): void;
49
+ writeInt64(value: bigint): void;
50
+ writeUint8(value: number): void;
51
+ writeUint16(value: number): void;
52
+ writeUint32(value: number): void;
53
+ writeUint64(value: bigint): void;
54
+ getFloat32(offset: number): number;
55
+ getFloat64(offset: number): number;
56
+ getInt8(offset: number): number;
57
+ getInt16(offset: number): number;
58
+ getInt32(offset: number): number;
59
+ getInt64(offset: number): bigint;
60
+ getUint8(offset: number): number;
61
+ getUint16(offset: number): number;
62
+ getUint32(offset: number): number;
63
+ getUint64(offset: number): bigint;
64
+ setFloat32(offset: number, value: number): void;
65
+ setFloat64(offset: number, value: number): void;
66
+ setInt8(offset: number, value: number): void;
67
+ setInt16(offset: number, value: number): void;
68
+ setInt32(offset: number, value: number): void;
69
+ setInt64(offset: number, value: bigint): void;
70
+ setUint8(offset: number, value: number): void;
71
+ setUint16(offset: number, value: number): void;
72
+ setUint32(offset: number, value: number): void;
73
+ setUint64(offset: number, value: bigint): void;
74
+ }
35
75
  /**
36
76
  * @public
37
77
  */
@@ -89,10 +129,6 @@ export declare type ByteBuffer = {
89
129
  * @returns The offset when this reserving starts.
90
130
  */
91
131
  incrementWriteOffset(amount: number): number;
92
- /**
93
- * @returns The total number of bytes writen in the buffer.
94
- */
95
- size(): number;
96
132
  /**
97
133
  * Take care using this function, if you modify the data after, the
98
134
  * returned subarray will change too. If you'll modify the content of the