@dcl/playground-assets 7.0.6-4138167187.commit-c9d306a → 7.0.6-4153633895.commit-4aad233

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.
package/dist/index.js CHANGED
@@ -13011,7 +13011,8 @@
13011
13011
  return {
13012
13012
  position: { x: 0, y: 0, z: 0 },
13013
13013
  scale: { x: 1, y: 1, z: 1 },
13014
- rotation: { x: 0, y: 0, z: 0, w: 1 }
13014
+ rotation: { x: 0, y: 0, z: 0, w: 1 },
13015
+ parent: 0
13015
13016
  };
13016
13017
  },
13017
13018
  extend(value) {
@@ -13019,6 +13020,7 @@
13019
13020
  position: { x: 0, y: 0, z: 0 },
13020
13021
  scale: { x: 1, y: 1, z: 1 },
13021
13022
  rotation: { x: 0, y: 0, z: 0, w: 1 },
13023
+ parent: 0,
13022
13024
  ...value
13023
13025
  };
13024
13026
  }
@@ -13667,402 +13669,57 @@
13667
13669
  Schemas.Optional = IOptional;
13668
13670
  })(exports.Schemas || (exports.Schemas = {}));
13669
13671
 
13670
- var dist = {};
13671
-
13672
- var gset = {};
13673
-
13674
- var hasRequiredGset;
13675
-
13676
- function requireGset () {
13677
- if (hasRequiredGset) return gset;
13678
- hasRequiredGset = 1;
13679
- Object.defineProperty(gset, "__esModule", { value: true });
13680
- gset.createVersionGSet = void 0;
13681
- /**
13682
- *
13683
- * @returns a new GSet
13684
- */
13685
- function createVersionGSet() {
13686
- const lastVersion = new Map();
13687
- return {
13688
- /**
13689
- *
13690
- * @param number
13691
- * @param version
13692
- * @returns
13693
- */
13694
- addTo(number, version) {
13695
- if (version < 0) {
13696
- return false;
13697
- }
13698
- const currentValue = lastVersion.get(number);
13699
- // If the version is >=, it means the value it's already in the set
13700
- if (currentValue !== undefined && currentValue >= version) {
13701
- return true;
13702
- }
13703
- lastVersion.set(number, version);
13704
- return true;
13705
- },
13706
- /**
13707
- * @returns the set with [number, version] of each value
13708
- */
13709
- get() {
13710
- const arr = [];
13711
- for (const [n, v] of lastVersion) {
13712
- for (let i = 0; i <= v; i++) {
13713
- arr.push([n, i]);
13714
- }
13715
- }
13716
- return arr;
13717
- },
13718
- /**
13719
- * @returns the set with [number, version] of each value
13720
- */
13721
- has(n, v) {
13722
- const currentValue = lastVersion.get(n);
13723
- // If the version is >=, it means the value it's already in the set
13724
- if (currentValue !== undefined && currentValue >= v) {
13725
- return true;
13726
- }
13727
- return false;
13728
- },
13729
- /**
13730
- * Warning: this function returns the reference to the internal map,
13731
- * if you need to mutate some value, make a copy.
13732
- * For optimization purpose the copy isn't made here.
13733
- *
13734
- * @returns the map of number to version
13735
- */
13736
- getMap() {
13737
- return lastVersion;
13738
- }
13739
- };
13740
- }
13741
- gset.createVersionGSet = createVersionGSet;
13742
-
13743
- return gset;
13744
- }
13745
-
13746
- var types = {};
13747
-
13748
- var hasRequiredTypes;
13749
-
13750
- function requireTypes () {
13751
- if (hasRequiredTypes) return types;
13752
- hasRequiredTypes = 1;
13753
- (function (exports) {
13754
- Object.defineProperty(exports, "__esModule", { value: true });
13755
- exports.ProcessMessageResultType = exports.CRDTMessageType = void 0;
13756
- (function (CRDTMessageType) {
13757
- CRDTMessageType[CRDTMessageType["CRDTMT_PutComponentData"] = 1] = "CRDTMT_PutComponentData";
13758
- CRDTMessageType[CRDTMessageType["CRDTMT_DeleteEntity"] = 2] = "CRDTMT_DeleteEntity";
13759
- })(exports.CRDTMessageType || (exports.CRDTMessageType = {}));
13760
- (function (ProcessMessageResultType) {
13761
- /**
13762
- * Typical message and new state set.
13763
- * @state CHANGE
13764
- * @reason Incoming message has a timestamp greater
13765
- */
13766
- ProcessMessageResultType[ProcessMessageResultType["StateUpdatedTimestamp"] = 1] = "StateUpdatedTimestamp";
13767
- /**
13768
- * Typical message when it is considered old.
13769
- * @state it does NOT CHANGE.
13770
- * @reason incoming message has a timestamp lower.
13771
- */
13772
- ProcessMessageResultType[ProcessMessageResultType["StateOutdatedTimestamp"] = 2] = "StateOutdatedTimestamp";
13773
- /**
13774
- * Weird message, same timestamp and data.
13775
- * @state it does NOT CHANGE.
13776
- * @reason consistent state between peers.
13777
- */
13778
- ProcessMessageResultType[ProcessMessageResultType["NoChanges"] = 3] = "NoChanges";
13779
- /**
13780
- * Less but typical message, same timestamp, resolution by data.
13781
- * @state it does NOT CHANGE.
13782
- * @reason incoming message has a LOWER data.
13783
- */
13784
- ProcessMessageResultType[ProcessMessageResultType["StateOutdatedData"] = 4] = "StateOutdatedData";
13785
- /**
13786
- * Less but typical message, same timestamp, resolution by data.
13787
- * @state CHANGE.
13788
- * @reason incoming message has a GREATER data.
13789
- */
13790
- ProcessMessageResultType[ProcessMessageResultType["StateUpdatedData"] = 5] = "StateUpdatedData";
13791
- /**
13792
- * Entity was previously deleted.
13793
- * @state it does NOT CHANGE.
13794
- * @reason The message is considered old.
13795
- */
13796
- ProcessMessageResultType[ProcessMessageResultType["EntityWasDeleted"] = 6] = "EntityWasDeleted";
13797
- /**
13798
- * Entity should be deleted.
13799
- * @state CHANGE.
13800
- * @reason the state is storing old entities
13801
- */
13802
- ProcessMessageResultType[ProcessMessageResultType["EntityDeleted"] = 7] = "EntityDeleted";
13803
- })(exports.ProcessMessageResultType || (exports.ProcessMessageResultType = {}));
13804
- // we receive LWW, v=6, we have v=5 => we receive with delay the deleteEntity(v=5)
13805
- // => we should generate the deleteEntity message effects internally with deleteEntity(v=5),
13806
- // but don't resend the deleteEntity
13807
- // - (CRDT) addDeletedEntitySet v=5 (with crdt state cleaning) and then LWW v=6
13808
- // - (engine) engine.deleteEntity v=5
13809
- // we receive LWW, v=7, we have v=5 => we receive with delay the deleteEntity(v=5), deleteEntity(v=6), ..., N
13810
- // => we should generate the deleteEntity message effects internally with deleteEntity(v=5),
13811
- // but don't resend the deleteEntity
13812
- // - (CRDT) addDeletedEntitySet v=5 (with crdt state cleaning) and then LWW v=6
13813
- // - (engine) engine.deleteEntity v=5
13814
- // msg delete entity: it only should be sent by deleter
13815
- //
13816
-
13817
- } (types));
13818
- return types;
13819
- }
13820
-
13821
- var hasRequiredDist;
13822
-
13823
- function requireDist () {
13824
- if (hasRequiredDist) return dist;
13825
- hasRequiredDist = 1;
13826
- (function (exports) {
13827
- var __createBinding = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13828
- if (k2 === undefined) k2 = k;
13829
- var desc = Object.getOwnPropertyDescriptor(m, k);
13830
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13831
- desc = { enumerable: true, get: function() { return m[k]; } };
13832
- }
13833
- Object.defineProperty(o, k2, desc);
13834
- }) : (function(o, m, k, k2) {
13835
- if (k2 === undefined) k2 = k;
13836
- o[k2] = m[k];
13837
- }));
13838
- var __exportStar = (commonjsGlobal && commonjsGlobal.__exportStar) || function(m, exports) {
13839
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
13840
- };
13841
- Object.defineProperty(exports, "__esModule", { value: true });
13842
- exports.crdtProtocol = exports.stateIterator = exports.dataCompare = void 0;
13843
- const gset_1 = requireGset();
13844
- const types_1 = requireTypes();
13845
- const globalBuffer = globalThis.Buffer;
13846
- __exportStar(requireTypes(), exports);
13847
- /**
13848
- * Compare raw data.
13849
- * @internal
13850
- * @returns 0 if is the same data, 1 if a > b, -1 if b > a
13851
- */
13852
- function dataCompare(a, b) {
13853
- // At reference level
13854
- if (a === b)
13855
- return 0;
13856
- if (a === null && b !== null)
13857
- return -1;
13858
- if (a !== null && b === null)
13859
- return 1;
13860
- if (a instanceof Uint8Array && b instanceof Uint8Array) {
13861
- let res;
13862
- const n = a.byteLength > b.byteLength ? b.byteLength : a.byteLength;
13863
- for (let i = 0; i < n; i++) {
13864
- res = a[i] - b[i];
13865
- if (res !== 0) {
13866
- return res > 0 ? 1 : -1;
13867
- }
13868
- }
13869
- res = a.byteLength - b.byteLength;
13870
- return res > 0 ? 1 : res < 0 ? -1 : 0;
13871
- }
13872
- if (globalBuffer) {
13873
- /* istanbul ignore next */
13874
- if (a instanceof globalBuffer && b instanceof globalBuffer) {
13875
- /* istanbul ignore next */
13876
- return a.compare(b);
13877
- }
13878
- }
13879
- if (typeof a === 'string') {
13880
- return a.localeCompare(b);
13881
- }
13882
- return a > b ? 1 : -1;
13883
- }
13884
- exports.dataCompare = dataCompare;
13885
- /**
13886
- * State iterator
13887
- * @internal
13888
- */
13889
- function* stateIterator(state) {
13890
- for (const [componentId, value1] of state.components.entries()) {
13891
- for (const [entityId, value2] of value1.entries()) {
13892
- yield [componentId, entityId, value2];
13893
- }
13894
- }
13895
- }
13896
- exports.stateIterator = stateIterator;
13897
- /**
13898
- * @public
13899
- * CRDT protocol.
13900
- * Stores the latest state, and decides whenever we have
13901
- * to process and store the new data in case its an update, or
13902
- * to discard and send our local value cause remote it's outdated.
13903
- */
13904
- function crdtProtocol(entityUtils) {
13905
- /**
13906
- * Local state where we store the latest lamport timestamp
13907
- * and the raw data value
13908
- * @internal
13909
- */
13910
- const state = {
13911
- components: new Map(),
13912
- deletedEntities: (0, gset_1.createVersionGSet)()
13913
- };
13914
- /**
13915
- * We should call this fn in order to update the state
13916
- * @internal
13917
- */
13918
- function updateState(componentId, entityId, // todo: force type entity
13919
- data, remoteTimestamp) {
13920
- const componentIdValue = state.components.get(componentId);
13921
- const timestamp = Math.max(remoteTimestamp, componentIdValue?.get(entityId)?.timestamp || 0);
13922
- if (componentIdValue) {
13923
- componentIdValue.set(entityId, { timestamp, data });
13924
- }
13925
- else {
13926
- const componentIdValue = new Map();
13927
- componentIdValue.set(entityId, { timestamp, data });
13928
- state.components.set(componentId, componentIdValue);
13929
- }
13930
- return { timestamp, data };
13931
- }
13932
- /**
13933
- * Create an event for the specified key and store the new data and
13934
- * lamport timestmap incremented by one in the state.components.
13935
- * @public
13936
- */
13937
- function createComponentDataEvent(componentId, entityId, data) {
13938
- // Increment the timestamp
13939
- const timestamp = (state.components.get(componentId)?.get(entityId)?.timestamp || 0) + 1;
13940
- const msg = {
13941
- type: types_1.CRDTMessageType.CRDTMT_PutComponentData,
13942
- componentId,
13943
- entityId,
13944
- data,
13945
- timestamp
13946
- };
13947
- const res = processComponentDataMessage(msg);
13948
- if (res === types_1.ProcessMessageResultType.StateUpdatedTimestamp) {
13949
- return msg;
13950
- }
13951
- else {
13952
- return null;
13953
- }
13954
- }
13955
- /**
13956
- * Create an event for the specified key and store the new data and
13957
- * lamport timestmap incremented by one in the state.components.
13958
- * @public
13959
- */
13960
- function createDeleteEntityEvent(entityId) {
13961
- // Increment the timestamp
13962
- const message = {
13963
- type: types_1.CRDTMessageType.CRDTMT_DeleteEntity,
13964
- entityId
13965
- };
13966
- processDeleteEntityMessage(message);
13967
- return message;
13968
- }
13969
- /**
13970
- * Process the received message only if the lamport number recieved is higher
13971
- * than the stored one. If its lower, we spread it to the network to correct the peer.
13972
- * If they are equal, the bigger raw data wins.
13973
-
13974
- * Returns the recieved data if the lamport number was bigger than ours.
13975
- * If it was an outdated message, then we return void
13976
- * @public
13977
- */
13978
- function processComponentDataMessage(message) {
13979
- const [entityNumber, entityVersion] = entityUtils.fromEntityId(message.entityId);
13980
- if (state.deletedEntities.has(entityNumber, entityVersion)) {
13981
- return types_1.ProcessMessageResultType.EntityWasDeleted;
13982
- }
13983
- const { componentId, entityId, data, timestamp } = message;
13984
- const current = state.components.get(componentId)?.get(entityId);
13985
- // The received message is > than our current value, update our state.components.
13986
- if (!current || current.timestamp < timestamp) {
13987
- updateState(componentId, entityId, data, timestamp);
13988
- return types_1.ProcessMessageResultType.StateUpdatedTimestamp;
13989
- }
13990
- // Outdated Message. Resend our state message through the wire.
13991
- if (current.timestamp > timestamp) {
13992
- return types_1.ProcessMessageResultType.StateOutdatedTimestamp;
13993
- }
13994
- const currentDataGreater = dataCompare(current.data, data);
13995
- // Same data, same timestamp. Weirdo echo message.
13996
- if (currentDataGreater === 0) {
13997
- return types_1.ProcessMessageResultType.NoChanges;
13998
- // Current data is greater
13999
- }
14000
- else if (currentDataGreater > 0) {
14001
- return types_1.ProcessMessageResultType.StateOutdatedData;
14002
- // Curent data is lower
14003
- }
14004
- else {
14005
- updateState(componentId, entityId, data, timestamp);
14006
- return types_1.ProcessMessageResultType.StateUpdatedData;
14007
- }
14008
- }
14009
- /*
14010
- * @public
14011
- */
14012
- function processMessage(message) {
14013
- if (message.type === types_1.CRDTMessageType.CRDTMT_PutComponentData) {
14014
- return processComponentDataMessage(message);
14015
- }
14016
- else if (message.type === types_1.CRDTMessageType.CRDTMT_DeleteEntity) {
14017
- return processDeleteEntityMessage(message);
14018
- }
14019
- else {
14020
- return types_1.ProcessMessageResultType.NoChanges;
14021
- }
14022
- }
14023
- function processDeleteEntityMessage(message) {
14024
- const { entityId } = message;
14025
- const [entityNumber, entityVersion] = entityUtils.fromEntityId(message.entityId);
14026
- state.deletedEntities.addTo(entityNumber, entityVersion);
14027
- for (const [, payload] of state.components) {
14028
- payload.delete(entityId);
14029
- }
14030
- return types_1.ProcessMessageResultType.EntityDeleted;
14031
- }
14032
- /**
14033
- * Returns the current state
14034
- * @public
14035
- */
14036
- function getState() {
14037
- return state;
14038
- }
14039
- /**
14040
- * Returns the element state of a given element of the LWW-ElementSet
14041
- * @public
14042
- */
14043
- function getElementSetState(componentId, entityId) {
14044
- return state.components.get(componentId)?.get(entityId) || null;
14045
- }
14046
- return {
14047
- getElementSetState,
14048
- createComponentDataEvent,
14049
- createDeleteEntityEvent,
14050
- processMessage,
14051
- getState
14052
- };
14053
- }
14054
- exports.crdtProtocol = crdtProtocol;
14055
-
14056
- } (dist));
14057
- return dist;
13672
+ /**
13673
+ *
13674
+ * @returns a new GSet
13675
+ */
13676
+ function createVersionGSet() {
13677
+ const lastVersion = new Map();
13678
+ return {
13679
+ /**
13680
+ *
13681
+ * @param number
13682
+ * @param version
13683
+ * @returns
13684
+ */
13685
+ addTo(number, version) {
13686
+ /* istanbul ignore next */
13687
+ if (version < 0) {
13688
+ /* istanbul ignore next */
13689
+ return false;
13690
+ }
13691
+ const currentValue = lastVersion.get(number);
13692
+ // If the version is >=, it means the value it's already in the set
13693
+ if (currentValue !== undefined && currentValue >= version) {
13694
+ return true;
13695
+ }
13696
+ lastVersion.set(number, version);
13697
+ return true;
13698
+ },
13699
+ /**
13700
+ * @returns the set with [number, version] of each value
13701
+ */
13702
+ has(n, v) {
13703
+ const currentValue = lastVersion.get(n);
13704
+ // If the version is >=, it means the value it's already in the set
13705
+ if (currentValue !== undefined && currentValue >= v) {
13706
+ return true;
13707
+ }
13708
+ return false;
13709
+ },
13710
+ /**
13711
+ * Warning: this function returns the reference to the internal map,
13712
+ * if you need to mutate some value, make a copy.
13713
+ * For optimization purpose the copy isn't made here.
13714
+ *
13715
+ * @returns the map of number to version
13716
+ */
13717
+ getMap() {
13718
+ return lastVersion;
13719
+ }
13720
+ };
14058
13721
  }
14059
13722
 
14060
- var distExports = requireDist();
14061
-
14062
- var typesExports = requireTypes();
14063
-
14064
- var gsetExports = requireGset();
14065
-
14066
13723
  /**
14067
13724
  * @internal
14068
13725
  */
@@ -14128,7 +13785,7 @@
14128
13785
  let entityCounter = RESERVED_STATIC_ENTITIES;
14129
13786
  const usedEntities = new Set();
14130
13787
  let toRemoveEntities = [];
14131
- const removedEntities = gsetExports.createVersionGSet();
13788
+ const removedEntities = createVersionGSet();
14132
13789
  function generateNewEntity() {
14133
13790
  if (entityCounter > MAX_ENTITY_NUMBER - 1) {
14134
13791
  throw new Error(`It fails trying to generate an entity out of range ${MAX_ENTITY_NUMBER}.`);
@@ -14173,10 +13830,12 @@
14173
13830
  }
14174
13831
  function releaseRemovedEntities() {
14175
13832
  const arr = toRemoveEntities;
14176
- toRemoveEntities = [];
14177
- for (const entity of arr) {
14178
- const [n, v] = exports.EntityUtils.fromEntityId(entity);
14179
- removedEntities.addTo(n, v);
13833
+ if (arr.length) {
13834
+ toRemoveEntities = [];
13835
+ for (const entity of arr) {
13836
+ const [n, v] = exports.EntityUtils.fromEntityId(entity);
13837
+ removedEntities.addTo(n, v);
13838
+ }
14180
13839
  }
14181
13840
  return arr;
14182
13841
  }
@@ -14192,10 +13851,9 @@
14192
13851
  }
14193
13852
  function updateUsedEntity(entity) {
14194
13853
  const [n, v] = exports.EntityUtils.fromEntityId(entity);
14195
- const removedVersion = removedEntities.getMap().get(n);
14196
- if (removedVersion !== undefined && removedVersion >= v) {
13854
+ // if the entity was removed then abort fast
13855
+ if (removedEntities.has(n, v))
14197
13856
  return false;
14198
- }
14199
13857
  // Update
14200
13858
  if (v > 0) {
14201
13859
  for (let i = 0; i <= v - 1; i++) {
@@ -14489,9 +14147,66 @@
14489
14147
  CrdtMessageType[CrdtMessageType["MAX_MESSAGE_TYPE"] = 4] = "MAX_MESSAGE_TYPE";
14490
14148
  })(exports.CrdtMessageType || (exports.CrdtMessageType = {}));
14491
14149
  /**
14492
- * @internal
14150
+ * @public
14493
14151
  */
14494
14152
  const CRDT_MESSAGE_HEADER_LENGTH = 8;
14153
+ exports.ProcessMessageResultType = void 0;
14154
+ (function (ProcessMessageResultType) {
14155
+ /**
14156
+ * Typical message and new state set.
14157
+ * @state CHANGE
14158
+ * @reason Incoming message has a timestamp greater
14159
+ */
14160
+ ProcessMessageResultType[ProcessMessageResultType["StateUpdatedTimestamp"] = 1] = "StateUpdatedTimestamp";
14161
+ /**
14162
+ * Typical message when it is considered old.
14163
+ * @state it does NOT CHANGE.
14164
+ * @reason incoming message has a timestamp lower.
14165
+ */
14166
+ ProcessMessageResultType[ProcessMessageResultType["StateOutdatedTimestamp"] = 2] = "StateOutdatedTimestamp";
14167
+ /**
14168
+ * Weird message, same timestamp and data.
14169
+ * @state it does NOT CHANGE.
14170
+ * @reason consistent state between peers.
14171
+ */
14172
+ ProcessMessageResultType[ProcessMessageResultType["NoChanges"] = 3] = "NoChanges";
14173
+ /**
14174
+ * Less but typical message, same timestamp, resolution by data.
14175
+ * @state it does NOT CHANGE.
14176
+ * @reason incoming message has a LOWER data.
14177
+ */
14178
+ ProcessMessageResultType[ProcessMessageResultType["StateOutdatedData"] = 4] = "StateOutdatedData";
14179
+ /**
14180
+ * Less but typical message, same timestamp, resolution by data.
14181
+ * @state CHANGE.
14182
+ * @reason incoming message has a GREATER data.
14183
+ */
14184
+ ProcessMessageResultType[ProcessMessageResultType["StateUpdatedData"] = 5] = "StateUpdatedData";
14185
+ /**
14186
+ * Entity was previously deleted.
14187
+ * @state it does NOT CHANGE.
14188
+ * @reason The message is considered old.
14189
+ */
14190
+ ProcessMessageResultType[ProcessMessageResultType["EntityWasDeleted"] = 6] = "EntityWasDeleted";
14191
+ /**
14192
+ * Entity should be deleted.
14193
+ * @state CHANGE.
14194
+ * @reason the state is storing old entities
14195
+ */
14196
+ ProcessMessageResultType[ProcessMessageResultType["EntityDeleted"] = 7] = "EntityDeleted";
14197
+ })(exports.ProcessMessageResultType || (exports.ProcessMessageResultType = {}));
14198
+ // we receive LWW, v=6, we have v=5 => we receive with delay the deleteEntity(v=5)
14199
+ // => we should generate the deleteEntity message effects internally with deleteEntity(v=5),
14200
+ // but don't resend the deleteEntity
14201
+ // - (CRDT) addDeletedEntitySet v=5 (with crdt state cleaning) and then LWW v=6
14202
+ // - (engine) engine.deleteEntity v=5
14203
+ // we receive LWW, v=7, we have v=5 => we receive with delay the deleteEntity(v=5), deleteEntity(v=6), ..., N
14204
+ // => we should generate the deleteEntity message effects internally with deleteEntity(v=5),
14205
+ // but don't resend the deleteEntity
14206
+ // - (CRDT) addDeletedEntitySet v=5 (with crdt state cleaning) and then LWW v=6
14207
+ // - (engine) engine.deleteEntity v=5
14208
+ // msg delete entity: it only should be sent by deleter
14209
+ //
14495
14210
 
14496
14211
  /**
14497
14212
  * @internal
@@ -14642,18 +14357,18 @@
14642
14357
  * Call this function for an optimal writing data passing the ByteBuffer
14643
14358
  * already allocated
14644
14359
  */
14645
- function write(entity, timestamp, componentDefinition, buf) {
14360
+ function write(entity, timestamp, componentId, data, buf) {
14646
14361
  // reserve the beginning
14647
14362
  const startMessageOffset = buf.incrementWriteOffset(CRDT_MESSAGE_HEADER_LENGTH + PutComponentOperation.MESSAGE_HEADER_LENGTH);
14648
14363
  // write body
14649
- componentDefinition.writeToByteBuffer(entity, buf);
14364
+ buf.writeBuffer(data, false);
14650
14365
  const messageLength = buf.currentWriteOffset() - startMessageOffset;
14651
14366
  // Write CrdtMessage header
14652
14367
  buf.setUint32(startMessageOffset, messageLength);
14653
14368
  buf.setUint32(startMessageOffset + 4, exports.CrdtMessageType.PUT_COMPONENT);
14654
14369
  // Write ComponentOperation header
14655
14370
  buf.setUint32(startMessageOffset + 8, entity);
14656
- buf.setUint32(startMessageOffset + 12, componentDefinition.componentId);
14371
+ buf.setUint32(startMessageOffset + 12, componentId);
14657
14372
  buf.setUint32(startMessageOffset + 16, timestamp);
14658
14373
  const newLocal = messageLength - PutComponentOperation.MESSAGE_HEADER_LENGTH - CRDT_MESSAGE_HEADER_LENGTH;
14659
14374
  buf.setUint32(startMessageOffset + 20, newLocal);
@@ -14683,11 +14398,6 @@
14683
14398
  */
14684
14399
  function crdtSceneSystem(engine, onProcessEntityComponentChange) {
14685
14400
  const transports = [];
14686
- // CRDT Client
14687
- const crdtClient = distExports.crdtProtocol({
14688
- toEntityId: exports.EntityUtils.toEntityId,
14689
- fromEntityId: exports.EntityUtils.fromEntityId
14690
- });
14691
14401
  // Messages that we received at transport.onMessage waiting to be processed
14692
14402
  const receivedMessages = [];
14693
14403
  // Messages already processed by the engine but that we need to broadcast to other transports.
@@ -14764,20 +14474,9 @@
14764
14474
  const entitiesShouldBeCleaned = [];
14765
14475
  for (const msg of messagesToProcess) {
14766
14476
  if (msg.type === exports.CrdtMessageType.DELETE_ENTITY) {
14767
- crdtClient.processMessage({
14768
- type: typesExports.CRDTMessageType.CRDTMT_DeleteEntity,
14769
- entityId: msg.entityId
14770
- });
14771
14477
  entitiesShouldBeCleaned.push(msg.entityId);
14772
14478
  }
14773
14479
  else {
14774
- const crdtMessage = {
14775
- type: typesExports.CRDTMessageType.CRDTMT_PutComponentData,
14776
- entityId: msg.entityId,
14777
- componentId: msg.componentId,
14778
- data: msg.type === exports.CrdtMessageType.PUT_COMPONENT ? msg.data : null,
14779
- timestamp: msg.timestamp
14780
- };
14781
14480
  const entityState = engine.entityContainer.getEntityState(msg.entityId);
14782
14481
  // Skip updates from removed entityes
14783
14482
  if (entityState === exports.EntityState.Removed)
@@ -14787,144 +14486,73 @@
14787
14486
  engine.entityContainer.updateUsedEntity(msg.entityId);
14788
14487
  }
14789
14488
  const component = engine.getComponentOrNull(msg.componentId);
14790
- // The state isn't updated because the dirty was set
14791
- // out of the block of systems update between `receiveMessage` and `updateState`
14792
- if (component?.isDirty(msg.entityId)) {
14793
- crdtClient.createComponentDataEvent(component.componentId, msg.entityId, component.toBinaryOrNull(msg.entityId)?.toBinary() || null);
14794
- }
14795
- const processResult = crdtClient.processMessage(crdtMessage);
14796
- if (!component) {
14797
- continue;
14798
- }
14799
- switch (processResult) {
14800
- case typesExports.ProcessMessageResultType.StateUpdatedTimestamp:
14801
- case typesExports.ProcessMessageResultType.StateUpdatedData:
14802
- // Add message to transport queue to be processed by others transports
14803
- broadcastMessages.push(msg);
14804
- // Process CRDT Message
14805
- if (msg.type === exports.CrdtMessageType.DELETE_COMPONENT) {
14806
- component.deleteFrom(msg.entityId, false);
14489
+ if (component) {
14490
+ const [conflictMessage] = component.updateFromCrdt(msg);
14491
+ if (conflictMessage) {
14492
+ const offset = bufferForOutdated.currentWriteOffset();
14493
+ if (conflictMessage.type === exports.CrdtMessageType.PUT_COMPONENT) {
14494
+ exports.PutComponentOperation.write(msg.entityId, conflictMessage.timestamp, conflictMessage.componentId, conflictMessage.data, bufferForOutdated);
14807
14495
  }
14808
14496
  else {
14809
- const data = new ReadWriteByteBuffer(msg.data);
14810
- component.upsertFromBinary(msg.entityId, data, false);
14497
+ exports.DeleteComponent.write(msg.entityId, component.componentId, conflictMessage.timestamp, bufferForOutdated);
14811
14498
  }
14499
+ outdatedMessages.push({
14500
+ ...msg,
14501
+ messageBuffer: bufferForOutdated.buffer().subarray(offset, bufferForOutdated.currentWriteOffset())
14502
+ });
14503
+ }
14504
+ else {
14505
+ // Add message to transport queue to be processed by others transports
14506
+ broadcastMessages.push(msg);
14812
14507
  onProcessEntityComponentChange && onProcessEntityComponentChange(msg.entityId, msg.type, component);
14813
- break;
14814
- // CRDT outdated message. Resend this message to the transport
14815
- // To do this we add this message to a queue that will be processed at the end of the update tick
14816
- case typesExports.ProcessMessageResultType.StateOutdatedData:
14817
- case typesExports.ProcessMessageResultType.StateOutdatedTimestamp:
14818
- const current = crdtClient.getState().components.get(msg.componentId)?.get(msg.entityId);
14819
- if (current) {
14820
- const offset = bufferForOutdated.currentWriteOffset();
14821
- const ts = current.timestamp;
14822
- if (component.has(msg.entityId)) {
14823
- exports.PutComponentOperation.write(msg.entityId, ts, component, bufferForOutdated);
14824
- }
14825
- else {
14826
- exports.DeleteComponent.write(msg.entityId, component.componentId, ts, bufferForOutdated);
14827
- }
14828
- outdatedMessages.push({
14829
- ...msg,
14830
- messageBuffer: bufferForOutdated.buffer().subarray(offset, bufferForOutdated.currentWriteOffset())
14831
- });
14832
- }
14833
- break;
14834
- case typesExports.ProcessMessageResultType.NoChanges:
14835
- case typesExports.ProcessMessageResultType.EntityDeleted:
14836
- case typesExports.ProcessMessageResultType.EntityWasDeleted:
14508
+ }
14837
14509
  }
14838
14510
  }
14839
14511
  }
14512
+ // the last stage of the syncrhonization is to delete the entities
14840
14513
  for (const entity of entitiesShouldBeCleaned) {
14841
14514
  // If we tried to resend outdated message and the entity was deleted before, we avoid sending them.
14842
14515
  for (let i = outdatedMessages.length - 1; i >= 0; i--) {
14843
- if (outdatedMessages[i].entityId === entity) {
14516
+ if (outdatedMessages[i].entityId === entity && outdatedMessages[i].type !== exports.CrdtMessageType.DELETE_ENTITY) {
14844
14517
  outdatedMessages.splice(i, 1);
14845
14518
  }
14846
14519
  }
14847
14520
  for (const definition of engine.componentsIter()) {
14848
- definition.deleteFrom(entity, false);
14521
+ definition.entityDeleted(entity, false);
14849
14522
  }
14850
14523
  engine.entityContainer.updateRemovedEntity(entity);
14851
14524
  onProcessEntityComponentChange && onProcessEntityComponentChange(entity, exports.CrdtMessageType.DELETE_ENTITY);
14852
14525
  }
14853
14526
  }
14854
- /**
14855
- * Updates CRDT state of the current engine dirty components
14856
- *
14857
- * TODO: optimize this function allocations using a bitmap
14858
- * TODO: unify this function with sendMessages
14859
- */
14860
- function updateState() {
14861
- const dirtyMap = new Map();
14862
- for (const component of engine.componentsIter()) {
14863
- let entitySet = null;
14864
- for (const entity of component.dirtyIterator()) {
14865
- if (!entitySet) {
14866
- entitySet = [];
14867
- dirtyMap.set(component, entitySet);
14868
- }
14869
- // TODO: reuse shared writer to prevent extra allocations of toBinary
14870
- const componentValue = component.toBinaryOrNull(entity)?.toBinary() ?? null;
14871
- // TODO: do not emit event if componentValue equals the value didn't change
14872
- // if update goes bad, the entity doesn't accept put anymore (it's added to deleted entities set)
14873
- if (crdtClient.createComponentDataEvent(component.componentId, entity, componentValue) === null) {
14874
- component.deleteFrom(entity, false);
14875
- }
14876
- else {
14877
- entitySet.push(entity);
14878
- onProcessEntityComponentChange &&
14879
- onProcessEntityComponentChange(entity, componentValue === null ? exports.CrdtMessageType.DELETE_COMPONENT : exports.CrdtMessageType.PUT_COMPONENT, component);
14880
- }
14881
- }
14882
- }
14883
- return dirtyMap;
14884
- }
14885
14527
  /**
14886
14528
  * Iterates the dirty map and generates crdt messages to be send
14887
14529
  */
14888
- async function sendMessages(dirtyEntities, deletedEntities) {
14530
+ async function sendMessages(entitiesDeletedThisTick) {
14889
14531
  // CRDT Messages will be the merge between the recieved transport messages and the new crdt messages
14890
14532
  const crdtMessages = getMessages(broadcastMessages);
14891
14533
  const outdatedMessagesBkp = getMessages(outdatedMessages);
14892
14534
  const buffer = new ReadWriteByteBuffer();
14893
- for (const [component, entities] of dirtyEntities) {
14894
- for (const entity of entities) {
14895
- // Component will be always defined here since dirtyMap its an iterator of engine.componentsDefinition
14896
- const { timestamp } = crdtClient
14897
- .getState()
14898
- .components.get(component.componentId)
14899
- .get(entity);
14535
+ for (const component of engine.componentsIter()) {
14536
+ for (const message of component.getCrdtUpdates()) {
14900
14537
  const offset = buffer.currentWriteOffset();
14901
- const type = component.has(entity)
14902
- ? exports.CrdtMessageType.PUT_COMPONENT
14903
- : exports.CrdtMessageType.DELETE_COMPONENT;
14904
- const transportMessage = {
14905
- type,
14906
- entityId: entity,
14907
- componentId: component.componentId,
14908
- timestamp
14909
- };
14910
14538
  // Avoid creating messages if there is no transport that will handle it
14911
- if (transports.some((t) => t.filter(transportMessage))) {
14912
- if (transportMessage.type === exports.CrdtMessageType.PUT_COMPONENT) {
14913
- exports.PutComponentOperation.write(entity, timestamp, component, buffer);
14539
+ if (transports.some((t) => t.filter(message))) {
14540
+ if (message.type === exports.CrdtMessageType.PUT_COMPONENT) {
14541
+ exports.PutComponentOperation.write(message.entityId, message.timestamp, message.componentId, message.data, buffer);
14914
14542
  }
14915
- else {
14916
- exports.DeleteComponent.write(entity, component.componentId, timestamp, buffer);
14543
+ else if (message.type === exports.CrdtMessageType.DELETE_COMPONENT) {
14544
+ exports.DeleteComponent.write(message.entityId, component.componentId, message.timestamp, buffer);
14917
14545
  }
14918
14546
  crdtMessages.push({
14919
- ...transportMessage,
14547
+ ...message,
14920
14548
  messageBuffer: buffer.buffer().subarray(offset, buffer.currentWriteOffset())
14921
14549
  });
14550
+ onProcessEntityComponentChange && onProcessEntityComponentChange(message.entityId, message.type, component);
14922
14551
  }
14923
14552
  }
14924
14553
  }
14925
14554
  // After all updates, I execute the DeletedEntity messages
14926
- for (const entityId of deletedEntities) {
14927
- crdtClient.createDeleteEntityEvent(entityId);
14555
+ for (const entityId of entitiesDeletedThisTick) {
14928
14556
  const offset = buffer.currentWriteOffset();
14929
14557
  exports.DeleteEntity.write(entityId, buffer);
14930
14558
  crdtMessages.push({
@@ -14932,6 +14560,7 @@
14932
14560
  entityId,
14933
14561
  messageBuffer: buffer.buffer().subarray(offset, buffer.currentWriteOffset())
14934
14562
  });
14563
+ onProcessEntityComponentChange && onProcessEntityComponentChange(entityId, exports.CrdtMessageType.DELETE_ENTITY);
14935
14564
  }
14936
14565
  // Send CRDT messages to transports
14937
14566
  const transportBuffer = new ReadWriteByteBuffer();
@@ -14970,22 +14599,53 @@
14970
14599
  const id = transports.push(transport) - 1;
14971
14600
  transport.onmessage = parseChunkMessage(id);
14972
14601
  }
14973
- /**
14974
- * @public
14975
- * @returns returns the crdt state
14976
- */
14977
- function getCrdt() {
14978
- return crdtClient.getState();
14979
- }
14980
14602
  return {
14981
- getCrdt,
14982
14603
  sendMessages,
14983
14604
  receiveMessages,
14984
- addTransport,
14985
- updateState
14605
+ addTransport
14986
14606
  };
14987
14607
  }
14988
14608
 
14609
+ var CrdtUtils;
14610
+ (function (CrdtUtils) {
14611
+ (function (SynchronizedEntityType) {
14612
+ // synchronizes entities with the NetworkSynchronized component only, used for networked games
14613
+ SynchronizedEntityType[SynchronizedEntityType["NETWORKED"] = 0] = "NETWORKED";
14614
+ // synchronizes entities needed by the renderer
14615
+ SynchronizedEntityType[SynchronizedEntityType["RENDERER"] = 1] = "RENDERER";
14616
+ })(CrdtUtils.SynchronizedEntityType || (CrdtUtils.SynchronizedEntityType = {}));
14617
+ })(CrdtUtils || (CrdtUtils = {}));
14618
+ /**
14619
+ * Compare raw data.
14620
+ * @internal
14621
+ * @returns 0 if is the same data, 1 if a > b, -1 if b > a
14622
+ */
14623
+ function dataCompare(a, b) {
14624
+ // At reference level
14625
+ if (a === b)
14626
+ return 0;
14627
+ if (a === null && b !== null)
14628
+ return -1;
14629
+ if (a !== null && b === null)
14630
+ return 1;
14631
+ if (a instanceof Uint8Array && b instanceof Uint8Array) {
14632
+ let res;
14633
+ const n = a.byteLength > b.byteLength ? b.byteLength : a.byteLength;
14634
+ for (let i = 0; i < n; i++) {
14635
+ res = a[i] - b[i];
14636
+ if (res !== 0) {
14637
+ return res > 0 ? 1 : -1;
14638
+ }
14639
+ }
14640
+ res = a.byteLength - b.byteLength;
14641
+ return res > 0 ? 1 : res < 0 ? -1 : 0;
14642
+ }
14643
+ if (typeof a === 'string') {
14644
+ return a.localeCompare(b);
14645
+ }
14646
+ return a > b ? 1 : -1;
14647
+ }
14648
+
14989
14649
  /**
14990
14650
  * @internal
14991
14651
  */
@@ -14993,12 +14653,148 @@
14993
14653
  return Object.freeze({ ...val });
14994
14654
  }
14995
14655
 
14656
+ function incrementTimestamp(entity, timestamps) {
14657
+ const newTimestamp = (timestamps.get(entity) || 0) + 1;
14658
+ timestamps.set(entity, newTimestamp);
14659
+ return newTimestamp;
14660
+ }
14661
+ function createUpdateFromCrdt(componentId, timestamps, schema, data) {
14662
+ /**
14663
+ * Process the received message only if the lamport number recieved is higher
14664
+ * than the stored one. If its lower, we spread it to the network to correct the peer.
14665
+ * If they are equal, the bigger raw data wins.
14666
+
14667
+ * Returns the recieved data if the lamport number was bigger than ours.
14668
+ * If it was an outdated message, then we return void
14669
+ * @public
14670
+ */
14671
+ function crdtRuleForCurrentState(message) {
14672
+ const { entityId, timestamp } = message;
14673
+ const currentTimestamp = timestamps.get(entityId);
14674
+ // The received message is > than our current value, update our state.components.
14675
+ if (currentTimestamp === undefined || currentTimestamp < timestamp) {
14676
+ return exports.ProcessMessageResultType.StateUpdatedTimestamp;
14677
+ }
14678
+ // Outdated Message. Resend our state message through the wire.
14679
+ if (currentTimestamp > timestamp) {
14680
+ // console.log('2', currentTimestamp, timestamp)
14681
+ return exports.ProcessMessageResultType.StateOutdatedTimestamp;
14682
+ }
14683
+ // Deletes are idempotent
14684
+ if (message.type === exports.CrdtMessageType.DELETE_COMPONENT && !data.has(entityId)) {
14685
+ return exports.ProcessMessageResultType.NoChanges;
14686
+ }
14687
+ let currentDataGreater = 0;
14688
+ if (data.has(entityId)) {
14689
+ const writeBuffer = new ReadWriteByteBuffer();
14690
+ schema.serialize(data.get(entityId), writeBuffer);
14691
+ currentDataGreater = dataCompare(writeBuffer.toBinary(), message.data || null);
14692
+ }
14693
+ else {
14694
+ currentDataGreater = dataCompare(null, message.data);
14695
+ }
14696
+ // Same data, same timestamp. Weirdo echo message.
14697
+ // console.log('3', currentDataGreater, writeBuffer.toBinary(), (message as any).data || null)
14698
+ if (currentDataGreater === 0) {
14699
+ return exports.ProcessMessageResultType.NoChanges;
14700
+ }
14701
+ else if (currentDataGreater > 0) {
14702
+ // Current data is greater
14703
+ return exports.ProcessMessageResultType.StateOutdatedData;
14704
+ }
14705
+ else {
14706
+ // Curent data is lower
14707
+ return exports.ProcessMessageResultType.StateUpdatedData;
14708
+ }
14709
+ }
14710
+ return (msg) => {
14711
+ /* istanbul ignore next */
14712
+ if (msg.type !== exports.CrdtMessageType.PUT_COMPONENT && msg.type !== exports.CrdtMessageType.DELETE_COMPONENT)
14713
+ /* istanbul ignore next */
14714
+ return [null, data.get(msg.entityId)];
14715
+ const action = crdtRuleForCurrentState(msg);
14716
+ const entity = msg.entityId;
14717
+ switch (action) {
14718
+ case exports.ProcessMessageResultType.StateUpdatedData:
14719
+ case exports.ProcessMessageResultType.StateUpdatedTimestamp: {
14720
+ timestamps.set(entity, msg.timestamp);
14721
+ if (msg.type === exports.CrdtMessageType.PUT_COMPONENT) {
14722
+ const buf = new ReadWriteByteBuffer(msg.data);
14723
+ data.set(entity, schema.deserialize(buf));
14724
+ }
14725
+ else {
14726
+ data.delete(entity);
14727
+ }
14728
+ return [null, data.get(entity)];
14729
+ }
14730
+ case exports.ProcessMessageResultType.StateOutdatedTimestamp:
14731
+ case exports.ProcessMessageResultType.StateOutdatedData: {
14732
+ if (data.has(entity)) {
14733
+ const writeBuffer = new ReadWriteByteBuffer();
14734
+ schema.serialize(data.get(entity), writeBuffer);
14735
+ return [
14736
+ {
14737
+ type: exports.CrdtMessageType.PUT_COMPONENT,
14738
+ componentId,
14739
+ data: writeBuffer.toBinary(),
14740
+ entityId: entity,
14741
+ timestamp: timestamps.get(entity)
14742
+ },
14743
+ data.get(entity)
14744
+ ];
14745
+ }
14746
+ else {
14747
+ return [
14748
+ {
14749
+ type: exports.CrdtMessageType.DELETE_COMPONENT,
14750
+ componentId,
14751
+ entityId: entity,
14752
+ timestamp: timestamps.get(entity)
14753
+ },
14754
+ undefined
14755
+ ];
14756
+ }
14757
+ }
14758
+ }
14759
+ return [null, data.get(entity)];
14760
+ };
14761
+ }
14762
+ function createGetCrdtMessages(componentId, timestamps, dirtyIterator, schema, data) {
14763
+ return function* () {
14764
+ for (const entity of dirtyIterator) {
14765
+ const newTimestamp = incrementTimestamp(entity, timestamps);
14766
+ if (data.has(entity)) {
14767
+ const writeBuffer = new ReadWriteByteBuffer();
14768
+ schema.serialize(data.get(entity), writeBuffer);
14769
+ const msg = {
14770
+ type: exports.CrdtMessageType.PUT_COMPONENT,
14771
+ componentId,
14772
+ entityId: entity,
14773
+ data: writeBuffer.toBinary(),
14774
+ timestamp: newTimestamp
14775
+ };
14776
+ yield msg;
14777
+ }
14778
+ else {
14779
+ const msg = {
14780
+ type: exports.CrdtMessageType.DELETE_COMPONENT,
14781
+ componentId,
14782
+ entityId: entity,
14783
+ timestamp: newTimestamp
14784
+ };
14785
+ yield msg;
14786
+ }
14787
+ }
14788
+ dirtyIterator.clear();
14789
+ };
14790
+ }
14996
14791
  /**
14997
14792
  * @internal
14998
14793
  */
14999
14794
  function createComponentDefinitionFromSchema(componentName, componentId, schema) {
15000
14795
  const data = new Map();
15001
14796
  const dirtyIterator = new Set();
14797
+ const timestamps = new Map();
15002
14798
  return {
15003
14799
  get componentId() {
15004
14800
  return componentId;
@@ -15017,15 +14813,16 @@
15017
14813
  },
15018
14814
  deleteFrom(entity, markAsDirty = true) {
15019
14815
  const component = data.get(entity);
15020
- data.delete(entity);
15021
- if (markAsDirty) {
14816
+ if (data.delete(entity) && markAsDirty) {
15022
14817
  dirtyIterator.add(entity);
15023
14818
  }
15024
- else {
15025
- dirtyIterator.delete(entity);
15026
- }
15027
14819
  return component || null;
15028
14820
  },
14821
+ entityDeleted(entity, markAsDirty) {
14822
+ if (data.delete(entity) && markAsDirty) {
14823
+ dirtyIterator.add(entity);
14824
+ }
14825
+ },
15029
14826
  getOrNull(entity) {
15030
14827
  const component = data.get(entity);
15031
14828
  return component ? deepReadonly(component) : null;
@@ -15078,6 +14875,7 @@
15078
14875
  yield entity;
15079
14876
  }
15080
14877
  },
14878
+ getCrdtUpdates: createGetCrdtMessages(componentId, timestamps, dirtyIterator, schema, data),
15081
14879
  toBinary(entity) {
15082
14880
  const component = data.get(entity);
15083
14881
  if (!component) {
@@ -15087,45 +14885,9 @@
15087
14885
  schema.serialize(component, writeBuffer);
15088
14886
  return writeBuffer;
15089
14887
  },
15090
- toBinaryOrNull(entity) {
15091
- const component = data.get(entity);
15092
- if (!component) {
15093
- return null;
15094
- }
15095
- const writeBuffer = new ReadWriteByteBuffer();
15096
- schema.serialize(component, writeBuffer);
15097
- return writeBuffer;
15098
- },
15099
- writeToByteBuffer(entity, buffer) {
15100
- const component = data.get(entity);
15101
- if (!component) {
15102
- throw new Error(`[writeToByteBuffer] Component ${componentName} for entity #${entity} not found`);
15103
- }
15104
- schema.serialize(component, buffer);
15105
- },
15106
- updateFromBinary(entity, buffer, markAsDirty = true) {
15107
- const component = data.get(entity);
15108
- if (!component) {
15109
- throw new Error(`[updateFromBinary] Component ${componentName} for ${entity} not found`);
15110
- }
15111
- return this.upsertFromBinary(entity, buffer, markAsDirty);
15112
- },
15113
- upsertFromBinary(entity, buffer, markAsDirty = true) {
15114
- const newValue = schema.deserialize(buffer);
15115
- data.set(entity, newValue);
15116
- if (markAsDirty) {
15117
- dirtyIterator.add(entity);
15118
- }
15119
- else {
15120
- dirtyIterator.delete(entity);
15121
- }
15122
- return newValue;
15123
- },
14888
+ updateFromCrdt: createUpdateFromCrdt(componentId, timestamps, schema, data),
15124
14889
  deserialize(buffer) {
15125
14890
  return schema.deserialize(buffer);
15126
- },
15127
- clearDirty() {
15128
- dirtyIterator.clear();
15129
14891
  }
15130
14892
  };
15131
14893
  }
@@ -15346,9 +15108,7 @@
15346
15108
  }
15347
15109
  function removeEntity(entity) {
15348
15110
  for (const [, component] of componentsDefinition) {
15349
- if (component.has(entity)) {
15350
- component.deleteFrom(entity);
15351
- }
15111
+ component.entityDeleted(entity, true);
15352
15112
  }
15353
15113
  return entityContainer.removeEntity(entity);
15354
15114
  }
@@ -15504,12 +15264,9 @@
15504
15264
  const ret = system.fn(dt);
15505
15265
  checkNotThenable(ret, `A system (${system.name || 'anonymous'}) returned a thenable. Systems cannot be async functions. Documentation: https://dcl.gg/sdk/sync-systems`);
15506
15266
  }
15507
- const dirtyEntities = crdtSystem.updateState();
15267
+ // get the deleted entities to send the DeleteEntity CRDT commands
15508
15268
  const deletedEntites = partialEngine.entityContainer.releaseRemovedEntities();
15509
- await crdtSystem.sendMessages(dirtyEntities, deletedEntites);
15510
- for (const definition of partialEngine.componentsIter()) {
15511
- definition.clearDirty();
15512
- }
15269
+ await crdtSystem.sendMessages(deletedEntites);
15513
15270
  }
15514
15271
  return {
15515
15272
  addEntity: partialEngine.addEntity,
@@ -15532,7 +15289,6 @@
15532
15289
  CameraEntity: 2,
15533
15290
  getEntityState: partialEngine.entityContainer.getEntityState,
15534
15291
  addTransport: crdtSystem.addTransport,
15535
- getCrdtState: crdtSystem.getCrdt,
15536
15292
  entityContainer: partialEngine.entityContainer
15537
15293
  };
15538
15294
  }
@@ -42525,14 +42281,17 @@
42525
42281
  exports.components = index;
42526
42282
  exports.createComponentDefinitionFromSchema = createComponentDefinitionFromSchema;
42527
42283
  exports.createEthereumProvider = createEthereumProvider;
42284
+ exports.createGetCrdtMessages = createGetCrdtMessages;
42528
42285
  exports.createInputSystem = createInputSystem;
42529
42286
  exports.createPointerEventSystem = createPointerEventSystem;
42530
42287
  exports.createReactBasedUiSystem = createReactBasedUiSystem;
42531
42288
  exports.createTaskSystem = createTaskSystem;
42289
+ exports.createUpdateFromCrdt = createUpdateFromCrdt;
42532
42290
  exports.cyclicParentingChecker = cyclicParentingChecker;
42533
42291
  exports.deepReadonly = deepReadonly;
42534
42292
  exports.engine = engine;
42535
42293
  exports.executeTask = executeTask;
42294
+ exports.incrementTimestamp = incrementTimestamp;
42536
42295
  exports.inputSystem = inputSystem;
42537
42296
  exports.isListener = isListener;
42538
42297
  exports.onCommsMessage = onCommsMessage;