@dcl/ecs 7.28.0 → 7.28.1-34502200570.commit-e3d4af5

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.
@@ -25,6 +25,16 @@ export function createPointerEventsSystem(engine, inputSystem) {
25
25
  function getEvent(entity) {
26
26
  return eventsMap.get(entity) || eventsMap.set(entity, new Map()).get(entity);
27
27
  }
28
+ // A cursor handler and a proximity handler are separate registrations that
29
+ // produce separate PointerEvents entries, so they need separate slots here
30
+ // too. Keying on the event type alone made onProximityDown evict whatever
31
+ // onPointerDown had left.
32
+ function eventKey(type, interactionType) {
33
+ return `${type}:${interactionType}`;
34
+ }
35
+ function setEvent(entity, type, cb, opts, interactionType = 0 /* InteractionType.CURSOR */) {
36
+ getEvent(entity).set(eventKey(type, interactionType), { cb, opts, eventType: type });
37
+ }
28
38
  function setPointerEvent(entity, type, opts, interactionType = 0 /* InteractionType.CURSOR */) {
29
39
  const pointerEvent = PointerEvents.getMutableOrNull(entity) || PointerEvents.create(entity);
30
40
  pointerEvent.pointerEvents.push({
@@ -42,13 +52,27 @@ export function createPointerEventsSystem(engine, inputSystem) {
42
52
  interactionType: interactionType ?? 0 /* InteractionType.CURSOR */
43
53
  });
44
54
  }
45
- function removePointerEvent(entity, type, button, interactionType = 0 /* InteractionType.CURSOR */) {
55
+ function removePointerEvent(entity, type, opts, interactionType = 0 /* InteractionType.CURSOR */) {
46
56
  const pointerEvent = PointerEvents.getMutableOrNull(entity);
47
57
  if (!pointerEvent)
48
58
  return;
49
- pointerEvent.pointerEvents = pointerEvent.pointerEvents.filter((pointer) => !(pointer.eventInfo?.button === button &&
50
- pointer.eventType === type &&
51
- pointer.interactionType === interactionType));
59
+ const sameSlot = (pointer) => pointer.eventType === type && pointer.interactionType === interactionType;
60
+ // onClick and onPointerDown both describe themselves as PET_DOWN, so the event
61
+ // type and button alone do not say which registration an entry belongs to. Match
62
+ // everything the entry was built from, or removing one handler can take the
63
+ // other's descriptor and leave the renderer advertising the wrong interaction.
64
+ const index = pointerEvent.pointerEvents.findIndex((pointer) => sameSlot(pointer) &&
65
+ pointer.eventInfo?.button === opts.button &&
66
+ pointer.eventInfo?.hoverText === opts.hoverText &&
67
+ pointer.eventInfo?.showFeedback === opts.showFeedback &&
68
+ pointer.eventInfo?.showHighlight === opts.showHighlight &&
69
+ pointer.eventInfo?.maxDistance === opts.maxDistance &&
70
+ pointer.eventInfo?.maxPlayerDistance === opts.maxPlayerDistance &&
71
+ pointer.eventInfo?.priority === opts.priority &&
72
+ pointer.eventInfo?.maxCameraDistance === opts.maxCameraDistance);
73
+ if (index === -1)
74
+ return;
75
+ pointerEvent.pointerEvents.splice(index, 1);
52
76
  }
53
77
  function getPointerEvent(eventType) {
54
78
  if (eventType === EventType.Up) {
@@ -70,11 +94,16 @@ export function createPointerEventsSystem(engine, inputSystem) {
70
94
  }
71
95
  function removeEvent(entity, type, interactionType = 0 /* InteractionType.CURSOR */) {
72
96
  const event = getEvent(entity);
73
- const pointerEvent = event.get(type);
74
- if (pointerEvent?.opts.hoverText) {
75
- removePointerEvent(entity, getPointerEvent(type), pointerEvent.opts.button);
97
+ const key = eventKey(type, interactionType);
98
+ const pointerEvent = event.get(key);
99
+ // Every registration adds an entry, not only the ones carrying a hoverText,
100
+ // so every removal has to take one away. Gating on hoverText left the
101
+ // renderer showing an interaction whose callback was already gone, and made
102
+ // re-registering grow the component by one entry each time.
103
+ if (pointerEvent) {
104
+ removePointerEvent(entity, getPointerEvent(type), pointerEvent.opts, interactionType);
76
105
  }
77
- event.delete(type);
106
+ event.delete(key);
78
107
  }
79
108
  engine.addSystem(function PointerEventSystem() {
80
109
  for (const [entity, event] of eventsMap) {
@@ -82,7 +111,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
82
111
  eventsMap.delete(entity);
83
112
  continue;
84
113
  }
85
- for (const [eventType, { cb, opts }] of event) {
114
+ for (const [, { cb, opts, eventType }] of event) {
86
115
  if (eventType === EventType.Click) {
87
116
  const command = inputSystem.getClick(opts.button, entity);
88
117
  if (command)
@@ -110,7 +139,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
110
139
  const { entity, opts } = data;
111
140
  const options = getDefaultOpts(opts);
112
141
  removeEvent(entity, EventType.Down);
113
- getEvent(entity).set(EventType.Down, { cb, opts: options });
142
+ setEvent(entity, EventType.Down, cb, options);
114
143
  setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options);
115
144
  };
116
145
  const onPointerUp = (...args) => {
@@ -121,7 +150,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
121
150
  const { entity, opts } = data;
122
151
  const options = getDefaultOpts(opts);
123
152
  removeEvent(entity, EventType.Up);
124
- getEvent(entity).set(EventType.Up, { cb, opts: options });
153
+ setEvent(entity, EventType.Up, cb, options);
125
154
  setPointerEvent(entity, 0 /* PointerEventType.PET_UP */, options);
126
155
  };
127
156
  const onPointerHoverEnter = (...args) => {
@@ -129,7 +158,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
129
158
  const { entity, opts } = data;
130
159
  const options = getDefaultOpts(opts);
131
160
  removeEvent(entity, EventType.HoverEnter);
132
- getEvent(entity).set(EventType.HoverEnter, { cb, opts: options });
161
+ setEvent(entity, EventType.HoverEnter, cb, options);
133
162
  setPointerEvent(entity, 2 /* PointerEventType.PET_HOVER_ENTER */, options);
134
163
  };
135
164
  const onPointerHoverLeave = (...args) => {
@@ -137,7 +166,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
137
166
  const { entity, opts } = data;
138
167
  const options = getDefaultOpts(opts);
139
168
  removeEvent(entity, EventType.HoverLeave);
140
- getEvent(entity).set(EventType.HoverLeave, { cb, opts: options });
169
+ setEvent(entity, EventType.HoverLeave, cb, options);
141
170
  setPointerEvent(entity, 3 /* PointerEventType.PET_HOVER_LEAVE */, options);
142
171
  };
143
172
  const onProximityDown = (...args) => {
@@ -145,7 +174,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
145
174
  const { entity, opts } = data;
146
175
  const options = getDefaultOpts(opts);
147
176
  removeEvent(entity, EventType.Down, 1 /* InteractionType.PROXIMITY */);
148
- getEvent(entity).set(EventType.Down, { cb, opts: options });
177
+ setEvent(entity, EventType.Down, cb, options, 1 /* InteractionType.PROXIMITY */);
149
178
  setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options, 1 /* InteractionType.PROXIMITY */);
150
179
  };
151
180
  const onProximityUp = (...args) => {
@@ -153,7 +182,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
153
182
  const { entity, opts } = data;
154
183
  const options = getDefaultOpts(opts);
155
184
  removeEvent(entity, EventType.Up, 1 /* InteractionType.PROXIMITY */);
156
- getEvent(entity).set(EventType.Up, { cb, opts: options });
185
+ setEvent(entity, EventType.Up, cb, options, 1 /* InteractionType.PROXIMITY */);
157
186
  setPointerEvent(entity, 0 /* PointerEventType.PET_UP */, options, 1 /* InteractionType.PROXIMITY */);
158
187
  };
159
188
  const onProximityEnter = (...args) => {
@@ -161,7 +190,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
161
190
  const { entity, opts } = data;
162
191
  const options = getDefaultOpts(opts);
163
192
  removeEvent(entity, EventType.ProximityEnter, 1 /* InteractionType.PROXIMITY */);
164
- getEvent(entity).set(EventType.ProximityEnter, { cb, opts: options });
193
+ setEvent(entity, EventType.ProximityEnter, cb, options, 1 /* InteractionType.PROXIMITY */);
165
194
  setPointerEvent(entity, 4 /* PointerEventType.PET_PROXIMITY_ENTER */, options, 1 /* InteractionType.PROXIMITY */);
166
195
  };
167
196
  const onProximityLeave = (...args) => {
@@ -169,7 +198,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
169
198
  const { entity, opts } = data;
170
199
  const options = getDefaultOpts(opts);
171
200
  removeEvent(entity, EventType.ProximityLeave, 1 /* InteractionType.PROXIMITY */);
172
- getEvent(entity).set(EventType.ProximityLeave, { cb, opts: options });
201
+ setEvent(entity, EventType.ProximityLeave, cb, options, 1 /* InteractionType.PROXIMITY */);
173
202
  setPointerEvent(entity, 5 /* PointerEventType.PET_PROXIMITY_LEAVE */, options, 1 /* InteractionType.PROXIMITY */);
174
203
  };
175
204
  return {
@@ -206,7 +235,7 @@ export function createPointerEventsSystem(engine, inputSystem) {
206
235
  // Clear previous event with over feedback included
207
236
  removeEvent(entity, EventType.Click);
208
237
  // Set new event
209
- getEvent(entity).set(EventType.Click, { cb, opts: options });
238
+ setEvent(entity, EventType.Click, cb, options);
210
239
  setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options);
211
240
  },
212
241
  onPointerDown,
@@ -52,6 +52,16 @@ function createPointerEventsSystem(engine, inputSystem) {
52
52
  function getEvent(entity) {
53
53
  return eventsMap.get(entity) || eventsMap.set(entity, new Map()).get(entity);
54
54
  }
55
+ // A cursor handler and a proximity handler are separate registrations that
56
+ // produce separate PointerEvents entries, so they need separate slots here
57
+ // too. Keying on the event type alone made onProximityDown evict whatever
58
+ // onPointerDown had left.
59
+ function eventKey(type, interactionType) {
60
+ return `${type}:${interactionType}`;
61
+ }
62
+ function setEvent(entity, type, cb, opts, interactionType = 0 /* InteractionType.CURSOR */) {
63
+ getEvent(entity).set(eventKey(type, interactionType), { cb, opts, eventType: type });
64
+ }
55
65
  function setPointerEvent(entity, type, opts, interactionType = 0 /* InteractionType.CURSOR */) {
56
66
  const pointerEvent = PointerEvents.getMutableOrNull(entity) || PointerEvents.create(entity);
57
67
  pointerEvent.pointerEvents.push({
@@ -69,13 +79,27 @@ function createPointerEventsSystem(engine, inputSystem) {
69
79
  interactionType: interactionType ?? 0 /* InteractionType.CURSOR */
70
80
  });
71
81
  }
72
- function removePointerEvent(entity, type, button, interactionType = 0 /* InteractionType.CURSOR */) {
82
+ function removePointerEvent(entity, type, opts, interactionType = 0 /* InteractionType.CURSOR */) {
73
83
  const pointerEvent = PointerEvents.getMutableOrNull(entity);
74
84
  if (!pointerEvent)
75
85
  return;
76
- pointerEvent.pointerEvents = pointerEvent.pointerEvents.filter((pointer) => !(pointer.eventInfo?.button === button &&
77
- pointer.eventType === type &&
78
- pointer.interactionType === interactionType));
86
+ const sameSlot = (pointer) => pointer.eventType === type && pointer.interactionType === interactionType;
87
+ // onClick and onPointerDown both describe themselves as PET_DOWN, so the event
88
+ // type and button alone do not say which registration an entry belongs to. Match
89
+ // everything the entry was built from, or removing one handler can take the
90
+ // other's descriptor and leave the renderer advertising the wrong interaction.
91
+ const index = pointerEvent.pointerEvents.findIndex((pointer) => sameSlot(pointer) &&
92
+ pointer.eventInfo?.button === opts.button &&
93
+ pointer.eventInfo?.hoverText === opts.hoverText &&
94
+ pointer.eventInfo?.showFeedback === opts.showFeedback &&
95
+ pointer.eventInfo?.showHighlight === opts.showHighlight &&
96
+ pointer.eventInfo?.maxDistance === opts.maxDistance &&
97
+ pointer.eventInfo?.maxPlayerDistance === opts.maxPlayerDistance &&
98
+ pointer.eventInfo?.priority === opts.priority &&
99
+ pointer.eventInfo?.maxCameraDistance === opts.maxCameraDistance);
100
+ if (index === -1)
101
+ return;
102
+ pointerEvent.pointerEvents.splice(index, 1);
79
103
  }
80
104
  function getPointerEvent(eventType) {
81
105
  if (eventType === EventType.Up) {
@@ -97,11 +121,16 @@ function createPointerEventsSystem(engine, inputSystem) {
97
121
  }
98
122
  function removeEvent(entity, type, interactionType = 0 /* InteractionType.CURSOR */) {
99
123
  const event = getEvent(entity);
100
- const pointerEvent = event.get(type);
101
- if (pointerEvent?.opts.hoverText) {
102
- removePointerEvent(entity, getPointerEvent(type), pointerEvent.opts.button);
124
+ const key = eventKey(type, interactionType);
125
+ const pointerEvent = event.get(key);
126
+ // Every registration adds an entry, not only the ones carrying a hoverText,
127
+ // so every removal has to take one away. Gating on hoverText left the
128
+ // renderer showing an interaction whose callback was already gone, and made
129
+ // re-registering grow the component by one entry each time.
130
+ if (pointerEvent) {
131
+ removePointerEvent(entity, getPointerEvent(type), pointerEvent.opts, interactionType);
103
132
  }
104
- event.delete(type);
133
+ event.delete(key);
105
134
  }
106
135
  engine.addSystem(function PointerEventSystem() {
107
136
  for (const [entity, event] of eventsMap) {
@@ -109,7 +138,7 @@ function createPointerEventsSystem(engine, inputSystem) {
109
138
  eventsMap.delete(entity);
110
139
  continue;
111
140
  }
112
- for (const [eventType, { cb, opts }] of event) {
141
+ for (const [, { cb, opts, eventType }] of event) {
113
142
  if (eventType === EventType.Click) {
114
143
  const command = inputSystem.getClick(opts.button, entity);
115
144
  if (command)
@@ -137,7 +166,7 @@ function createPointerEventsSystem(engine, inputSystem) {
137
166
  const { entity, opts } = data;
138
167
  const options = (0, exports.getDefaultOpts)(opts);
139
168
  removeEvent(entity, EventType.Down);
140
- getEvent(entity).set(EventType.Down, { cb, opts: options });
169
+ setEvent(entity, EventType.Down, cb, options);
141
170
  setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options);
142
171
  };
143
172
  const onPointerUp = (...args) => {
@@ -148,7 +177,7 @@ function createPointerEventsSystem(engine, inputSystem) {
148
177
  const { entity, opts } = data;
149
178
  const options = (0, exports.getDefaultOpts)(opts);
150
179
  removeEvent(entity, EventType.Up);
151
- getEvent(entity).set(EventType.Up, { cb, opts: options });
180
+ setEvent(entity, EventType.Up, cb, options);
152
181
  setPointerEvent(entity, 0 /* PointerEventType.PET_UP */, options);
153
182
  };
154
183
  const onPointerHoverEnter = (...args) => {
@@ -156,7 +185,7 @@ function createPointerEventsSystem(engine, inputSystem) {
156
185
  const { entity, opts } = data;
157
186
  const options = (0, exports.getDefaultOpts)(opts);
158
187
  removeEvent(entity, EventType.HoverEnter);
159
- getEvent(entity).set(EventType.HoverEnter, { cb, opts: options });
188
+ setEvent(entity, EventType.HoverEnter, cb, options);
160
189
  setPointerEvent(entity, 2 /* PointerEventType.PET_HOVER_ENTER */, options);
161
190
  };
162
191
  const onPointerHoverLeave = (...args) => {
@@ -164,7 +193,7 @@ function createPointerEventsSystem(engine, inputSystem) {
164
193
  const { entity, opts } = data;
165
194
  const options = (0, exports.getDefaultOpts)(opts);
166
195
  removeEvent(entity, EventType.HoverLeave);
167
- getEvent(entity).set(EventType.HoverLeave, { cb, opts: options });
196
+ setEvent(entity, EventType.HoverLeave, cb, options);
168
197
  setPointerEvent(entity, 3 /* PointerEventType.PET_HOVER_LEAVE */, options);
169
198
  };
170
199
  const onProximityDown = (...args) => {
@@ -172,7 +201,7 @@ function createPointerEventsSystem(engine, inputSystem) {
172
201
  const { entity, opts } = data;
173
202
  const options = (0, exports.getDefaultOpts)(opts);
174
203
  removeEvent(entity, EventType.Down, 1 /* InteractionType.PROXIMITY */);
175
- getEvent(entity).set(EventType.Down, { cb, opts: options });
204
+ setEvent(entity, EventType.Down, cb, options, 1 /* InteractionType.PROXIMITY */);
176
205
  setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options, 1 /* InteractionType.PROXIMITY */);
177
206
  };
178
207
  const onProximityUp = (...args) => {
@@ -180,7 +209,7 @@ function createPointerEventsSystem(engine, inputSystem) {
180
209
  const { entity, opts } = data;
181
210
  const options = (0, exports.getDefaultOpts)(opts);
182
211
  removeEvent(entity, EventType.Up, 1 /* InteractionType.PROXIMITY */);
183
- getEvent(entity).set(EventType.Up, { cb, opts: options });
212
+ setEvent(entity, EventType.Up, cb, options, 1 /* InteractionType.PROXIMITY */);
184
213
  setPointerEvent(entity, 0 /* PointerEventType.PET_UP */, options, 1 /* InteractionType.PROXIMITY */);
185
214
  };
186
215
  const onProximityEnter = (...args) => {
@@ -188,7 +217,7 @@ function createPointerEventsSystem(engine, inputSystem) {
188
217
  const { entity, opts } = data;
189
218
  const options = (0, exports.getDefaultOpts)(opts);
190
219
  removeEvent(entity, EventType.ProximityEnter, 1 /* InteractionType.PROXIMITY */);
191
- getEvent(entity).set(EventType.ProximityEnter, { cb, opts: options });
220
+ setEvent(entity, EventType.ProximityEnter, cb, options, 1 /* InteractionType.PROXIMITY */);
192
221
  setPointerEvent(entity, 4 /* PointerEventType.PET_PROXIMITY_ENTER */, options, 1 /* InteractionType.PROXIMITY */);
193
222
  };
194
223
  const onProximityLeave = (...args) => {
@@ -196,7 +225,7 @@ function createPointerEventsSystem(engine, inputSystem) {
196
225
  const { entity, opts } = data;
197
226
  const options = (0, exports.getDefaultOpts)(opts);
198
227
  removeEvent(entity, EventType.ProximityLeave, 1 /* InteractionType.PROXIMITY */);
199
- getEvent(entity).set(EventType.ProximityLeave, { cb, opts: options });
228
+ setEvent(entity, EventType.ProximityLeave, cb, options, 1 /* InteractionType.PROXIMITY */);
200
229
  setPointerEvent(entity, 5 /* PointerEventType.PET_PROXIMITY_LEAVE */, options, 1 /* InteractionType.PROXIMITY */);
201
230
  };
202
231
  return {
@@ -233,7 +262,7 @@ function createPointerEventsSystem(engine, inputSystem) {
233
262
  // Clear previous event with over feedback included
234
263
  removeEvent(entity, EventType.Click);
235
264
  // Set new event
236
- getEvent(entity).set(EventType.Click, { cb, opts: options });
265
+ setEvent(entity, EventType.Click, cb, options);
237
266
  setPointerEvent(entity, 1 /* PointerEventType.PET_DOWN */, options);
238
267
  },
239
268
  onPointerDown,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dcl/ecs",
3
3
  "description": "Decentraland ECS",
4
- "version": "7.28.0",
4
+ "version": "7.28.1-34502200570.commit-e3d4af5",
5
5
  "author": "DCL",
6
6
  "bugs": "https://github.com/decentraland/ecs/issues",
7
7
  "files": [
@@ -34,5 +34,5 @@
34
34
  "dependencies": {},
35
35
  "types": "./dist/index.d.ts",
36
36
  "typings": "./dist/index.d.ts",
37
- "commit": "2a59cb6c6005b4f6b5c2391d6138778e85e1ae65"
37
+ "commit": "e3d4af57313819bf28e079e08a9e9e44385c7876"
38
38
  }