@dcl/ecs 7.3.31 → 7.3.32

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 (59) hide show
  1. package/dist/components/index.d.ts +10 -0
  2. package/dist/components/index.js +12 -0
  3. package/dist/components/manual/NetworkEntity.d.ts +12 -0
  4. package/dist/components/manual/NetworkEntity.js +9 -0
  5. package/dist/components/manual/NetworkParent.d.ts +12 -0
  6. package/dist/components/manual/NetworkParent.js +9 -0
  7. package/dist/components/types.d.ts +2 -0
  8. package/dist/engine/index.js +8 -21
  9. package/dist/engine/lww-element-set-component-definition.js +5 -2
  10. package/dist/engine/types.d.ts +0 -12
  11. package/dist/index.d.ts +11 -1
  12. package/dist/index.js +10 -0
  13. package/dist/runtime/helpers/tree.d.ts +1 -1
  14. package/dist/runtime/helpers/tree.js +25 -2
  15. package/dist/serialization/crdt/index.d.ts +3 -0
  16. package/dist/serialization/crdt/index.js +3 -0
  17. package/dist/serialization/crdt/message.js +12 -0
  18. package/dist/serialization/crdt/network/deleteComponentNetwork.d.ts +14 -0
  19. package/dist/serialization/crdt/network/deleteComponentNetwork.js +43 -0
  20. package/dist/serialization/crdt/network/deleteEntityNetwork.d.ts +11 -0
  21. package/dist/serialization/crdt/network/deleteEntityNetwork.js +33 -0
  22. package/dist/serialization/crdt/network/putComponentNetwork.d.ts +15 -0
  23. package/dist/serialization/crdt/network/putComponentNetwork.js +49 -0
  24. package/dist/serialization/crdt/network/utils.d.ts +9 -0
  25. package/dist/serialization/crdt/network/utils.js +62 -0
  26. package/dist/serialization/crdt/types.d.ts +48 -3
  27. package/dist/serialization/crdt/types.js +5 -1
  28. package/dist/systems/crdt/index.js +111 -69
  29. package/dist/systems/crdt/types.d.ts +9 -1
  30. package/dist-cjs/components/index.d.ts +10 -0
  31. package/dist-cjs/components/index.js +15 -1
  32. package/dist-cjs/components/manual/NetworkEntity.d.ts +12 -0
  33. package/dist-cjs/components/manual/NetworkEntity.js +11 -0
  34. package/dist-cjs/components/manual/NetworkParent.d.ts +12 -0
  35. package/dist-cjs/components/manual/NetworkParent.js +11 -0
  36. package/dist-cjs/components/types.d.ts +2 -0
  37. package/dist-cjs/engine/index.js +8 -21
  38. package/dist-cjs/engine/lww-element-set-component-definition.js +5 -2
  39. package/dist-cjs/engine/types.d.ts +0 -12
  40. package/dist-cjs/index.d.ts +11 -1
  41. package/dist-cjs/index.js +11 -1
  42. package/dist-cjs/runtime/helpers/tree.d.ts +1 -1
  43. package/dist-cjs/runtime/helpers/tree.js +25 -2
  44. package/dist-cjs/serialization/crdt/index.d.ts +3 -0
  45. package/dist-cjs/serialization/crdt/index.js +3 -0
  46. package/dist-cjs/serialization/crdt/message.js +12 -0
  47. package/dist-cjs/serialization/crdt/network/deleteComponentNetwork.d.ts +14 -0
  48. package/dist-cjs/serialization/crdt/network/deleteComponentNetwork.js +46 -0
  49. package/dist-cjs/serialization/crdt/network/deleteEntityNetwork.d.ts +11 -0
  50. package/dist-cjs/serialization/crdt/network/deleteEntityNetwork.js +36 -0
  51. package/dist-cjs/serialization/crdt/network/putComponentNetwork.d.ts +15 -0
  52. package/dist-cjs/serialization/crdt/network/putComponentNetwork.js +52 -0
  53. package/dist-cjs/serialization/crdt/network/utils.d.ts +9 -0
  54. package/dist-cjs/serialization/crdt/network/utils.js +69 -0
  55. package/dist-cjs/serialization/crdt/types.d.ts +48 -3
  56. package/dist-cjs/serialization/crdt/types.js +5 -1
  57. package/dist-cjs/systems/crdt/index.js +133 -68
  58. package/dist-cjs/systems/crdt/types.d.ts +9 -1
  59. package/package.json +2 -2
@@ -8,7 +8,10 @@ export declare enum CrdtMessageType {
8
8
  DELETE_COMPONENT = 2,
9
9
  DELETE_ENTITY = 3,
10
10
  APPEND_VALUE = 4,
11
- MAX_MESSAGE_TYPE = 5
11
+ PUT_COMPONENT_NETWORK = 5,
12
+ DELETE_COMPONENT_NETWORK = 6,
13
+ DELETE_ENTITY_NETWORK = 7,
14
+ MAX_MESSAGE_TYPE = 8
12
15
  }
13
16
  /**
14
17
  * Min length = 8 bytes
@@ -41,6 +44,10 @@ export type PutComponentMessageBody = {
41
44
  timestamp: number;
42
45
  data: Uint8Array;
43
46
  };
47
+ export type PutNetworkComponentMessageBody = Omit<PutComponentMessageBody, 'type'> & {
48
+ type: CrdtMessageType.PUT_COMPONENT_NETWORK;
49
+ networkId: number;
50
+ };
44
51
  /**
45
52
  * Min. length = header (8 bytes) + 16 bytes = 24 bytes
46
53
  *
@@ -69,6 +76,20 @@ export type DeleteComponentMessageBody = {
69
76
  componentId: number;
70
77
  timestamp: number;
71
78
  };
79
+ /**
80
+ * @param entity - Uint32 number of the entity
81
+ * @param componentId - Uint32 number of id
82
+ * @param timestamp - Uint32 Lamport timestamp
83
+ * @param networkId - Uint32 user network id
84
+ * @public
85
+ */
86
+ export type DeleteComponentNetworkMessageBody = {
87
+ type: CrdtMessageType.DELETE_COMPONENT_NETWORK;
88
+ entityId: Entity;
89
+ componentId: number;
90
+ timestamp: number;
91
+ networkId: number;
92
+ };
72
93
  /**
73
94
  * @param entity - uint32 number of the entity
74
95
  * @public
@@ -77,6 +98,14 @@ export type DeleteEntityMessageBody = {
77
98
  type: CrdtMessageType.DELETE_ENTITY;
78
99
  entityId: Entity;
79
100
  };
101
+ /**
102
+ * @public
103
+ */
104
+ export type DeleteEntityNetworkMessageBody = {
105
+ type: CrdtMessageType.DELETE_ENTITY_NETWORK;
106
+ entityId: Entity;
107
+ networkId: number;
108
+ };
80
109
  /**
81
110
  * @public
82
111
  */
@@ -85,10 +114,18 @@ export type AppendValueMessage = CrdtMessageHeader & AppendValueMessageBody;
85
114
  * @public
86
115
  */
87
116
  export type PutComponentMessage = CrdtMessageHeader & PutComponentMessageBody;
117
+ /**
118
+ * @public
119
+ */
120
+ export type PutNetworkComponentMessage = CrdtMessageHeader & PutNetworkComponentMessageBody;
88
121
  /**
89
122
  * @public
90
123
  */
91
124
  export type DeleteComponentMessage = CrdtMessageHeader & DeleteComponentMessageBody;
125
+ /**
126
+ * @public
127
+ */
128
+ export type DeleteComponentNetworkMessage = CrdtMessageHeader & DeleteComponentNetworkMessageBody;
92
129
  /**
93
130
  * @public
94
131
  */
@@ -96,11 +133,19 @@ export type DeleteEntityMessage = CrdtMessageHeader & DeleteEntityMessageBody;
96
133
  /**
97
134
  * @public
98
135
  */
99
- export type CrdtMessage = PutComponentMessage | DeleteComponentMessage | DeleteEntityMessage | AppendValueMessage;
136
+ export type DeleteEntityNetworkMessage = CrdtMessageHeader & DeleteEntityNetworkMessageBody;
137
+ /**
138
+ * @public
139
+ */
140
+ export type CrdtMessage = PutComponentMessage | DeleteComponentMessage | AppendValueMessage | DeleteEntityMessage | PutNetworkComponentMessage | DeleteComponentNetworkMessage | DeleteEntityNetworkMessage;
141
+ /**
142
+ * @public
143
+ */
144
+ export type CrdtNetworkMessageBody = PutNetworkComponentMessageBody | DeleteComponentNetworkMessageBody | DeleteEntityNetworkMessageBody;
100
145
  /**
101
146
  * @public
102
147
  */
103
- export type CrdtMessageBody = PutComponentMessageBody | DeleteComponentMessageBody | DeleteEntityMessageBody | AppendValueMessageBody;
148
+ export type CrdtMessageBody = PutComponentMessageBody | DeleteComponentMessageBody | DeleteEntityMessageBody | AppendValueMessageBody | CrdtNetworkMessageBody;
104
149
  export declare enum ProcessMessageResultType {
105
150
  /**
106
151
  * Typical message and new state set.
@@ -9,7 +9,11 @@ export var CrdtMessageType;
9
9
  CrdtMessageType[CrdtMessageType["DELETE_COMPONENT"] = 2] = "DELETE_COMPONENT";
10
10
  CrdtMessageType[CrdtMessageType["DELETE_ENTITY"] = 3] = "DELETE_ENTITY";
11
11
  CrdtMessageType[CrdtMessageType["APPEND_VALUE"] = 4] = "APPEND_VALUE";
12
- CrdtMessageType[CrdtMessageType["MAX_MESSAGE_TYPE"] = 5] = "MAX_MESSAGE_TYPE";
12
+ // Network operations
13
+ CrdtMessageType[CrdtMessageType["PUT_COMPONENT_NETWORK"] = 5] = "PUT_COMPONENT_NETWORK";
14
+ CrdtMessageType[CrdtMessageType["DELETE_COMPONENT_NETWORK"] = 6] = "DELETE_COMPONENT_NETWORK";
15
+ CrdtMessageType[CrdtMessageType["DELETE_ENTITY_NETWORK"] = 7] = "DELETE_ENTITY_NETWORK";
16
+ CrdtMessageType[CrdtMessageType["MAX_MESSAGE_TYPE"] = 8] = "MAX_MESSAGE_TYPE";
13
17
  })(CrdtMessageType || (CrdtMessageType = {}));
14
18
  /**
15
19
  * @public
@@ -1,21 +1,26 @@
1
1
  import { EntityState } from '../../engine/entity';
2
2
  import { ReadWriteByteBuffer } from '../../serialization/ByteBuffer';
3
- import { AppendValueOperation, CrdtMessageProtocol } from '../../serialization/crdt';
3
+ import { AppendValueOperation, CrdtMessageProtocol, DeleteComponentNetwork, DeleteEntityNetwork } 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';
7
7
  import { CrdtMessageType } from '../../serialization/crdt/types';
8
+ import { PutNetworkComponentOperation } from '../../serialization/crdt/network/putComponentNetwork';
9
+ import { NetworkEntity as defineNetworkEntity, NetworkParent as defineNetworkParent, Transform as defineTransform } from '../../components';
10
+ import * as networkUtils from '../../serialization/crdt/network/utils';
8
11
  /**
9
12
  * @internal
10
13
  */
11
14
  export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
12
15
  const transports = [];
16
+ // Components that we used on this system
17
+ const NetworkEntity = defineNetworkEntity(engine);
18
+ const NetworkParent = defineNetworkParent(engine);
19
+ const Transform = defineTransform(engine);
13
20
  // Messages that we received at transport.onMessage waiting to be processed
14
21
  const receivedMessages = [];
15
22
  // Messages already processed by the engine but that we need to broadcast to other transports.
16
23
  const broadcastMessages = [];
17
- // Messages receieved by a transport that were outdated. We need to correct them
18
- const outdatedMessages = [];
19
24
  /**
20
25
  *
21
26
  * @param transportId tranport id to identiy messages
@@ -32,45 +37,41 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
32
37
  let header;
33
38
  while ((header = CrdtMessageProtocol.getHeader(buffer))) {
34
39
  const offset = buffer.currentReadOffset();
40
+ let message = undefined;
35
41
  if (header.type === CrdtMessageType.DELETE_COMPONENT) {
36
- const message = DeleteComponent.read(buffer);
37
- receivedMessages.push({
38
- ...message,
39
- transportId,
40
- messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
41
- });
42
+ message = DeleteComponent.read(buffer);
43
+ }
44
+ else if (header.type === CrdtMessageType.DELETE_COMPONENT_NETWORK) {
45
+ message = DeleteComponentNetwork.read(buffer);
42
46
  }
43
47
  else if (header.type === CrdtMessageType.PUT_COMPONENT) {
44
- const message = PutComponentOperation.read(buffer);
45
- receivedMessages.push({
46
- ...message,
47
- transportId,
48
- messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
49
- });
48
+ message = PutComponentOperation.read(buffer);
49
+ }
50
+ else if (header.type === CrdtMessageType.PUT_COMPONENT_NETWORK) {
51
+ message = PutNetworkComponentOperation.read(buffer);
50
52
  }
51
53
  else if (header.type === CrdtMessageType.DELETE_ENTITY) {
52
- const message = DeleteEntity.read(buffer);
53
- receivedMessages.push({
54
- ...message,
55
- transportId,
56
- messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
57
- });
54
+ message = DeleteEntity.read(buffer);
55
+ }
56
+ else if (header.type === CrdtMessageType.DELETE_ENTITY_NETWORK) {
57
+ message = DeleteEntityNetwork.read(buffer);
58
58
  }
59
59
  else if (header.type === CrdtMessageType.APPEND_VALUE) {
60
- const message = AppendValueOperation.read(buffer);
61
- receivedMessages.push({
62
- ...message,
63
- transportId,
64
- messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
65
- });
60
+ message = AppendValueOperation.read(buffer);
66
61
  // Unknown message, we skip it
67
62
  }
68
63
  else {
69
64
  // consume the message
70
65
  buffer.incrementReadOffset(header.length);
71
66
  }
67
+ if (message) {
68
+ receivedMessages.push({
69
+ ...message,
70
+ transportId,
71
+ messageBuffer: buffer.buffer().subarray(offset, buffer.currentReadOffset())
72
+ });
73
+ }
72
74
  }
73
- // TODO: do something if buffler.len>0
74
75
  };
75
76
  }
76
77
  /**
@@ -81,46 +82,61 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
81
82
  const messagesToProcess = value.splice(0, value.length);
82
83
  return messagesToProcess;
83
84
  }
85
+ /**
86
+ * Find the local entityId associated to the network component message.
87
+ * It's a mapping Network -> to Local
88
+ * If it's not a network message, return the entityId received by the message
89
+ */
90
+ function findNetworkId(msg) {
91
+ const hasNetworkId = 'networkId' in msg;
92
+ if (hasNetworkId) {
93
+ for (const [entityId, network] of engine.getEntitiesWith(NetworkEntity)) {
94
+ if (network.networkId === msg.networkId && network.entityId === msg.entityId) {
95
+ return { entityId, network };
96
+ }
97
+ }
98
+ }
99
+ return { entityId: msg.entityId };
100
+ }
84
101
  /**
85
102
  * This fn will be called on every tick.
86
103
  * Process all the messages queue received by the transport
87
104
  */
88
105
  async function receiveMessages() {
89
106
  const messagesToProcess = getMessages(receivedMessages);
90
- const bufferForOutdated = new ReadWriteByteBuffer();
91
107
  const entitiesShouldBeCleaned = [];
92
108
  for (const msg of messagesToProcess) {
93
- if (msg.type === CrdtMessageType.DELETE_ENTITY) {
94
- entitiesShouldBeCleaned.push(msg.entityId);
109
+ let { entityId, network } = findNetworkId(msg);
110
+ // We receive a new Entity. Create the localEntity and map it to the NetworkEntity component
111
+ if (networkUtils.isNetworkMessage(msg) && !network) {
112
+ entityId = engine.addEntity();
113
+ network = { entityId: msg.entityId, networkId: msg.networkId };
114
+ NetworkEntity.createOrReplace(entityId, network);
115
+ }
116
+ if (msg.type === CrdtMessageType.DELETE_ENTITY || msg.type === CrdtMessageType.DELETE_ENTITY_NETWORK) {
117
+ entitiesShouldBeCleaned.push(entityId);
95
118
  broadcastMessages.push(msg);
96
119
  }
97
120
  else {
98
- const entityState = engine.entityContainer.getEntityState(msg.entityId);
121
+ const entityState = engine.entityContainer.getEntityState(entityId);
99
122
  // Skip updates from removed entityes
100
123
  if (entityState === EntityState.Removed)
101
124
  continue;
102
125
  // Entities with unknown entities should update its entity state
103
126
  if (entityState === EntityState.Unknown) {
104
- engine.entityContainer.updateUsedEntity(msg.entityId);
127
+ engine.entityContainer.updateUsedEntity(entityId);
105
128
  }
106
129
  const component = engine.getComponentOrNull(msg.componentId);
107
130
  /* istanbul ignore else */
108
131
  if (component) {
109
- const [conflictMessage, value] = component.updateFromCrdt(msg);
110
- if (conflictMessage) {
111
- const offset = bufferForOutdated.currentWriteOffset();
112
- if (conflictMessage.type === CrdtMessageType.PUT_COMPONENT) {
113
- PutComponentOperation.write(msg.entityId, conflictMessage.timestamp, conflictMessage.componentId, conflictMessage.data, bufferForOutdated);
114
- }
115
- else if (conflictMessage.type === CrdtMessageType.DELETE_COMPONENT) {
116
- DeleteComponent.write(msg.entityId, component.componentId, conflictMessage.timestamp, bufferForOutdated);
117
- }
118
- outdatedMessages.push({
119
- ...msg,
120
- messageBuffer: bufferForOutdated.buffer().subarray(offset, bufferForOutdated.currentWriteOffset())
121
- });
132
+ if (msg.type === CrdtMessageType.PUT_COMPONENT &&
133
+ component.componentId === Transform.componentId &&
134
+ NetworkEntity.has(entityId) &&
135
+ NetworkParent.has(entityId)) {
136
+ msg.data = networkUtils.fixTransformParent(msg);
122
137
  }
123
- else {
138
+ const [conflictMessage, value] = component.updateFromCrdt({ ...msg, entityId });
139
+ if (!conflictMessage) {
124
140
  // Add message to transport queue to be processed by others transports
125
141
  broadcastMessages.push(msg);
126
142
  onProcessEntityComponentChange && onProcessEntityComponentChange(msg.entityId, msg.type, component, value);
@@ -134,12 +150,6 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
134
150
  }
135
151
  // the last stage of the syncrhonization is to delete the entities
136
152
  for (const entity of entitiesShouldBeCleaned) {
137
- // If we tried to resend outdated message and the entity was deleted before, we avoid sending them.
138
- for (let i = outdatedMessages.length - 1; i >= 0; i--) {
139
- if (outdatedMessages[i].entityId === entity && outdatedMessages[i].type !== CrdtMessageType.DELETE_ENTITY) {
140
- outdatedMessages.splice(i, 1);
141
- }
142
- }
143
153
  for (const definition of engine.componentsIter()) {
144
154
  // TODO: check this with pato/pravus
145
155
  definition.entityDeleted(entity, true);
@@ -154,7 +164,6 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
154
164
  async function sendMessages(entitiesDeletedThisTick) {
155
165
  // CRDT Messages will be the merge between the recieved transport messages and the new crdt messages
156
166
  const crdtMessages = getMessages(broadcastMessages);
157
- const outdatedMessagesBkp = getMessages(outdatedMessages);
158
167
  const buffer = new ReadWriteByteBuffer();
159
168
  for (const component of engine.componentsIter()) {
160
169
  for (const message of component.getCrdtUpdates()) {
@@ -199,25 +208,58 @@ export function crdtSceneSystem(engine, onProcessEntityComponentChange) {
199
208
  for (const index in transports) {
200
209
  const transportIndex = Number(index);
201
210
  const transport = transports[transportIndex];
211
+ const isRendererTransport = transport.type === 'renderer';
212
+ const isNetworkTransport = transport.type === 'network';
202
213
  transportBuffer.resetBuffer();
203
- // First we need to send all the messages that were outdated from a transport
204
- // So we can fix their crdt state
205
- for (const message of outdatedMessagesBkp) {
206
- if (message.transportId === transportIndex &&
207
- // TODO: This is an optimization, the state should converge anyway, whatever the message is sent.
208
- // Avoid sending multiple messages for the same entity-componentId
209
- !crdtMessages.find((m) => m.entityId === message.entityId &&
210
- // TODO: as any, with multiple type of messages, it should have many checks before the check for similar messages
211
- m.componentId &&
212
- m.componentId === message.componentId)) {
213
- transportBuffer.writeBuffer(message.messageBuffer, false);
214
- }
215
- }
214
+ const buffer = new ReadWriteByteBuffer();
216
215
  // Then we send all the new crdtMessages that the transport needs to process
217
216
  for (const message of crdtMessages) {
218
- if (message.transportId !== transportIndex && transport.filter(message)) {
219
- transportBuffer.writeBuffer(message.messageBuffer, false);
217
+ // Avoid echo messages
218
+ if (message.transportId === transportIndex)
219
+ continue;
220
+ // Redundant message for the transport
221
+ if (!transport.filter(message))
222
+ continue;
223
+ const { entityId } = findNetworkId(message);
224
+ const transformNeedsFix = 'componentId' in message &&
225
+ message.componentId === Transform.componentId &&
226
+ Transform.has(entityId) &&
227
+ NetworkParent.has(entityId) &&
228
+ NetworkEntity.has(entityId);
229
+ // If there was a LOCAL change in the transform. Add the parent to that transform
230
+ if (isRendererTransport && message.type === CrdtMessageType.PUT_COMPONENT && transformNeedsFix) {
231
+ const parent = findNetworkId(NetworkParent.get(entityId));
232
+ const transformData = networkUtils.fixTransformParent(message, Transform.get(entityId), parent.entityId);
233
+ const offset = buffer.currentWriteOffset();
234
+ PutComponentOperation.write(entityId, message.timestamp, message.componentId, transformData, buffer);
235
+ transportBuffer.writeBuffer(buffer.buffer().subarray(offset, buffer.currentWriteOffset()), false);
236
+ continue;
237
+ }
238
+ if (isRendererTransport && networkUtils.isNetworkMessage(message)) {
239
+ // If it's the renderer transport and its a NetworkMessage, we need to fix the entityId field and convert it to a known Message.
240
+ // PUT_NETWORK_COMPONENT -> PUT_COMPONENT
241
+ let transformData = 'data' in message ? message.data : new Uint8Array();
242
+ if (transformNeedsFix) {
243
+ const parent = findNetworkId(NetworkParent.get(entityId));
244
+ transformData = networkUtils.fixTransformParent(message, Transform.get(entityId), parent.entityId);
245
+ }
246
+ networkUtils.networkMessageToLocal({ ...message, data: transformData }, entityId, buffer, transportBuffer);
247
+ // Iterate the next message
248
+ continue;
249
+ }
250
+ // If its a network transport and its a PUT_COMPONENT that has a NetworkEntity component, we need to send this message
251
+ // through comms with the EntityID and NetworkID from ther NetworkEntity so everyone can recieve this message and map to their custom entityID.
252
+ if (isNetworkTransport && !networkUtils.isNetworkMessage(message)) {
253
+ const networkData = NetworkEntity.getOrNull(message.entityId);
254
+ // If it has networkData convert the message to PUT_NETWORK_COMPONENT.
255
+ if (networkData) {
256
+ networkUtils.localMessageToNetwork(message, networkData, buffer, transportBuffer);
257
+ // Iterate the next message
258
+ continue;
259
+ }
220
260
  }
261
+ // Common message
262
+ transportBuffer.writeBuffer(message.messageBuffer, false);
221
263
  }
222
264
  const message = transportBuffer.currentWriteOffset() ? transportBuffer.toBinary() : new Uint8Array([]);
223
265
  await transport.send(message);
@@ -1,4 +1,4 @@
1
- import { CrdtMessageBody } from '../../serialization/crdt/types';
1
+ import { CrdtMessageBody, CrdtNetworkMessageBody } from '../../serialization/crdt/types';
2
2
  /**
3
3
  * @public
4
4
  */
@@ -6,6 +6,13 @@ export type ReceiveMessage = CrdtMessageBody & {
6
6
  transportId?: number;
7
7
  messageBuffer: Uint8Array;
8
8
  };
9
+ /**
10
+ * @public
11
+ */
12
+ export type ReceiveNetworkMessage = CrdtNetworkMessageBody & {
13
+ transportId?: number;
14
+ messageBuffer: Uint8Array;
15
+ };
9
16
  /**
10
17
  * @public
11
18
  */
@@ -17,4 +24,5 @@ export type Transport = {
17
24
  send(message: Uint8Array): Promise<void>;
18
25
  onmessage?(message: Uint8Array): void;
19
26
  filter(message: Omit<TransportMessage, 'messageBuffer'>): boolean;
27
+ type?: string;
20
28
  };
@@ -8,6 +8,8 @@ import { TweenComponentDefinitionExtended } from './extended/Tween';
8
8
  import { LwwComponentGetter, GSetComponentGetter } from './generated/index.gen';
9
9
  import { NameType } from './manual/Name';
10
10
  import { ISyncComponentsType } from './manual/SyncComponents';
11
+ import { INetowrkEntityType } from './manual/NetworkEntity';
12
+ import { INetowrkParentType } from './manual/NetworkParent';
11
13
  import { TransformComponentExtended } from './manual/Transform';
12
14
  export * from './generated/index.gen';
13
15
  export type { GrowOnlyValueSetComponentDefinition, LastWriteWinElementSetComponentDefinition, LwwComponentGetter, GSetComponentGetter };
@@ -25,3 +27,11 @@ export declare const Name: (engine: Pick<IEngine, 'defineComponent'>) => LastWri
25
27
  * @alpha
26
28
  */
27
29
  export declare const SyncComponents: (engine: Pick<IEngine, 'defineComponent'>) => LastWriteWinElementSetComponentDefinition<ISyncComponentsType>;
30
+ /**
31
+ * @alpha
32
+ */
33
+ export declare const NetworkEntity: (engine: Pick<IEngine, 'defineComponent'>) => LastWriteWinElementSetComponentDefinition<INetowrkEntityType>;
34
+ /**
35
+ * @alpha
36
+ */
37
+ export declare const NetworkParent: (engine: Pick<IEngine, 'defineComponent'>) => LastWriteWinElementSetComponentDefinition<INetowrkParentType>;
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.SyncComponents = exports.Name = exports.Tween = exports.MeshCollider = exports.MeshRenderer = exports.Animator = exports.Material = exports.Transform = void 0;
20
+ exports.NetworkParent = exports.NetworkEntity = exports.SyncComponents = exports.Name = exports.Tween = exports.MeshCollider = exports.MeshRenderer = exports.Animator = exports.Material = exports.Transform = void 0;
21
21
  const Animator_1 = require("./extended/Animator");
22
22
  const Material_1 = require("./extended/Material");
23
23
  const MeshCollider_1 = require("./extended/MeshCollider");
@@ -25,6 +25,8 @@ const MeshRenderer_1 = require("./extended/MeshRenderer");
25
25
  const Tween_1 = require("./extended/Tween");
26
26
  const Name_1 = __importDefault(require("./manual/Name"));
27
27
  const SyncComponents_1 = __importDefault(require("./manual/SyncComponents"));
28
+ const NetworkEntity_1 = __importDefault(require("./manual/NetworkEntity"));
29
+ const NetworkParent_1 = __importDefault(require("./manual/NetworkParent"));
28
30
  const Transform_1 = require("./manual/Transform");
29
31
  __exportStar(require("./generated/index.gen"), exports);
30
32
  /* @__PURE__ */
@@ -57,3 +59,15 @@ exports.Name = Name;
57
59
  /* @__PURE__ */
58
60
  const SyncComponents = (engine) => (0, SyncComponents_1.default)(engine);
59
61
  exports.SyncComponents = SyncComponents;
62
+ /**
63
+ * @alpha
64
+ */
65
+ /* @__PURE__ */
66
+ const NetworkEntity = (engine) => (0, NetworkEntity_1.default)(engine);
67
+ exports.NetworkEntity = NetworkEntity;
68
+ /**
69
+ * @alpha
70
+ */
71
+ /* @__PURE__ */
72
+ const NetworkParent = (engine) => (0, NetworkParent_1.default)(engine);
73
+ exports.NetworkParent = NetworkParent;
@@ -0,0 +1,12 @@
1
+ import { Entity } from '../../engine';
2
+ import { IEngine, LastWriteWinElementSetComponentDefinition } from '../../engine/types';
3
+ export interface INetowrkEntityType {
4
+ networkId: number;
5
+ entityId: Entity;
6
+ }
7
+ export type INetowrkEntity = LastWriteWinElementSetComponentDefinition<INetowrkEntityType>;
8
+ declare function defineNetworkEntityComponent(engine: Pick<IEngine, 'defineComponent'>): import("../../engine").MapComponentDefinition<import("../..").MapResult<{
9
+ networkId: import("../../schemas").ISchema<number>;
10
+ entityId: import("../../schemas").ISchema<Entity>;
11
+ }>>;
12
+ export default defineNetworkEntityComponent;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schemas_1 = require("../../schemas");
4
+ function defineNetworkEntityComponent(engine) {
5
+ const EntityNetwork = engine.defineComponent('core-schema::Network-Entity', {
6
+ networkId: schemas_1.Schemas.Int64,
7
+ entityId: schemas_1.Schemas.Entity
8
+ });
9
+ return EntityNetwork;
10
+ }
11
+ exports.default = defineNetworkEntityComponent;
@@ -0,0 +1,12 @@
1
+ import { Entity } from '../../engine';
2
+ import { IEngine, LastWriteWinElementSetComponentDefinition } from '../../engine/types';
3
+ export interface INetowrkParentType {
4
+ networkId: number;
5
+ entityId: Entity;
6
+ }
7
+ export type INetowrkParent = LastWriteWinElementSetComponentDefinition<INetowrkParentType>;
8
+ declare function defineNetworkParentComponent(engine: Pick<IEngine, 'defineComponent'>): import("../../engine").MapComponentDefinition<import("../..").MapResult<{
9
+ networkId: import("../../schemas").ISchema<number>;
10
+ entityId: import("../../schemas").ISchema<Entity>;
11
+ }>>;
12
+ export default defineNetworkParentComponent;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schemas_1 = require("../../schemas");
4
+ function defineNetworkParentComponent(engine) {
5
+ const EntityNetwork = engine.defineComponent('core-schema::Network-Parent', {
6
+ networkId: schemas_1.Schemas.Int64,
7
+ entityId: schemas_1.Schemas.Entity
8
+ });
9
+ return EntityNetwork;
10
+ }
11
+ exports.default = defineNetworkParentComponent;
@@ -6,3 +6,5 @@ export type { TweenHelper, TweenComponentDefinitionExtended } from './extended/T
6
6
  export type { TransformComponentExtended, TransformTypeWithOptionals } from './manual/Transform';
7
7
  export type { NameComponent, NameType } from './manual/Name';
8
8
  export type { ISyncComponents, ISyncComponentsType } from './manual/SyncComponents';
9
+ export type { INetowrkEntity, INetowrkEntityType } from './manual/NetworkEntity';
10
+ export type { INetowrkParent, INetowrkParentType } from './manual/NetworkParent';
@@ -44,7 +44,6 @@ function preEngine() {
44
44
  const entityContainer = (0, entity_1.EntityContainer)();
45
45
  const componentsDefinition = new Map();
46
46
  const systems = (0, systems_1.SystemContainer)();
47
- let networkManager;
48
47
  let sealed = false;
49
48
  function addSystem(fn, priority = systems_1.SYSTEMS_REGULAR_PRIORITY, name) {
50
49
  systems.add(fn, priority, name);
@@ -52,30 +51,22 @@ function preEngine() {
52
51
  function removeSystem(selector) {
53
52
  return systems.remove(selector);
54
53
  }
55
- function getNetworkManager() {
56
- if (!networkManager)
57
- throw new Error('Network manager not initialized. Start CRDT Server');
58
- return networkManager;
59
- }
60
- function addNetworkManager(reservedLocalEntities, range) {
61
- entityContainer.setNetworkEntitiesRange(reservedLocalEntities, range);
62
- networkManager = {
63
- addEntity: () => entityContainer.generateEntity(true)
64
- };
65
- return networkManager;
66
- }
67
54
  function addEntity() {
68
55
  const entity = entityContainer.generateEntity();
69
56
  return entity;
70
57
  }
71
58
  function removeEntity(entity) {
72
59
  for (const [, component] of componentsDefinition) {
60
+ // TODO: hack for the moment. It should be enough to delete the entity, but the renderer is not cleaning the components.
61
+ // So we still need the NetworkEntity to forward this message to the SyncTransport.
62
+ if (component.componentName === 'core-schema::Network-Entity')
63
+ continue;
73
64
  component.entityDeleted(entity, true);
74
65
  }
75
66
  return entityContainer.removeEntity(entity);
76
67
  }
77
68
  function removeEntityWithChildren(entity) {
78
- return (0, tree_1.removeEntityWithChildren)({ removeEntity, defineComponentFromSchema, getEntitiesWith }, entity);
69
+ return (0, tree_1.removeEntityWithChildren)({ removeEntity, defineComponentFromSchema, getEntitiesWith, defineComponent }, entity);
79
70
  }
80
71
  function registerComponentDefinition(componentName, component) {
81
72
  /* istanbul ignore next */
@@ -152,7 +143,7 @@ function preEngine() {
152
143
  const componentId = typeof componentIdOrName === 'number' ? componentIdOrName : (0, component_number_1.componentNumberFromName)(componentIdOrName);
153
144
  const component = componentsDefinition.get(componentId);
154
145
  if (!component) {
155
- throw new Error(`Component ${componentId} not found. You need to declare the components at the beginnig of the engine declaration`);
146
+ throw new Error(`Component ${componentIdOrName} not found. You need to declare the components at the beginnig of the engine declaration`);
156
147
  }
157
148
  return component;
158
149
  }
@@ -226,9 +217,7 @@ function preEngine() {
226
217
  registerComponentDefinition,
227
218
  entityContainer,
228
219
  componentsIter,
229
- seal,
230
- addNetworkManager,
231
- getNetworkManager
220
+ seal
232
221
  };
233
222
  }
234
223
  /**
@@ -272,9 +261,7 @@ function Engine(options) {
272
261
  CameraEntity: 2,
273
262
  getEntityState: partialEngine.entityContainer.getEntityState,
274
263
  addTransport: crdtSystem.addTransport,
275
- entityContainer: partialEngine.entityContainer,
276
- addNetworkManager: partialEngine.addNetworkManager,
277
- getNetworkManager: partialEngine.getNetworkManager
264
+ entityContainer: partialEngine.entityContainer
278
265
  };
279
266
  }
280
267
  exports.Engine = Engine;
@@ -86,7 +86,10 @@ function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
86
86
  }
87
87
  return (msg) => {
88
88
  /* istanbul ignore next */
89
- if (msg.type !== crdt_1.CrdtMessageType.PUT_COMPONENT && msg.type !== crdt_1.CrdtMessageType.DELETE_COMPONENT)
89
+ if (msg.type !== crdt_1.CrdtMessageType.PUT_COMPONENT &&
90
+ msg.type !== crdt_1.CrdtMessageType.PUT_COMPONENT_NETWORK &&
91
+ msg.type !== crdt_1.CrdtMessageType.DELETE_COMPONENT &&
92
+ msg.type !== crdt_1.CrdtMessageType.DELETE_COMPONENT_NETWORK)
90
93
  /* istanbul ignore next */
91
94
  return [null, data.get(msg.entityId)];
92
95
  const action = crdtRuleForCurrentState(msg);
@@ -95,7 +98,7 @@ function createUpdateLwwFromCrdt(componentId, timestamps, schema, data) {
95
98
  case crdt_1.ProcessMessageResultType.StateUpdatedData:
96
99
  case crdt_1.ProcessMessageResultType.StateUpdatedTimestamp: {
97
100
  timestamps.set(entity, msg.timestamp);
98
- if (msg.type === crdt_1.CrdtMessageType.PUT_COMPONENT) {
101
+ if (msg.type === crdt_1.CrdtMessageType.PUT_COMPONENT || msg.type === crdt_1.CrdtMessageType.PUT_COMPONENT_NETWORK) {
99
102
  const buf = new ByteBuffer_1.ReadWriteByteBuffer(msg.data);
100
103
  data.set(entity, schema.deserialize(buf));
101
104
  }
@@ -227,16 +227,4 @@ export interface IEngine {
227
227
  * components that will be available to this engine and to run optimizations.
228
228
  */
229
229
  seal(): void;
230
- /**
231
- * @alpha
232
- * Initialize network manager
233
- */
234
- addNetworkManager(reservedLocalEntities: number, range: [number, number]): {
235
- addEntity: IEngine['addEntity'];
236
- };
237
- /**
238
- * @alpha
239
- * Get netowrk manager to create entities.
240
- */
241
- getNetworkManager(): ReturnType<IEngine['addNetworkManager']>;
242
230
  }