• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 20450486144

23 Dec 2025 03:28AM UTC coverage: 88.744% (+0.1%) from 88.638%
20450486144

push

github

web-flow
fix: Realistic body sleeping (#3589)

* wip sleeping is more stable

* refactor

* maybe help with floaters

* maybe fix all the thigns

* okay

* fix motion system

* dont interpolate sleeping bodies

* better canonicalizeAngle

* working

* implement islands

* fix tests and refactoring

* tweak

* fix lint

* add system durations

* fix tests

* really fix tests

* really fix tests

* delete commented code

* remove unused param

* remove assert

* add changelog

* fix trail off

* really fix tests

5387 of 7332 branches covered (73.47%)

148 of 154 new or added lines in 10 files covered. (96.1%)

3 existing lines in 3 files now uncovered.

14846 of 16729 relevant lines covered (88.74%)

24523.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/src/engine/GarbageCollector.ts
1
export interface GarbageCollectionOptions {
2
  /**
3
   * Textures that aren't drawn after a certain number of milliseconds are unloaded from the GPU
4
   * Default 60_000 ms
5
   */
6
  textureCollectInterval?: number; // default 60_000 ms
7
  // TODO future work to integrate the font and text configuration, refactor existing collection mechanism
8
  // /**
9
  //  * Font pre-renders that aren't drawn after a certain number of milliseconds are unloaded from the GPU
10
  //  * Default 60_000 ms
11
  //  */
12
  // fontCollectInterval: number; // default 60_000 ms
13
  // /**
14
  //  * Text measurements that aren't used after a certain number of milliseconds are unloaded from the GPU
15
  //  * Default 60_000 ms
16
  //  */
17
  // textMeasurementCollectInterval: number; // default 60_000 ms
18
}
19

20
export const DefaultGarbageCollectionOptions: GarbageCollectionOptions = {
248✔
21
  textureCollectInterval: 60_000
22
  // TODO future work to integrate the font and text configuration, refactor existing collection mechanism
23
  // fontCollectInterval: 60_000,
24
  // textMeasurementCollectInterval: 60_000,
25
};
26

27
export interface GarbageCollectorOptions {
28
  /**
29
   * Returns a timestamp in milliseconds representing now
30
   */
31
  getTimestamp: () => number;
32
}
33

34
export class GarbageCollector {
35
  private _collectHandle: number;
36
  private _running = false;
751✔
37
  private _collectionMap = new Map<any, [type: string, time: number]>();
751✔
38
  private _collectors = new Map<string, [(resource: any) => boolean, interval: number]>();
751✔
39

40
  constructor(public options: GarbageCollectorOptions) {}
751✔
41

42
  /**
43
   *
44
   * @param type Resource type
45
   * @param timeoutInterval If resource type exceeds interval in milliseconds collect() is called
46
   * @param collect Collection implementation, returns true if collected
47
   */
48
  registerCollector(type: string, timeoutInterval: number, collect: (resource: any) => boolean) {
49
    this._collectors.set(type, [collect, timeoutInterval]);
748✔
50
  }
51

52
  /**
53
   * Add a resource to be tracked for collection
54
   * @param type
55
   * @param resource
56
   */
57
  addCollectableResource(type: string, resource: any) {
58
    this._collectionMap.set(resource, [type, this.options.getTimestamp()]);
166✔
59
  }
60

61
  /**
62
   * Update the resource last used timestamp preventing collection
63
   * @param resource
64
   */
65
  touch(resource: any) {
66
    const collectionData = this._collectionMap.get(resource);
1,751✔
67
    if (collectionData) {
1,751!
68
      this._collectionMap.set(resource, [collectionData[0], this.options.getTimestamp()]);
1,751✔
69
    }
70
  }
71

72
  /**
73
   * Runs the collection loop to cleanup any stale resources given the registered collect handlers
74
   */
75
  public collectStaleResources = (deadline?: IdleDeadline) => {
751✔
76
    if (!this._running) {
870!
UNCOV
77
      return;
×
78
    }
79
    for (const [type, [collector, timeoutInterval]] of this._collectors.entries()) {
870✔
80
      const now = this.options.getTimestamp();
861✔
81
      for (const [resource, [resourceType, time]] of this._collectionMap.entries()) {
861✔
82
        if (type !== resourceType || time + timeoutInterval >= now) {
208✔
83
          continue;
206✔
84
        }
85

86
        const collected = collector(resource);
2✔
87
        if (collected) {
2!
88
          this._collectionMap.delete(resource);
2✔
89
        }
90
      }
91
    }
92

93
    this._collectHandle = requestIdleCallback(this.collectStaleResources);
870✔
94
  };
95

96
  /**
97
   * Force collect all resources, useful for shutting down a game
98
   * or if you know that you will not use anything you've allocated before now
99
   */
100
  public forceCollectAll() {
101
    for (const [_, [collector]] of this._collectors.entries()) {
745✔
102
      for (const [resource] of this._collectionMap.entries()) {
744✔
103
        const collected = collector(resource);
164✔
104
        if (collected) {
164!
105
          this._collectionMap.delete(resource);
164✔
106
        }
107
      }
108
    }
109
  }
110

111
  running(): boolean {
112
    return this._running;
×
113
  }
114

115
  /**
116
   * Starts the garbage collection loop
117
   */
118
  start() {
119
    this._running = true;
583✔
120
    this.collectStaleResources();
583✔
121
  }
122

123
  /**
124
   * Stops the garbage collection loop
125
   */
126
  stop() {
127
    this._running = false;
588✔
128
    cancelIdleCallback(this._collectHandle);
588✔
129
  }
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc