@dcl/ecs 7.24.1 → 7.24.2-27638397160.commit-401ee50

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.
@@ -20,47 +20,59 @@
20
20
  export function createTimers(targetEngine) {
21
21
  const timers = new Map();
22
22
  let timerIdCounter = 0;
23
+ // While a timer's callback is running this holds the time already consumed this
24
+ // frame before that timer's logical fire instant (`elapsedMs - residualMs`);
25
+ // `null` otherwise. A timer armed from within the callback is seeded with the
26
+ // negative of this, so its delay is measured from the parent's fire instant
27
+ // rather than from the start of the frame.
28
+ let armContext = null;
23
29
  function system(dt) {
30
+ const elapsedMs = 1000 * dt;
24
31
  for (const [timerId, timerData] of timers) {
25
- timerData.accumulatedTime += 1000 * dt;
32
+ timerData.accumulatedTime += elapsedMs;
26
33
  if (timerData.accumulatedTime < timerData.interval) {
27
34
  continue;
28
35
  }
36
+ // Time elapsed past this timer's logical fire instant this frame.
37
+ const residualMs = timerData.recurrent
38
+ ? timerData.accumulatedTime % timerData.interval
39
+ : timerData.accumulatedTime - timerData.interval;
29
40
  if (timerData.recurrent) {
30
- // For intervals, subtract full interval periods to handle accumulated time
31
- const fullIntervals = Math.floor(timerData.accumulatedTime / timerData.interval);
32
- timerData.accumulatedTime -= fullIntervals * timerData.interval;
41
+ // Collapse any missed periods into a single callback, keep the remainder.
42
+ timerData.accumulatedTime = residualMs;
33
43
  }
34
44
  else {
35
45
  timers.delete(timerId);
36
46
  }
47
+ armContext = { accruedMs: elapsedMs - residualMs };
37
48
  timerData.callback();
49
+ armContext = null;
38
50
  }
39
51
  }
40
52
  targetEngine.addSystem(system, Number.MAX_SAFE_INTEGER, '@dcl/ecs/timers');
53
+ function addTimer(callback, interval, recurrent) {
54
+ const timerId = timerIdCounter++;
55
+ let accumulatedTime = 0;
56
+ if (armContext) {
57
+ // Armed from inside a firing callback: this timer is appended to the map
58
+ // being iterated, so the loop will still add this frame's elapsed to it.
59
+ // Inherit the residual so that `+= elapsedMs` nets to the true time
60
+ // elapsed since the parent fired (phase-accurate). Each successive arming
61
+ // starts one interval lower, so a re-arming chain terminates this frame.
62
+ accumulatedTime = -armContext.accruedMs;
63
+ }
64
+ timers.set(timerId, { callback, interval, recurrent, accumulatedTime });
65
+ return timerId;
66
+ }
41
67
  return {
42
68
  setTimeout(callback, ms) {
43
- const timerId = timerIdCounter++;
44
- timers.set(timerId, {
45
- callback,
46
- interval: ms,
47
- recurrent: false,
48
- accumulatedTime: 0
49
- });
50
- return timerId;
69
+ return addTimer(callback, ms, false);
51
70
  },
52
71
  clearTimeout(timerId) {
53
72
  timers.delete(timerId);
54
73
  },
55
74
  setInterval(callback, ms) {
56
- const timerId = timerIdCounter++;
57
- timers.set(timerId, {
58
- callback,
59
- interval: ms,
60
- recurrent: true,
61
- accumulatedTime: 0
62
- });
63
- return timerId;
75
+ return addTimer(callback, ms, true);
64
76
  },
65
77
  clearInterval(timerId) {
66
78
  timers.delete(timerId);
@@ -23,47 +23,59 @@ exports.createTimers = void 0;
23
23
  function createTimers(targetEngine) {
24
24
  const timers = new Map();
25
25
  let timerIdCounter = 0;
26
+ // While a timer's callback is running this holds the time already consumed this
27
+ // frame before that timer's logical fire instant (`elapsedMs - residualMs`);
28
+ // `null` otherwise. A timer armed from within the callback is seeded with the
29
+ // negative of this, so its delay is measured from the parent's fire instant
30
+ // rather than from the start of the frame.
31
+ let armContext = null;
26
32
  function system(dt) {
33
+ const elapsedMs = 1000 * dt;
27
34
  for (const [timerId, timerData] of timers) {
28
- timerData.accumulatedTime += 1000 * dt;
35
+ timerData.accumulatedTime += elapsedMs;
29
36
  if (timerData.accumulatedTime < timerData.interval) {
30
37
  continue;
31
38
  }
39
+ // Time elapsed past this timer's logical fire instant this frame.
40
+ const residualMs = timerData.recurrent
41
+ ? timerData.accumulatedTime % timerData.interval
42
+ : timerData.accumulatedTime - timerData.interval;
32
43
  if (timerData.recurrent) {
33
- // For intervals, subtract full interval periods to handle accumulated time
34
- const fullIntervals = Math.floor(timerData.accumulatedTime / timerData.interval);
35
- timerData.accumulatedTime -= fullIntervals * timerData.interval;
44
+ // Collapse any missed periods into a single callback, keep the remainder.
45
+ timerData.accumulatedTime = residualMs;
36
46
  }
37
47
  else {
38
48
  timers.delete(timerId);
39
49
  }
50
+ armContext = { accruedMs: elapsedMs - residualMs };
40
51
  timerData.callback();
52
+ armContext = null;
41
53
  }
42
54
  }
43
55
  targetEngine.addSystem(system, Number.MAX_SAFE_INTEGER, '@dcl/ecs/timers');
56
+ function addTimer(callback, interval, recurrent) {
57
+ const timerId = timerIdCounter++;
58
+ let accumulatedTime = 0;
59
+ if (armContext) {
60
+ // Armed from inside a firing callback: this timer is appended to the map
61
+ // being iterated, so the loop will still add this frame's elapsed to it.
62
+ // Inherit the residual so that `+= elapsedMs` nets to the true time
63
+ // elapsed since the parent fired (phase-accurate). Each successive arming
64
+ // starts one interval lower, so a re-arming chain terminates this frame.
65
+ accumulatedTime = -armContext.accruedMs;
66
+ }
67
+ timers.set(timerId, { callback, interval, recurrent, accumulatedTime });
68
+ return timerId;
69
+ }
44
70
  return {
45
71
  setTimeout(callback, ms) {
46
- const timerId = timerIdCounter++;
47
- timers.set(timerId, {
48
- callback,
49
- interval: ms,
50
- recurrent: false,
51
- accumulatedTime: 0
52
- });
53
- return timerId;
72
+ return addTimer(callback, ms, false);
54
73
  },
55
74
  clearTimeout(timerId) {
56
75
  timers.delete(timerId);
57
76
  },
58
77
  setInterval(callback, ms) {
59
- const timerId = timerIdCounter++;
60
- timers.set(timerId, {
61
- callback,
62
- interval: ms,
63
- recurrent: true,
64
- accumulatedTime: 0
65
- });
66
- return timerId;
78
+ return addTimer(callback, ms, true);
67
79
  },
68
80
  clearInterval(timerId) {
69
81
  timers.delete(timerId);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dcl/ecs",
3
3
  "description": "Decentraland ECS",
4
- "version": "7.24.1",
4
+ "version": "7.24.2-27638397160.commit-401ee50",
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": "558451f7deaac1ece95b58a178ab8b291e524479"
37
+ "commit": "401ee505079894389381bf3a1cfc0e8ae97fe357"
38
38
  }