@dcl/ecs 7.0.6-3808988484.commit-63d3e2c → 7.0.6-3823801200.commit-32470bd

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,5 @@
1
1
  import { ByteBuffer } from '../serialization/ByteBuffer';
2
+ import { OnChangeFunction } from '../systems/crdt';
2
3
  import { ComponentDefinition } from './component';
3
4
  import { Entity } from './entity';
4
5
  import { SystemItem } from './systems';
@@ -6,8 +7,14 @@ import type { IEngine } from './types';
6
7
  export * from './input';
7
8
  export * from './readonly';
8
9
  export * from './types';
9
- export { Entity, ByteBuffer, ComponentDefinition, SystemItem };
10
+ export { Entity, ByteBuffer, ComponentDefinition, SystemItem, OnChangeFunction };
10
11
  /**
11
12
  * @public
12
13
  */
13
- export declare function Engine(): IEngine;
14
+ export declare type IEngineOptions = {
15
+ onChangeFunction: OnChangeFunction;
16
+ };
17
+ /**
18
+ * @public
19
+ */
20
+ export declare function Engine(options?: IEngineOptions): IEngine;
@@ -106,6 +106,9 @@ function preEngine() {
106
106
  function getSystems() {
107
107
  return systems.getSystems();
108
108
  }
109
+ function componentsIter() {
110
+ return componentsDefinition.values();
111
+ }
109
112
  function removeComponentDefinition(componentId) {
110
113
  componentsDefinition.delete(componentId);
111
114
  }
@@ -142,15 +145,16 @@ function preEngine() {
142
145
  getComponentOrNull,
143
146
  removeComponentDefinition,
144
147
  removeEntityWithChildren,
145
- registerCustomComponent
148
+ registerCustomComponent,
149
+ componentsIter
146
150
  };
147
151
  }
148
152
  /**
149
153
  * @public
150
154
  */
151
- export function Engine() {
155
+ export function Engine(options) {
152
156
  const engine = preEngine();
153
- const crdtSystem = crdtSceneSystem(engine);
157
+ const crdtSystem = crdtSceneSystem(engine, options?.onChangeFunction || null);
154
158
  async function update(dt) {
155
159
  await crdtSystem.receiveMessages();
156
160
  for (const system of engine.getSystems()) {
@@ -176,6 +180,7 @@ export function Engine() {
176
180
  getComponent: engine.getComponent,
177
181
  getComponentOrNull: engine.getComponentOrNull,
178
182
  removeComponentDefinition: engine.removeComponentDefinition,
183
+ componentsIter: engine.componentsIter,
179
184
  update,
180
185
  RootEntity: 0,
181
186
  PlayerEntity: 1,
@@ -173,4 +173,8 @@ 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
+ * Iterator of registered components
178
+ */
179
+ componentsIter(): Iterable<ComponentDefinition<unknown>>;
176
180
  };
@@ -1,10 +1,15 @@
1
- import type { IEngine } from '../../engine';
1
+ import type { ComponentDefinition, IEngine } from '../../engine';
2
2
  import { Entity } from '../../engine/entity';
3
+ import WireMessage from '../../serialization/wireMessage';
3
4
  import { Transport } from './types';
4
- export declare function crdtSceneSystem(engine: Pick<IEngine, 'getComponentOrNull' | 'getComponent' | 'componentsDefinition'>): {
5
+ /**
6
+ * @public
7
+ */
8
+ export declare type OnChangeFunction = (entity: Entity, component: ComponentDefinition<any>, operation: WireMessage.Enum) => void;
9
+ export declare function crdtSceneSystem(engine: Pick<IEngine, 'getComponentOrNull' | 'getComponent' | 'componentsIter'>, onProcessEntityComponentChange: OnChangeFunction | null): {
5
10
  getCrdt: () => import("@dcl/crdt").State<Uint8Array>;
6
- sendMessages: (dirtyEntities: Map<Entity, Set<number>>) => Promise<void>;
11
+ sendMessages: (dirtyEntities: Map<ComponentDefinition<unknown>, Array<Entity>>) => Promise<void>;
7
12
  receiveMessages: () => Promise<void>;
8
13
  addTransport: (transport: Transport) => void;
9
- updateState: () => Map<Entity, Set<number>>;
14
+ updateState: () => Map<ComponentDefinition<unknown>, Entity[]>;
10
15
  };
@@ -2,7 +2,7 @@ import { crdtProtocol } from '@dcl/crdt';
2
2
  import { createByteBuffer } from '../../serialization/ByteBuffer';
3
3
  import { ComponentOperation as Message } from '../../serialization/crdt/componentOperation';
4
4
  import WireMessage from '../../serialization/wireMessage';
5
- export function crdtSceneSystem(engine) {
5
+ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
6
6
  const transports = [];
7
7
  // CRDT Client
8
8
  const crdtClient = crdtProtocol();
@@ -106,34 +106,38 @@ export function crdtSceneSystem(engine) {
106
106
  const data = createByteBuffer(opts);
107
107
  component.upsertFromBinary(message.entity, data, false);
108
108
  }
109
+ onProcessEntityComponentChange &&
110
+ onProcessEntityComponentChange(entity, component, type);
109
111
  }
110
112
  }
111
113
  }
112
- function getDirtyMap() {
113
- const dirtySet = new Map();
114
- for (const [componentId, definition] of engine.componentsDefinition) {
115
- for (const entity of definition.dirtyIterator()) {
116
- if (!dirtySet.has(entity)) {
117
- dirtySet.set(entity, new Set());
118
- }
119
- dirtySet.get(entity).add(componentId);
120
- }
121
- }
122
- return dirtySet;
123
- }
124
114
  /**
125
115
  * Updates CRDT state of the current engine dirty components
116
+ *
117
+ * TODO: optimize this function allocations using a bitmap
118
+ * TODO: unify this function with sendMessages
126
119
  */
127
120
  function updateState() {
128
- const dirtyEntities = getDirtyMap();
129
- for (const [entity, componentsId] of getDirtyMap()) {
130
- for (const componentId of componentsId) {
131
- const component = engine.getComponent(componentId);
121
+ const dirtyMap = new Map();
122
+ for (const component of engine.componentsIter()) {
123
+ let entitySet = null;
124
+ for (const entity of component.dirtyIterator()) {
125
+ if (!entitySet) {
126
+ entitySet = [];
127
+ dirtyMap.set(component, entitySet);
128
+ }
129
+ entitySet.push(entity);
130
+ // TODO: reuse shared writer to prevent extra allocations of toBinary
132
131
  const componentValue = component.toBinaryOrNull(entity)?.toBinary() ?? null;
133
- crdtClient.createEvent(entity, componentId, componentValue);
132
+ // TODO: do not emit event if componentValue equals the value didn't change
133
+ crdtClient.createEvent(entity, component._id, componentValue);
134
+ onProcessEntityComponentChange &&
135
+ onProcessEntityComponentChange(entity, component, componentValue === null
136
+ ? WireMessage.Enum.DELETE_COMPONENT
137
+ : WireMessage.Enum.PUT_COMPONENT);
134
138
  }
135
139
  }
136
- return dirtyEntities;
140
+ return dirtyMap;
137
141
  }
138
142
  /**
139
143
  * Iterates the dirty map and generates crdt messages to be send
@@ -143,19 +147,18 @@ export function crdtSceneSystem(engine) {
143
147
  const crdtMessages = getMessages(broadcastMessages);
144
148
  const outdatedMessagesBkp = getMessages(outdatedMessages);
145
149
  const buffer = createByteBuffer();
146
- for (const [entity, componentsId] of dirtyEntities) {
147
- for (const componentId of componentsId) {
150
+ for (const [component, entities] of dirtyEntities) {
151
+ for (const entity of entities) {
148
152
  // Component will be always defined here since dirtyMap its an iterator of engine.componentsDefinition
149
- const component = engine.getComponent(componentId);
150
153
  const { timestamp } = crdtClient
151
154
  .getState()
152
155
  .get(entity)
153
- .get(componentId);
156
+ .get(component._id);
154
157
  const offset = buffer.currentWriteOffset();
155
158
  const type = WireMessage.getType(component, entity);
156
159
  const transportMessage = {
157
160
  type,
158
- componentId,
161
+ componentId: component._id,
159
162
  entity,
160
163
  timestamp
161
164
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl/ecs",
3
- "version": "7.0.6-3808988484.commit-63d3e2c",
3
+ "version": "7.0.6-3823801200.commit-32470bd",
4
4
  "description": "Decentraland ECS",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "ts-proto": "^1.112.0"
28
28
  },
29
29
  "dependencies": {
30
- "@dcl/crdt": "7.0.6-3808988484.commit-63d3e2c",
30
+ "@dcl/crdt": "7.0.6-3823801200.commit-32470bd",
31
31
  "@dcl/js-runtime": "file:../js-runtime",
32
32
  "@dcl/protocol": "^1.0.0-3808528053.commit-d66d462"
33
33
  },
@@ -41,5 +41,5 @@
41
41
  "displayName": "ECS",
42
42
  "tsconfig": "./tsconfig.json"
43
43
  },
44
- "commit": "63d3e2c15a5a2d09285eca1b08d3832a12f75f13"
44
+ "commit": "32470bdb44a9d3c8663f432e0d3262a09c4201cf"
45
45
  }