murow 0.0.53 → 0.0.60
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/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/loop/drivers/immediate.d.ts +47 -0
- package/dist/core/loop/drivers/immediate.js +61 -0
- package/dist/core/loop/drivers/index.d.ts +3 -0
- package/dist/core/loop/drivers/index.js +3 -0
- package/dist/core/loop/drivers/raf.d.ts +44 -0
- package/dist/core/loop/drivers/raf.js +62 -0
- package/dist/core/loop/drivers/timeout.d.ts +52 -0
- package/dist/core/loop/drivers/timeout.js +71 -0
- package/dist/core/loop/index.d.ts +2 -0
- package/dist/core/loop/index.js +2 -0
- package/dist/core/loop/loop.d.ts +58 -0
- package/dist/core/loop/loop.js +47 -0
- package/dist/core.esm.js +1 -1
- package/dist/core.js +1 -1
- package/dist/ecs/component-store.d.ts +1 -0
- package/dist/ecs/component-store.js +3 -22
- package/dist/ecs/component.d.ts +2 -0
- package/dist/ecs/entity-handle.d.ts +184 -12
- package/dist/ecs/entity-handle.js +298 -15
- package/dist/ecs/system-builder.d.ts +130 -0
- package/dist/ecs/system-builder.js +180 -0
- package/dist/ecs/system.d.ts +63 -0
- package/dist/ecs/system.js +92 -0
- package/dist/ecs/world-systems.d.ts +69 -0
- package/dist/ecs/world-systems.js +79 -0
- package/dist/ecs/world.d.ts +42 -9
- package/dist/ecs/world.js +102 -11
- package/dist/net/client.d.ts +8 -0
- package/dist/net/client.js +16 -0
- package/dist/protocol/rpc/rpc-registry.d.ts +8 -0
- package/dist/protocol/rpc/rpc-registry.js +17 -0
- package/dist/protocol/snapshot/snapshot-registry.d.ts +8 -0
- package/dist/protocol/snapshot/snapshot-registry.js +17 -0
- package/package.json +1 -1
- package/src/core/index.ts +1 -0
- package/src/core/loop/README.md +97 -0
- package/src/core/loop/drivers/immediate.ts +66 -0
- package/src/core/loop/drivers/index.ts +3 -0
- package/src/core/loop/drivers/raf.ts +67 -0
- package/src/core/loop/drivers/timeout.ts +77 -0
- package/src/core/loop/index.ts +2 -0
- package/src/core/loop/loop.test.ts +414 -0
- package/src/core/loop/loop.ts +71 -0
- package/src/ecs/component-store.ts +5 -27
- package/src/ecs/component.ts +3 -0
- package/src/ecs/entity-handle.ts +334 -16
- package/src/ecs/system-builder.ts +309 -0
- package/src/ecs/system.ts +111 -0
- package/src/ecs/world-systems.ts +83 -0
- package/src/ecs/world.ts +828 -732
- package/src/net/client.test.ts +283 -2
- package/src/net/client.ts +18 -0
- package/src/protocol/rpc/rpc-registry.ts +20 -0
- package/src/protocol/snapshot/snapshot-registry.ts +20 -0
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { LoopDriver } from "../loop";
|
|
2
|
+
/**
|
|
3
|
+
* Server-side game loop driver using setImmediate.
|
|
4
|
+
*
|
|
5
|
+
* This driver runs the game loop as fast as possible without blocking the event loop,
|
|
6
|
+
* making it suitable for Node.js server environments where high tick rates are desired.
|
|
7
|
+
*
|
|
8
|
+
* Delta time is automatically calculated between iterations and passed to the update callback in seconds.
|
|
9
|
+
*
|
|
10
|
+
* **Note:** This driver requires Node.js as it uses `setImmediate` which is not available in browsers.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const driver = new ImmediateDriver((dt) => {
|
|
15
|
+
* world.tick(dt);
|
|
16
|
+
* broadcastState();
|
|
17
|
+
* });
|
|
18
|
+
* driver.start();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class ImmediateDriver implements LoopDriver {
|
|
22
|
+
update: (dt: number) => void;
|
|
23
|
+
/**
|
|
24
|
+
* @param update - Callback invoked each tick with delta time in seconds
|
|
25
|
+
*/
|
|
26
|
+
constructor(update: (dt: number) => void);
|
|
27
|
+
private last;
|
|
28
|
+
private running;
|
|
29
|
+
/**
|
|
30
|
+
* Starts the game loop using setImmediate.
|
|
31
|
+
*
|
|
32
|
+
* Resets timing to prevent large initial delta.
|
|
33
|
+
*/
|
|
34
|
+
start(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Stops the game loop.
|
|
37
|
+
*
|
|
38
|
+
* Note: Does not cancel already queued setImmediate callbacks.
|
|
39
|
+
*/
|
|
40
|
+
stop(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Internal loop method that calculates delta time and schedules the next iteration.
|
|
43
|
+
*
|
|
44
|
+
* Delta time is provided in seconds.
|
|
45
|
+
*/
|
|
46
|
+
loop: () => void;
|
|
47
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side game loop driver using setImmediate.
|
|
3
|
+
*
|
|
4
|
+
* This driver runs the game loop as fast as possible without blocking the event loop,
|
|
5
|
+
* making it suitable for Node.js server environments where high tick rates are desired.
|
|
6
|
+
*
|
|
7
|
+
* Delta time is automatically calculated between iterations and passed to the update callback in seconds.
|
|
8
|
+
*
|
|
9
|
+
* **Note:** This driver requires Node.js as it uses `setImmediate` which is not available in browsers.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const driver = new ImmediateDriver((dt) => {
|
|
14
|
+
* world.tick(dt);
|
|
15
|
+
* broadcastState();
|
|
16
|
+
* });
|
|
17
|
+
* driver.start();
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export class ImmediateDriver {
|
|
21
|
+
/**
|
|
22
|
+
* @param update - Callback invoked each tick with delta time in seconds
|
|
23
|
+
*/
|
|
24
|
+
constructor(update) {
|
|
25
|
+
this.update = update;
|
|
26
|
+
this.last = performance.now();
|
|
27
|
+
this.running = false;
|
|
28
|
+
/**
|
|
29
|
+
* Internal loop method that calculates delta time and schedules the next iteration.
|
|
30
|
+
*
|
|
31
|
+
* Delta time is provided in seconds.
|
|
32
|
+
*/
|
|
33
|
+
this.loop = () => {
|
|
34
|
+
if (!this.running)
|
|
35
|
+
return;
|
|
36
|
+
const now = performance.now();
|
|
37
|
+
const dt = (now - this.last) / 1000;
|
|
38
|
+
this.last = now;
|
|
39
|
+
this.update(dt);
|
|
40
|
+
setImmediate(this.loop);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Starts the game loop using setImmediate.
|
|
45
|
+
*
|
|
46
|
+
* Resets timing to prevent large initial delta.
|
|
47
|
+
*/
|
|
48
|
+
start() {
|
|
49
|
+
this.running = true;
|
|
50
|
+
this.last = performance.now();
|
|
51
|
+
this.loop();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Stops the game loop.
|
|
55
|
+
*
|
|
56
|
+
* Note: Does not cancel already queued setImmediate callbacks.
|
|
57
|
+
*/
|
|
58
|
+
stop() {
|
|
59
|
+
this.running = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LoopDriver } from "../loop";
|
|
2
|
+
/**
|
|
3
|
+
* Client-side game loop driver using requestAnimationFrame.
|
|
4
|
+
*
|
|
5
|
+
* This driver synchronizes updates with the browser's display refresh rate (typically 60 FPS),
|
|
6
|
+
* providing smooth rendering and automatic throttling when the tab is not visible.
|
|
7
|
+
*
|
|
8
|
+
* Delta time is automatically calculated between frames and passed to the update callback in seconds.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const driver = new RafDriver((dt) => {
|
|
13
|
+
* player.update(dt);
|
|
14
|
+
* renderer.render();
|
|
15
|
+
* });
|
|
16
|
+
* driver.start();
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare class RafDriver implements LoopDriver {
|
|
20
|
+
update: (dt: number) => void;
|
|
21
|
+
/**
|
|
22
|
+
* @param update - Callback invoked each frame with delta time in seconds
|
|
23
|
+
*/
|
|
24
|
+
constructor(update: (dt: number) => void);
|
|
25
|
+
private last;
|
|
26
|
+
private running;
|
|
27
|
+
private rafId;
|
|
28
|
+
/**
|
|
29
|
+
* Starts the game loop using requestAnimationFrame.
|
|
30
|
+
*
|
|
31
|
+
* Resets timing to prevent large initial delta.
|
|
32
|
+
*/
|
|
33
|
+
start(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Stops the game loop and cancels any pending animation frame.
|
|
36
|
+
*/
|
|
37
|
+
stop(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Internal loop method that calculates delta time and schedules the next frame.
|
|
40
|
+
*
|
|
41
|
+
* Delta time is provided in seconds.
|
|
42
|
+
*/
|
|
43
|
+
loop: () => void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side game loop driver using requestAnimationFrame.
|
|
3
|
+
*
|
|
4
|
+
* This driver synchronizes updates with the browser's display refresh rate (typically 60 FPS),
|
|
5
|
+
* providing smooth rendering and automatic throttling when the tab is not visible.
|
|
6
|
+
*
|
|
7
|
+
* Delta time is automatically calculated between frames and passed to the update callback in seconds.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const driver = new RafDriver((dt) => {
|
|
12
|
+
* player.update(dt);
|
|
13
|
+
* renderer.render();
|
|
14
|
+
* });
|
|
15
|
+
* driver.start();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class RafDriver {
|
|
19
|
+
/**
|
|
20
|
+
* @param update - Callback invoked each frame with delta time in seconds
|
|
21
|
+
*/
|
|
22
|
+
constructor(update) {
|
|
23
|
+
this.update = update;
|
|
24
|
+
this.last = performance.now();
|
|
25
|
+
this.running = false;
|
|
26
|
+
this.rafId = null;
|
|
27
|
+
/**
|
|
28
|
+
* Internal loop method that calculates delta time and schedules the next frame.
|
|
29
|
+
*
|
|
30
|
+
* Delta time is provided in seconds.
|
|
31
|
+
*/
|
|
32
|
+
this.loop = () => {
|
|
33
|
+
if (!this.running)
|
|
34
|
+
return;
|
|
35
|
+
const now = performance.now();
|
|
36
|
+
const dt = (now - this.last) / 1000;
|
|
37
|
+
this.last = now;
|
|
38
|
+
this.update(dt);
|
|
39
|
+
requestAnimationFrame(this.loop);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Starts the game loop using requestAnimationFrame.
|
|
44
|
+
*
|
|
45
|
+
* Resets timing to prevent large initial delta.
|
|
46
|
+
*/
|
|
47
|
+
start() {
|
|
48
|
+
this.running = true;
|
|
49
|
+
this.last = performance.now();
|
|
50
|
+
this.rafId = requestAnimationFrame(this.loop);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Stops the game loop and cancels any pending animation frame.
|
|
54
|
+
*/
|
|
55
|
+
stop() {
|
|
56
|
+
this.running = false;
|
|
57
|
+
if (this.rafId !== null) {
|
|
58
|
+
cancelAnimationFrame(this.rafId);
|
|
59
|
+
this.rafId = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { LoopDriver } from "../loop";
|
|
2
|
+
/**
|
|
3
|
+
* Server-side game loop driver using setTimeout.
|
|
4
|
+
*
|
|
5
|
+
* This driver provides a more controlled alternative to setImmediate, running the game loop
|
|
6
|
+
* with a minimal delay (1ms) between iterations. This ensures the event loop can process
|
|
7
|
+
* I/O operations while maintaining high tick rates.
|
|
8
|
+
*
|
|
9
|
+
* Unlike setImmediate which runs as fast as possible, setTimeout provides better I/O responsiveness
|
|
10
|
+
* by yielding to the event loop between ticks with a minimal delay.
|
|
11
|
+
*
|
|
12
|
+
* Delta time is automatically calculated between iterations and passed to the update callback in seconds.
|
|
13
|
+
*
|
|
14
|
+
* **Note:** This driver is designed for Node.js/Bun server environments. For maximum performance
|
|
15
|
+
* without I/O concerns, use ImmediateDriver instead.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const driver = new TimeoutDriver((dt) => {
|
|
20
|
+
* world.tick(dt);
|
|
21
|
+
* broadcastState();
|
|
22
|
+
* });
|
|
23
|
+
* driver.start();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class TimeoutDriver implements LoopDriver {
|
|
27
|
+
update: (dt: number) => void;
|
|
28
|
+
/**
|
|
29
|
+
* @param update - Callback invoked each tick with delta time in seconds
|
|
30
|
+
*/
|
|
31
|
+
constructor(update: (dt: number) => void);
|
|
32
|
+
private last;
|
|
33
|
+
private running;
|
|
34
|
+
/**
|
|
35
|
+
* Starts the game loop using setTimeout with minimal delay.
|
|
36
|
+
*
|
|
37
|
+
* Resets timing to prevent large initial delta.
|
|
38
|
+
*/
|
|
39
|
+
start(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Stops the game loop.
|
|
42
|
+
*
|
|
43
|
+
* Note: Does not cancel already queued setTimeout callbacks.
|
|
44
|
+
*/
|
|
45
|
+
stop(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Internal loop method that calculates delta time and schedules the next iteration.
|
|
48
|
+
*
|
|
49
|
+
* Delta time is provided in seconds. Uses 1ms delay to allow I/O processing.
|
|
50
|
+
*/
|
|
51
|
+
loop: () => void;
|
|
52
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal delay for setTimeout-based loop scheduling.
|
|
3
|
+
* Using 1ms allows the event loop to process I/O while still maintaining high tick rates.
|
|
4
|
+
*/
|
|
5
|
+
const TIMEOUT_DELAY = 1;
|
|
6
|
+
/**
|
|
7
|
+
* Server-side game loop driver using setTimeout.
|
|
8
|
+
*
|
|
9
|
+
* This driver provides a more controlled alternative to setImmediate, running the game loop
|
|
10
|
+
* with a minimal delay (1ms) between iterations. This ensures the event loop can process
|
|
11
|
+
* I/O operations while maintaining high tick rates.
|
|
12
|
+
*
|
|
13
|
+
* Unlike setImmediate which runs as fast as possible, setTimeout provides better I/O responsiveness
|
|
14
|
+
* by yielding to the event loop between ticks with a minimal delay.
|
|
15
|
+
*
|
|
16
|
+
* Delta time is automatically calculated between iterations and passed to the update callback in seconds.
|
|
17
|
+
*
|
|
18
|
+
* **Note:** This driver is designed for Node.js/Bun server environments. For maximum performance
|
|
19
|
+
* without I/O concerns, use ImmediateDriver instead.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const driver = new TimeoutDriver((dt) => {
|
|
24
|
+
* world.tick(dt);
|
|
25
|
+
* broadcastState();
|
|
26
|
+
* });
|
|
27
|
+
* driver.start();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class TimeoutDriver {
|
|
31
|
+
/**
|
|
32
|
+
* @param update - Callback invoked each tick with delta time in seconds
|
|
33
|
+
*/
|
|
34
|
+
constructor(update) {
|
|
35
|
+
this.update = update;
|
|
36
|
+
this.last = performance.now();
|
|
37
|
+
this.running = false;
|
|
38
|
+
/**
|
|
39
|
+
* Internal loop method that calculates delta time and schedules the next iteration.
|
|
40
|
+
*
|
|
41
|
+
* Delta time is provided in seconds. Uses 1ms delay to allow I/O processing.
|
|
42
|
+
*/
|
|
43
|
+
this.loop = () => {
|
|
44
|
+
if (!this.running)
|
|
45
|
+
return;
|
|
46
|
+
const now = performance.now();
|
|
47
|
+
const dt = (now - this.last) / 1000;
|
|
48
|
+
this.last = now;
|
|
49
|
+
this.update(dt);
|
|
50
|
+
setTimeout(this.loop, TIMEOUT_DELAY);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Starts the game loop using setTimeout with minimal delay.
|
|
55
|
+
*
|
|
56
|
+
* Resets timing to prevent large initial delta.
|
|
57
|
+
*/
|
|
58
|
+
start() {
|
|
59
|
+
this.running = true;
|
|
60
|
+
this.last = performance.now();
|
|
61
|
+
this.loop();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Stops the game loop.
|
|
65
|
+
*
|
|
66
|
+
* Note: Does not cancel already queued setTimeout callbacks.
|
|
67
|
+
*/
|
|
68
|
+
stop() {
|
|
69
|
+
this.running = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ImmediateDriver, RafDriver, TimeoutDriver } from "./drivers";
|
|
2
|
+
export { ImmediateDriver, RafDriver, TimeoutDriver };
|
|
3
|
+
/**
|
|
4
|
+
* Interface for game loop drivers that handle frame updates.
|
|
5
|
+
* Drivers are responsible for scheduling and executing the game loop
|
|
6
|
+
* at the appropriate rate for their environment (client or server).
|
|
7
|
+
*/
|
|
8
|
+
export interface LoopDriver {
|
|
9
|
+
/** Starts the game loop */
|
|
10
|
+
start(): void;
|
|
11
|
+
/** Stops the game loop */
|
|
12
|
+
stop(): void;
|
|
13
|
+
/** Internal loop iteration method */
|
|
14
|
+
loop(): void;
|
|
15
|
+
/** Update callback invoked each frame with delta time in seconds */
|
|
16
|
+
update(dt: number): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Type of driver to use for the game loop.
|
|
20
|
+
* - `'client'`: Uses requestAnimationFrame for browser environments (syncs with display refresh rate)
|
|
21
|
+
* - `'server-immediate'`: Uses setImmediate for Node.js environments (runs as fast as possible, maximum performance)
|
|
22
|
+
* - `'server-timeout'`: Uses setTimeout with 1ms delay for Node.js environments (balanced performance with better I/O responsiveness)
|
|
23
|
+
*/
|
|
24
|
+
export type DriverType = 'server-immediate' | 'client' | 'server-timeout';
|
|
25
|
+
/**
|
|
26
|
+
* Factory function to create a loop driver for the specified environment.
|
|
27
|
+
*
|
|
28
|
+
* @param type - The environment type
|
|
29
|
+
* - `'client'`: Browser RAF driver (60 FPS, syncs with display)
|
|
30
|
+
* - `'server'`: Node.js setImmediate driver (maximum performance)
|
|
31
|
+
* - `'server-timeout'`: Node.js setTimeout driver (balanced with I/O)
|
|
32
|
+
* @param update - Callback function invoked each frame with delta time in seconds
|
|
33
|
+
* @returns A configured LoopDriver instance ready to start
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // Client
|
|
38
|
+
* const clientDriver = createDriver('client', (dt) => {
|
|
39
|
+
* game.update(dt);
|
|
40
|
+
* renderer.render();
|
|
41
|
+
* });
|
|
42
|
+
* clientDriver.start();
|
|
43
|
+
*
|
|
44
|
+
* // Server (maximum performance)
|
|
45
|
+
* const serverDriver = createDriver('server', (dt) => {
|
|
46
|
+
* simulation.tick(dt);
|
|
47
|
+
* });
|
|
48
|
+
* serverDriver.start();
|
|
49
|
+
*
|
|
50
|
+
* // Server (balanced with I/O)
|
|
51
|
+
* const balancedDriver = createDriver('server-timeout', (dt) => {
|
|
52
|
+
* simulation.tick(dt);
|
|
53
|
+
* handleNetworkIO();
|
|
54
|
+
* });
|
|
55
|
+
* balancedDriver.start();
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function createDriver(type: DriverType, update: (dt: number) => void): ImmediateDriver | RafDriver | TimeoutDriver;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ImmediateDriver, RafDriver, TimeoutDriver } from "./drivers";
|
|
2
|
+
// Re-export driver classes for testing and direct usage
|
|
3
|
+
export { ImmediateDriver, RafDriver, TimeoutDriver };
|
|
4
|
+
/**
|
|
5
|
+
* Factory function to create a loop driver for the specified environment.
|
|
6
|
+
*
|
|
7
|
+
* @param type - The environment type
|
|
8
|
+
* - `'client'`: Browser RAF driver (60 FPS, syncs with display)
|
|
9
|
+
* - `'server'`: Node.js setImmediate driver (maximum performance)
|
|
10
|
+
* - `'server-timeout'`: Node.js setTimeout driver (balanced with I/O)
|
|
11
|
+
* @param update - Callback function invoked each frame with delta time in seconds
|
|
12
|
+
* @returns A configured LoopDriver instance ready to start
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Client
|
|
17
|
+
* const clientDriver = createDriver('client', (dt) => {
|
|
18
|
+
* game.update(dt);
|
|
19
|
+
* renderer.render();
|
|
20
|
+
* });
|
|
21
|
+
* clientDriver.start();
|
|
22
|
+
*
|
|
23
|
+
* // Server (maximum performance)
|
|
24
|
+
* const serverDriver = createDriver('server', (dt) => {
|
|
25
|
+
* simulation.tick(dt);
|
|
26
|
+
* });
|
|
27
|
+
* serverDriver.start();
|
|
28
|
+
*
|
|
29
|
+
* // Server (balanced with I/O)
|
|
30
|
+
* const balancedDriver = createDriver('server-timeout', (dt) => {
|
|
31
|
+
* simulation.tick(dt);
|
|
32
|
+
* handleNetworkIO();
|
|
33
|
+
* });
|
|
34
|
+
* balancedDriver.start();
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function createDriver(type, update) {
|
|
38
|
+
if (type === 'server-immediate') {
|
|
39
|
+
return new ImmediateDriver(update);
|
|
40
|
+
}
|
|
41
|
+
else if (type === 'server-timeout') {
|
|
42
|
+
return new TimeoutDriver(update);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return new RafDriver(update);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/dist/core.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var H=Object.defineProperty;var G=(l,e)=>()=>(l&&(e=l(l=0)),e);var Z=(l,e)=>{for(var t in e)H(l,t,{get:e[t],enumerable:!0})};var C={};Z(C,{NavMeshWorkerPool:()=>z});var z,_=G(()=>{z=class{constructor(e,t,s="grid",r=[]){this.poolSize=e;this.workerPath=t;this.navType=s;this.obstacles=r;this.workers=[];this.nextWorkerIndex=0;this.requestId=0;this.pendingRequests=new Map;this.initialized=!1}async init(){if(this.initialized)return;let e=[];for(let t=0;t<this.poolSize;t++){let s=new Worker(this.workerPath,{type:"module"});s.onmessage=o=>{let n=o.data;if(n.type==="PATH_RESULT"){let i=this.pendingRequests.get(n.id);i&&(i.resolve(n.path),this.pendingRequests.delete(n.id))}else if(n.type==="ERROR")for(let[i,a]of this.pendingRequests.entries())a.reject(new Error(n.error)),this.pendingRequests.delete(i)},s.onerror=o=>{console.error("Worker error:",o);for(let[n,i]of this.pendingRequests.entries())i.reject(new Error("Worker error")),this.pendingRequests.delete(n)},this.workers.push(s);let r=new Promise(o=>{let n=i=>{i.data.type==="READY"&&(s.removeEventListener("message",n),o())};s.addEventListener("message",n)});s.postMessage({type:"INIT",navType:this.navType,obstacles:this.obstacles}),e.push(r)}await Promise.all(e),this.initialized=!0}async findPath(e,t){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let s=this.requestId++,r=this.workers[this.nextWorkerIndex];return this.nextWorkerIndex=(this.nextWorkerIndex+1)%this.workers.length,new Promise((o,n)=>{this.pendingRequests.set(s,{id:s,from:e,to:t,resolve:o,reject:n}),r.postMessage({type:"FIND_PATH",id:s,from:e,to:t})})}async addObstacle(e){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let t=this.workers.map(r=>new Promise(o=>{let n=i=>{i.data.type==="OBSTACLE_ADDED"&&(r.removeEventListener("message",n),o(i.data.obstacleId))};r.addEventListener("message",n),r.postMessage({type:"ADD_OBSTACLE",obstacle:e})}));return(await Promise.all(t))[0]}async removeObstacle(e){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let t=this.workers.map(s=>new Promise(r=>{let o=n=>{n.data.type==="OBSTACLE_REMOVED"&&(s.removeEventListener("message",o),r())};s.addEventListener("message",o),s.postMessage({type:"REMOVE_OBSTACLE",obstacleId:e})}));await Promise.all(t)}async moveObstacle(e,t){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let s=this.workers.map(r=>new Promise(o=>{let n=i=>{i.data.type==="OBSTACLE_MOVED"&&(r.removeEventListener("message",n),o())};r.addEventListener("message",n),r.postMessage({type:"MOVE_OBSTACLE",obstacleId:e,pos:t})}));await Promise.all(s)}terminate(){for(let e of this.workers)e.terminate();this.workers=[],this.pendingRequests.clear(),this.initialized=!1}get pendingCount(){return this.pendingRequests.size}get size(){return this.workers.length}}});var V=Symbol("schemaSize");function R(l){let e=l[V];if(e!==void 0)return e;let t=0;for(let s of Object.keys(l))t+=l[s].size;return l[V]=t,t}var v=class{static encodeInto(e,t){let s=R(e),r=new ArrayBuffer(s),o=new DataView(r),n=0;for(let i of Object.keys(e)){let a=e[i];a.write(o,n,t[i]),n+=a.size}return new Uint8Array(r)}static decodeInto(e,t,s){let r=R(e);if(t.byteLength<r)throw new RangeError(`Buffer too small: expected ${r} bytes, got ${t.byteLength}`);let o=new DataView(t.buffer,t.byteOffset,t.byteLength),n=0;for(let i of Object.keys(e)){let a=e[i];s[i]=a.read(o,n),n+=a.size}return s}},m=class{static{this.u8={size:1,write:(e,t,s)=>e.setUint8(t,s),read:(e,t)=>e.getUint8(t),toNil:()=>0}}static{this.u16={size:2,write:(e,t,s)=>e.setUint16(t,s,!1),read:(e,t)=>e.getUint16(t,!1),toNil:()=>0}}static{this.u32={size:4,write:(e,t,s)=>e.setUint32(t,s,!1),read:(e,t)=>e.getUint32(t,!1),toNil:()=>0}}static{this.i8={size:1,write:(e,t,s)=>e.setInt8(t,s),read:(e,t)=>e.getInt8(t),toNil:()=>0}}static{this.i16={size:2,write:(e,t,s)=>e.setInt16(t,s,!1),read:(e,t)=>e.getInt16(t,!1),toNil:()=>0}}static{this.i32={size:4,write:(e,t,s)=>e.setInt32(t,s,!1),read:(e,t)=>e.getInt32(t,!1),toNil:()=>0}}static{this.f32={size:4,write:(e,t,s)=>e.setFloat32(t,s,!1),read:(e,t)=>e.getFloat32(t,!1),toNil:()=>0}}static{this.f64={size:8,write:(e,t,s)=>e.setFloat64(t,s,!1),read:(e,t)=>e.getFloat64(t,!1),toNil:()=>0}}static{this.bool={size:1,write:(e,t,s)=>e.setUint8(t,s?1:0),read:(e,t)=>e.getUint8(t)!==0,toNil:()=>!1}}static string(e){return{size:e+2,write(t,s,r){let n=new TextEncoder().encode(r);if(n.length>e)throw new RangeError(`String too long, max ${e} bytes`);t.setUint16(s,n.length,!1);for(let i=0;i<n.length;i++)t.setUint8(s+2+i,n[i]);for(let i=n.length;i<e;i++)t.setUint8(s+2+i,0)},read(t,s){let r=t.getUint16(s,!1),o=new Uint8Array(r);for(let n=0;n<r;n++)o[n]=t.getUint8(s+2+n);return new TextDecoder().decode(o)},toNil:()=>""}}static{this.vec2={size:8,write(e,t,s){e.setFloat32(t,s.x,!1),e.setFloat32(t+4,s.y,!1)},read(e,t){return{x:e.getFloat32(t,!1),y:e.getFloat32(t+4,!1)}},toNil:()=>({x:0,y:0})}}static{this.vec3={size:12,write(e,t,s){e.setFloat32(t,s.x,!1),e.setFloat32(t+4,s.y,!1),e.setFloat32(t+8,s.z,!1)},read(e,t){return{x:e.getFloat32(t,!1),y:e.getFloat32(t+4,!1),z:e.getFloat32(t+8,!1)}},toNil:()=>({x:0,y:0,z:0})}}static{this.color={size:4,write(e,t,s){e.setUint8(t,s.r),e.setUint8(t+1,s.g),e.setUint8(t+2,s.b),e.setUint8(t+3,s.a)},read(e,t){return{r:e.getUint8(t),g:e.getUint8(t+1),b:e.getUint8(t+2),a:e.getUint8(t+3)}},toNil:()=>({r:0,g:0,b:0,a:0})}}static{this.f32_le={size:4,write:(e,t,s)=>e.setFloat32(t,s,!0),read:(e,t)=>e.getFloat32(t,!0),toNil:()=>0}}static{this.f64_le={size:8,write:(e,t,s)=>e.setFloat64(t,s,!0),read:(e,t)=>e.getFloat64(t,!0),toNil:()=>0}}static{this.u16_le={size:2,write:(e,t,s)=>e.setUint16(t,s,!0),read:(e,t)=>e.getUint16(t,!0),toNil:()=>0}}static{this.u32_le={size:4,write:(e,t,s)=>e.setUint32(t,s,!0),read:(e,t)=>e.getUint32(t,!0),toNil:()=>0}}static{this.i16_le={size:2,write:(e,t,s)=>e.setInt16(t,s,!0),read:(e,t)=>e.getInt16(t,!0),toNil:()=>0}}static{this.i32_le={size:4,write:(e,t,s)=>e.setInt32(t,s,!0),read:(e,t)=>e.getInt32(t,!0),toNil:()=>0}}static{this.vec2_le={size:8,write:(e,t,s)=>{e.setFloat32(t,s[0],!0),e.setFloat32(t+4,s[1],!0)},read:(e,t)=>[e.getFloat32(t,!0),e.getFloat32(t+4,!0)],toNil:()=>[0,0]}}static{this.vec3_le={size:12,write:(e,t,s)=>{e.setFloat32(t,s[0],!0),e.setFloat32(t+4,s[1],!0),e.setFloat32(t+8,s[2],!0)},read:(e,t)=>[e.getFloat32(t,!0),e.getFloat32(t+4,!0),e.getFloat32(t+8,!0)],toNil:()=>[0,0,0]}}static{this.vec4_le={size:16,write:(e,t,s)=>{e.setFloat32(t,s[0],!0),e.setFloat32(t+4,s[1],!0),e.setFloat32(t+8,s[2],!0),e.setFloat32(t+12,s[3],!0)},read:(e,t)=>[e.getFloat32(t,!0),e.getFloat32(t+4,!0),e.getFloat32(t+8,!0),e.getFloat32(t+12,!0)],toNil:()=>[0,0,0,0]}}},k=class extends v{static{this.u8=m.u8}static{this.u16=m.u16}static{this.u32=m.u32}static{this.i8=m.i8}static{this.i16=m.i16}static{this.i32=m.i32}static{this.f32=m.f32}static{this.bool=m.bool}static{this.string=m.string}static{this.vec2=m.vec2}static{this.vec3=m.vec3}static{this.color=m.color}static encode(e,t){return this.encodeInto(e,t)}static decode(e,t,s){return this.decodeInto(e,t,s)}};var A=class{constructor({events:e}){this.callbacks=new Map,this.events=e;for(let t of this.events)this.callbacks.set(t,new Set)}on(e,t){let s=this.callbacks.get(e);if(!s)return console.warn(`Event "${e}" does not exist.`);s.add(t)}once(e,t){let s=r=>{t(r),this.off(e,s)};this.on(e,s)}emit(e,t){let s=this.callbacks.get(e);if(!s)return console.warn(`Event "${e}" does not exist.`);for(let r of s)r(t)}off(e,t){let s=this.callbacks.get(e);if(!s)return console.warn(`Event "${e}" does not exist.`);s.delete(t)}clear(e){if(!e){this.callbacks.clear();for(let s of this.events)this.callbacks.set(s,new Set);return}let t=this.callbacks.get(e);if(!t)return console.warn(`Event "${e}" does not exist.`);t.clear()}};var N=class{constructor({rate:e,onTick:t}){this.accumulator=0;this._tickCount=0;this.rate=e,this.intervalMs=1e3/this.rate,this.onTick=t,this.maxTicksPerFrame=Math.max(1,Math.floor(e/2))}getTicks(e){this.accumulator+=e*1e3;let t=0;for(;this.accumulator>=this.intervalMs&&t<this.maxTicksPerFrame;)this.accumulator-=this.intervalMs,t++;let s=Math.floor(this.accumulator/this.intervalMs);return s>0&&this.onTickSkipped&&this.onTickSkipped(s),t}tick(e){let t=this.getTicks(e);for(let s=0;s<t;s++)this.onTick(1/this.rate,this._tickCount++)}get tickCount(){return this._tickCount}resetTickCount(){this._tickCount=0}get accumulatedTime(){return this.accumulator/1e3}get alpha(){return Math.min(this.accumulatedTime/(1/this.rate),1)}};function ue(l={}){let{prefix:e="",size:t=16}=l,s=Math.max(t-e.length,8),r=Math.ceil(s/8),n=crypto.getRandomValues(new Uint32Array(r)).reduce((i,a)=>i+a.toString(16).padStart(8,"0"),"");return n=n.slice(0,s).padStart(s,"0"),`${e}${n}`}function ye(l,e,t){return l+(e-l)*t}var J=[{x:1,y:0},{x:-1,y:0},{x:0,y:1},{x:0,y:-1}],w=l=>({x:Math.floor(l.x),y:Math.floor(l.y)}),j=l=>({x:l.x+.5,y:l.y+.5}),Q=(()=>{let l=1;return()=>l++})(),b=(l,e)=>l&65535|(e&65535)<<16,O=l=>({x:l<<16>>16,y:l>>16}),S=class{constructor(e){this.scoreFn=e;this.heap=[]}push(e){this.heap.push(e),this.bubbleUp(this.heap.length-1)}pop(){let e=this.heap[0],t=this.heap.pop();return this.heap.length>0&&t!==void 0&&(this.heap[0]=t,this.sinkDown(0)),e}get size(){return this.heap.length}bubbleUp(e){let t=this.heap[e],s=this.scoreFn(t);for(;e>0;){let r=(e+1>>1)-1,o=this.heap[r];if(s>=this.scoreFn(o))break;this.heap[r]=t,this.heap[e]=o,e=r}}sinkDown(e){let t=this.heap.length,s=this.heap[e],r=this.scoreFn(s);for(;;){let o=e+1<<1,n=o-1,i=null,a;if(n<t){let c=this.heap[n];a=this.scoreFn(c),a<r&&(i=n)}if(o<t){let c=this.heap[o];this.scoreFn(c)<(i===null?r:a)&&(i=o)}if(i===null)break;this.heap[e]=this.heap[i],this.heap[i]=s,e=i}}},E=class{constructor(e=1){this.grid=new Map;this.obstacleCells=new Map;this.cellSize=e}hash(e,t){let s=Math.floor(e/this.cellSize),r=Math.floor(t/this.cellSize);return b(s,r)}add(e,t){let s=this.getCellsForObstacle(t);for(let r of s)this.grid.has(r)||this.grid.set(r,new Set),this.grid.get(r).add(e);this.obstacleCells.set(e,s)}remove(e){let t=this.obstacleCells.get(e);if(t){for(let s of t){let r=this.grid.get(s);r&&(r.delete(e),r.size===0&&this.grid.delete(s))}this.obstacleCells.delete(e)}}query(e){let t=this.hash(e.x,e.y);return this.grid.get(t)||new Set}clear(){this.grid.clear(),this.obstacleCells.clear()}getCellsForObstacle(e){let t=new Set;if(e.type==="circle"){let s=e.radius,r=Math.floor((e.pos.x-s)/this.cellSize),o=Math.floor((e.pos.x+s)/this.cellSize),n=Math.floor((e.pos.y-s)/this.cellSize),i=Math.floor((e.pos.y+s)/this.cellSize);for(let a=r;a<=o;a++)for(let c=n;c<=i;c++)t.add(b(a,c))}else if(e.type==="rect"){let s=e.pos.x+e.size.x/2,r=e.pos.y+e.size.y/2,o=e.size.x/2,n=e.size.y/2,i=Math.sqrt(o*o+n*n),a=Math.floor((s-i)/this.cellSize),c=Math.floor((s+i)/this.cellSize),u=Math.floor((r-i)/this.cellSize),d=Math.floor((r+i)/this.cellSize);for(let h=a;h<=c;h++)for(let f=u;f<=d;f++)t.add(b(h,f))}else if(e.type==="polygon"){let s=X(e),r=Math.floor(s.minX/this.cellSize),o=Math.floor(s.maxX/this.cellSize),n=Math.floor(s.minY/this.cellSize),i=Math.floor(s.maxY/this.cellSize);for(let a=r;a<=o;a++)for(let c=n;c<=i;c++)t.add(b(a,c))}return t}};function q(l,e){let t=l.x-e.pos.x,s=l.y-e.pos.y;return t*t+s*s<=e.radius*e.radius}function D(l,e){let t=e.pos.x+e.size.x/2,s=e.pos.y+e.size.y/2;if(e.rotation){let r=Math.cos(-e.rotation),o=Math.sin(-e.rotation),n=l.x-t,i=l.y-s,a=n*r-i*o,c=n*o+i*r;return Math.abs(a)<=e.size.x/2&&Math.abs(c)<=e.size.y/2}return l.x>=e.pos.x&&l.y>=e.pos.y&&l.x<=e.pos.x+e.size.x&&l.y<=e.pos.y+e.size.y}function Y(l,e){let t=!1,s=e.points,r=e.rotation?Math.cos(e.rotation):1,o=e.rotation?Math.sin(e.rotation):0;for(let n=0,i=s.length-1;n<s.length;i=n++){let a=s[n].x,c=s[n].y,u=s[i].x,d=s[i].y;if(e.rotation){let f=a*r-c*o,y=a*o+c*r,p=u*r-d*o,x=u*o+d*r;a=f,c=y,u=p,d=x}a+=e.pos.x,c+=e.pos.y,u+=e.pos.x,d+=e.pos.y,c>l.y!=d>l.y&&l.x<(u-a)*(l.y-c)/(d-c)+a&&(t=!t)}return t}function X(l){let e=1/0,t=1/0,s=-1/0,r=-1/0,o=l.rotation?Math.cos(l.rotation):1,n=l.rotation?Math.sin(l.rotation):0;for(let i of l.points){let a=i.x,c=i.y;if(l.rotation){let u=a*o-c*n,d=a*n+c*o;a=u,c=d}a+=l.pos.x,c+=l.pos.y,e=Math.min(e,a),t=Math.min(t,c),s=Math.max(s,a),r=Math.max(r,c)}return{minX:e,minY:t,maxX:s,maxY:r}}var M=class{constructor(){this.items=new Map;this.spatial=new E(1);this._cachedItems=[];this.dirty=!0;this.version=0}add(e){let t=Q(),s={...e,id:t};return this.items.set(t,s),this.spatial.add(t,s),this.dirty=!0,this.version++,t}move(e,t){let s=this.items.get(e);if(!s)return;this.spatial.remove(e);let r={...s,pos:{...t}};this.items.set(e,r),this.spatial.add(e,r),this.dirty=!0,this.version++}remove(e){this.spatial.remove(e),this.items.delete(e),this.dirty=!0,this.version++}at(e){let t=this.spatial.query(e);for(let s of t){let r=this.items.get(s);if(!(!r||r.solid===!1)&&(r.type==="circle"&&q(e,r)||r.type==="rect"&&D(e,r)||r.type==="polygon"&&Y(e,r)))return r}}get values(){return this.dirty?(this._cachedItems=[...this.items.values()],this.dirty=!1,this._cachedItems):this._cachedItems}},F=class{constructor(e){this.obstacles=e;this.blocked=new Set}rebuild(){this.blocked.clear();for(let e of this.obstacles.values)if(e.solid!==!1){if(e.type==="circle"){let t=Math.ceil(e.radius),s=Math.floor(e.pos.x),r=Math.floor(e.pos.y);for(let o=-t;o<=t;o++)for(let n=-t;n<=t;n++){let i=s+o,a=r+n,c={x:i+.5,y:a+.5};q(c,e)&&this.blocked.add(b(i,a))}}else if(e.type==="rect"){let t=e.pos.x+e.size.x/2,s=e.pos.y+e.size.y/2,r=e.size.x/2,o=e.size.y/2,n=Math.sqrt(r*r+o*o),i=Math.floor(t-n),a=Math.ceil(t+n),c=Math.floor(s-n),u=Math.ceil(s+n);for(let d=i;d<=a;d++)for(let h=c;h<=u;h++){let f={x:d+.5,y:h+.5};D(f,e)&&this.blocked.add(b(d,h))}}else if(e.type==="polygon"){let t=X(e),s=Math.floor(t.minX),r=Math.ceil(t.maxX),o=Math.floor(t.minY),n=Math.ceil(t.maxY);for(let i=s;i<=r;i++)for(let a=o;a<=n;a++){let c={x:i+.5,y:a+.5};Y(c,e)&&this.blocked.add(b(i,a))}}}}findPath(e,t){return L(w(e),w(t),(s,r)=>!this.blocked.has(b(s,r))).map(j)}},P=class{constructor(e){this.obstacles=e}rebuild(){}findPath(e,t){let s=Math.ceil(Math.hypot(t.x-e.x,t.y-e.y)*2),r=!1;for(let n=1;n<=s;n++){let i=n/s,a={x:e.x+(t.x-e.x)*i,y:e.y+(t.y-e.y)*i};if(this.obstacles.at(a)){r=!0;break}}return r?L(w(e),w(t),(n,i)=>{let a={x:n+.5,y:i+.5};return!this.obstacles.at(a)}).map(j):[e,t]}},W=class{constructor(e,t){this.type=e;this.lastVersion=-1;this.pendingPaths=0;this.AUTO_WORKER_THRESHOLD=20;this.obstacles=new M,this.options={workers:t?.workers??!1,workerPoolSize:t?.workerPoolSize??4,workerPath:t?.workerPath??"./navmesh.worker.js"},e==="grid"&&(this.grid=new F(this.obstacles)),e==="graph"&&(this.graph=new P(this.obstacles)),this.options.workers===!0&&this.initWorkerPool()}async initWorkerPool(){if(!this.workerPool)try{let{NavMeshWorkerPool:e}=await Promise.resolve().then(()=>(_(),C));this.workerPool=new e(this.options.workerPoolSize,this.options.workerPath,this.type,this.obstacles.values),await this.workerPool.init()}catch(e){console.warn("Failed to initialize worker pool, falling back to sync:",e),this.options.workers=!1}}shouldUseWorkers(){return this.options.workers===!1?!1:this.options.workers===!0?!0:this.pendingPaths>=this.AUTO_WORKER_THRESHOLD}addObstacle(e){return this.obstacles.add(e)}moveObstacle(e,t){this.obstacles.move(e,t)}removeObstacle(e){this.obstacles.remove(e)}getObstacles(){return this.obstacles.values}findPath({from:e,to:t}){return this.shouldUseWorkers()&&this.workerPool?(this.pendingPaths++,this.findPathAsync(e,t).finally(()=>{this.pendingPaths--})):(this.rebuild(),this.type==="grid"?this.grid.findPath(e,t):this.graph.findPath(e,t))}async findPathAsync(e,t){return this.options.workers==="auto"&&!this.workerPool&&await this.initWorkerPool(),this.workerPool?this.workerPool.findPath(e,t):(this.rebuild(),this.type==="grid"?this.grid.findPath(e,t):this.graph.findPath(e,t))}rebuild(){this.lastVersion!==this.obstacles.version&&(this.grid?.rebuild(),this.graph?.rebuild(),this.lastVersion=this.obstacles.version)}dispose(){this.workerPool&&(this.workerPool.terminate(),this.workerPool=void 0)}getWorkerStatus(){return{workersEnabled:this.options.workers,workerPoolActive:!!this.workerPool,pendingPaths:this.pendingPaths,usingWorkersNow:this.shouldUseWorkers()}}};function L(l,e,t){let s=new Map,r=new Map,o=new Set,n=new Set,i=d=>b(d.x,d.y),a=(d,h)=>Math.abs(d.x-h.x)+Math.abs(d.y-h.y),c=new S(d=>{let h=O(d);return r.get(d)+a(h,e)}),u=i(l);for(r.set(u,0),c.push(u),n.add(u);c.size>0;){let d=c.pop();n.delete(d);let h=O(d);if(h.x===e.x&&h.y===e.y)return ee(s,h);o.add(d);for(let f of J){let y={x:h.x+f.x,y:h.y+f.y};if(!t(y.x,y.y))continue;let p=i(y);if(o.has(p))continue;let x=r.get(d)+1;x<(r.get(p)??1/0)&&(r.set(p,x),s.set(p,d),n.has(p)||(c.push(p),n.add(p)))}}return[]}function ee(l,e){let t=[e],s=b(e.x,e.y);for(;l.has(s);)s=l.get(s),t.push(O(s));return t.reverse()}var g=class{constructor(e){this.factory=e;this.pool=[]}acquire(){return this.pool.pop()??this.factory()}release(e){this.pool.push(e)}releaseAll(e){this.pool.push(...e)}},T=class{constructor(e){this.schema=e;this.pool=new g(()=>this.createNil())}createNil(){let e={};for(let t of Object.keys(this.schema)){let s=this.schema[t];e[t]="toNil"in s?s.toNil():void 0}return e}decode(e){let t=this.pool.acquire();return this.decodeInto(e,t),t}decodeInto(e,t){let s=0;for(let r of Object.keys(this.schema)){let o=this.schema[r];if("decodeAll"in o){let n=o.decodeAll(e.subarray(s));t[r]=n.value,s+=n.bytesRead}else if("decodeField"in o){let n=o.decodeField(e.subarray(s));t[r]=n.value,s+=n.bytesRead}else if("decode"in o){let n=o.decode(e.subarray(s));t[r]=n.value,s+=n.bytesRead}else{let n=o.size||0,i=e.subarray(s,s+n);k.decodeInto({[r]:o},i,t),s+=n}}}release(e){this.pool.release(e)}},K=class{constructor(e){this.pooledDecoder=new T(e)}decodeAll(e){return e.map(t=>this.pooledDecoder.decode(t))}releaseAll(e){e.forEach(t=>this.pooledDecoder.release(t))}},U=class{constructor(e,t=1024){this.schema=e;this.bufferSize=t;this.pool=new g(()=>new Uint8Array(t))}encode(e){let t=this.pool.acquire(),s=0;for(let r of Object.keys(this.schema)){let o=this.schema[r];if("encode"in o){let n=o.encode(e[r]);t.set(n,s),s+=n.length}else if("encodeAll"in o){let n=o.encodeAll(e[r]),i=0;for(let a of n)t.set(a,s+i),i+=a.length;s+=i}else{let n=k.encode({[r]:o},{[r]:e[r]});t.set(n,s),s+=n.length}}return t.subarray(0,s)}release(e){this.pool.release(e)}},B=class{constructor(e){this.schema=e;this.encoder=new U(e),this.decoder=new T(e)}calculateSize(e){let t=0;for(let s of Object.keys(this.schema)){let r=this.schema[s];"size"in r?t+=r.size:"calculateSize"in r&&(t+=r.calculateSize(e[s]))}return t}encodeInto(e,t,s){let r=new DataView(t.buffer,t.byteOffset),o=s;for(let n of Object.keys(this.schema)){let i=this.schema[n];if("write"in i)i.write(r,o,e[n]),o+=i.size;else if("encodeInto"in i){let a=i.encodeInto(e[n],t,o);o+=a}else if("encode"in i){let a=i.encode(e[n]);t.set(a,o),o+=a.length}}return o-s}encode(e){return this.encoder.encode(e)}decode(e){return this.decoder.decode(e)}release(e){this.decoder.release(e)}static array(e){let t=0;for(let a of Object.keys(e)){let c=e[a];t+=c.size||0}let s=new g(()=>new Uint8Array(16384)),r=new g(()=>{let a={};for(let c of Object.keys(e)){let u=e[c];a[c]="toNil"in u?u.toNil():void 0}return a}),o=new g(()=>[]),n=null,i=null;return{__arrayType:void 0,calculateSize(a){return 2+a.length*t},encodeInto(a,c,u){let d=new DataView(c.buffer,c.byteOffset);d.setUint16(u,a.length,!1);let h=u+2;for(let f of a)for(let y of Object.keys(e)){let p=e[y];p.write(d,h,f[y]),h+=p.size}return h-u},encode(a){let c=2+a.length*t,u=s.acquire();u.length<c&&(s.release(u),u=new Uint8Array(Math.max(c,u.length*2))),(!n||n.buffer!==u.buffer)&&(n=new DataView(u.buffer,u.byteOffset)),n.setUint16(0,a.length,!1);let d=2;for(let f of a)for(let y of Object.keys(e)){let p=e[y];p.write(n,d,f[y]),d+=p.size}let h=new Uint8Array(d);return h.set(u.subarray(0,d)),s.release(u),h},decodeField(a){let c=a[0]<<8|a[1],u=o.acquire();u.length=c,(!i||i.buffer!==a.buffer||i.byteOffset!==a.byteOffset)&&(i=new DataView(a.buffer,a.byteOffset));let d=2;for(let h=0;h<c;h++){let f=r.acquire();for(let y of Object.keys(e)){let p=e[y];f[y]=p.read(i,d),d+=p.size}u[h]=f}return{value:u,bytesRead:d}},decode(a){return this.decodeField(a).value},toNil(){return[]}}}};var I=class{constructor(){this.tracker=new Map}get size(){return this.tracker.size}track(e,t){return this.tracker.has(e)||this.tracker.set(e,[]),this.tracker.get(e).push(t),t}dropUpTo(e){let t=[];for(let[s,r]of this.tracker)s<=e?this.tracker.delete(s):t.push([s,r]);return t.sort(([s],[r])=>s-r),t.map(([s,r])=>r).flat()}values(){return Array.from(this.tracker.entries()).sort(([e],[t])=>e-t).map(([e,t])=>t).flat()}},$=class{constructor(e){this.options=e;this.tracker=new I}trackIntent(e,t){this.tracker.track(e,t)}onSnapshot(e){this.options.onLoadState(e.state);let t=this.tracker.dropUpTo(e.tick);t.length>0&&this.options.onReplay(t)}replay(e){this.options.onReplay(e)}};export{v as BaseBinaryCodec,k as BinaryCodec,m as BinaryPrimitives,A as EventSystem,N as FixedTicker,I as IntentTracker,W as NavMesh,g as ObjectPool,K as PooledArrayDecoder,B as PooledCodec,T as PooledDecoder,U as PooledEncoder,$ as Reconciliator,ue as generateId,ye as lerp};
|
|
1
|
+
var J=Object.defineProperty;var Q=(l,e)=>()=>(l&&(e=l(l=0)),e);var ee=(l,e)=>{for(var t in e)J(l,t,{get:e[t],enumerable:!0})};var W={};ee(W,{NavMeshWorkerPool:()=>E});var E,j=Q(()=>{E=class{constructor(e,t,s="grid",r=[]){this.poolSize=e;this.workerPath=t;this.navType=s;this.obstacles=r;this.workers=[];this.nextWorkerIndex=0;this.requestId=0;this.pendingRequests=new Map;this.initialized=!1}async init(){if(this.initialized)return;let e=[];for(let t=0;t<this.poolSize;t++){let s=new Worker(this.workerPath,{type:"module"});s.onmessage=o=>{let n=o.data;if(n.type==="PATH_RESULT"){let i=this.pendingRequests.get(n.id);i&&(i.resolve(n.path),this.pendingRequests.delete(n.id))}else if(n.type==="ERROR")for(let[i,a]of this.pendingRequests.entries())a.reject(new Error(n.error)),this.pendingRequests.delete(i)},s.onerror=o=>{console.error("Worker error:",o);for(let[n,i]of this.pendingRequests.entries())i.reject(new Error("Worker error")),this.pendingRequests.delete(n)},this.workers.push(s);let r=new Promise(o=>{let n=i=>{i.data.type==="READY"&&(s.removeEventListener("message",n),o())};s.addEventListener("message",n)});s.postMessage({type:"INIT",navType:this.navType,obstacles:this.obstacles}),e.push(r)}await Promise.all(e),this.initialized=!0}async findPath(e,t){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let s=this.requestId++,r=this.workers[this.nextWorkerIndex];return this.nextWorkerIndex=(this.nextWorkerIndex+1)%this.workers.length,new Promise((o,n)=>{this.pendingRequests.set(s,{id:s,from:e,to:t,resolve:o,reject:n}),r.postMessage({type:"FIND_PATH",id:s,from:e,to:t})})}async addObstacle(e){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let t=this.workers.map(r=>new Promise(o=>{let n=i=>{i.data.type==="OBSTACLE_ADDED"&&(r.removeEventListener("message",n),o(i.data.obstacleId))};r.addEventListener("message",n),r.postMessage({type:"ADD_OBSTACLE",obstacle:e})}));return(await Promise.all(t))[0]}async removeObstacle(e){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let t=this.workers.map(s=>new Promise(r=>{let o=n=>{n.data.type==="OBSTACLE_REMOVED"&&(s.removeEventListener("message",o),r())};s.addEventListener("message",o),s.postMessage({type:"REMOVE_OBSTACLE",obstacleId:e})}));await Promise.all(t)}async moveObstacle(e,t){if(!this.initialized)throw new Error("Worker pool not initialized. Call init() first.");let s=this.workers.map(r=>new Promise(o=>{let n=i=>{i.data.type==="OBSTACLE_MOVED"&&(r.removeEventListener("message",n),o())};r.addEventListener("message",n),r.postMessage({type:"MOVE_OBSTACLE",obstacleId:e,pos:t})}));await Promise.all(s)}terminate(){for(let e of this.workers)e.terminate();this.workers=[],this.pendingRequests.clear(),this.initialized=!1}get pendingCount(){return this.pendingRequests.size}get size(){return this.workers.length}}});var N=Symbol("schemaSize");function C(l){let e=l[N];if(e!==void 0)return e;let t=0;for(let s of Object.keys(l))t+=l[s].size;return l[N]=t,t}var S=class{static encodeInto(e,t){let s=C(e),r=new ArrayBuffer(s),o=new DataView(r),n=0;for(let i of Object.keys(e)){let a=e[i];a.write(o,n,t[i]),n+=a.size}return new Uint8Array(r)}static decodeInto(e,t,s){let r=C(e);if(t.byteLength<r)throw new RangeError(`Buffer too small: expected ${r} bytes, got ${t.byteLength}`);let o=new DataView(t.buffer,t.byteOffset,t.byteLength),n=0;for(let i of Object.keys(e)){let a=e[i];s[i]=a.read(o,n),n+=a.size}return s}},y=class{static{this.u8={size:1,write:(e,t,s)=>e.setUint8(t,s),read:(e,t)=>e.getUint8(t),toNil:()=>0}}static{this.u16={size:2,write:(e,t,s)=>e.setUint16(t,s,!1),read:(e,t)=>e.getUint16(t,!1),toNil:()=>0}}static{this.u32={size:4,write:(e,t,s)=>e.setUint32(t,s,!1),read:(e,t)=>e.getUint32(t,!1),toNil:()=>0}}static{this.i8={size:1,write:(e,t,s)=>e.setInt8(t,s),read:(e,t)=>e.getInt8(t),toNil:()=>0}}static{this.i16={size:2,write:(e,t,s)=>e.setInt16(t,s,!1),read:(e,t)=>e.getInt16(t,!1),toNil:()=>0}}static{this.i32={size:4,write:(e,t,s)=>e.setInt32(t,s,!1),read:(e,t)=>e.getInt32(t,!1),toNil:()=>0}}static{this.f32={size:4,write:(e,t,s)=>e.setFloat32(t,s,!1),read:(e,t)=>e.getFloat32(t,!1),toNil:()=>0}}static{this.f64={size:8,write:(e,t,s)=>e.setFloat64(t,s,!1),read:(e,t)=>e.getFloat64(t,!1),toNil:()=>0}}static{this.bool={size:1,write:(e,t,s)=>e.setUint8(t,s?1:0),read:(e,t)=>e.getUint8(t)!==0,toNil:()=>!1}}static string(e){return{size:e+2,write(t,s,r){let n=new TextEncoder().encode(r);if(n.length>e)throw new RangeError(`String too long, max ${e} bytes`);t.setUint16(s,n.length,!1);for(let i=0;i<n.length;i++)t.setUint8(s+2+i,n[i]);for(let i=n.length;i<e;i++)t.setUint8(s+2+i,0)},read(t,s){let r=t.getUint16(s,!1),o=new Uint8Array(r);for(let n=0;n<r;n++)o[n]=t.getUint8(s+2+n);return new TextDecoder().decode(o)},toNil:()=>""}}static{this.vec2={size:8,write(e,t,s){e.setFloat32(t,s.x,!1),e.setFloat32(t+4,s.y,!1)},read(e,t){return{x:e.getFloat32(t,!1),y:e.getFloat32(t+4,!1)}},toNil:()=>({x:0,y:0})}}static{this.vec3={size:12,write(e,t,s){e.setFloat32(t,s.x,!1),e.setFloat32(t+4,s.y,!1),e.setFloat32(t+8,s.z,!1)},read(e,t){return{x:e.getFloat32(t,!1),y:e.getFloat32(t+4,!1),z:e.getFloat32(t+8,!1)}},toNil:()=>({x:0,y:0,z:0})}}static{this.color={size:4,write(e,t,s){e.setUint8(t,s.r),e.setUint8(t+1,s.g),e.setUint8(t+2,s.b),e.setUint8(t+3,s.a)},read(e,t){return{r:e.getUint8(t),g:e.getUint8(t+1),b:e.getUint8(t+2),a:e.getUint8(t+3)}},toNil:()=>({r:0,g:0,b:0,a:0})}}static{this.f32_le={size:4,write:(e,t,s)=>e.setFloat32(t,s,!0),read:(e,t)=>e.getFloat32(t,!0),toNil:()=>0}}static{this.f64_le={size:8,write:(e,t,s)=>e.setFloat64(t,s,!0),read:(e,t)=>e.getFloat64(t,!0),toNil:()=>0}}static{this.u16_le={size:2,write:(e,t,s)=>e.setUint16(t,s,!0),read:(e,t)=>e.getUint16(t,!0),toNil:()=>0}}static{this.u32_le={size:4,write:(e,t,s)=>e.setUint32(t,s,!0),read:(e,t)=>e.getUint32(t,!0),toNil:()=>0}}static{this.i16_le={size:2,write:(e,t,s)=>e.setInt16(t,s,!0),read:(e,t)=>e.getInt16(t,!0),toNil:()=>0}}static{this.i32_le={size:4,write:(e,t,s)=>e.setInt32(t,s,!0),read:(e,t)=>e.getInt32(t,!0),toNil:()=>0}}static{this.vec2_le={size:8,write:(e,t,s)=>{e.setFloat32(t,s[0],!0),e.setFloat32(t+4,s[1],!0)},read:(e,t)=>[e.getFloat32(t,!0),e.getFloat32(t+4,!0)],toNil:()=>[0,0]}}static{this.vec3_le={size:12,write:(e,t,s)=>{e.setFloat32(t,s[0],!0),e.setFloat32(t+4,s[1],!0),e.setFloat32(t+8,s[2],!0)},read:(e,t)=>[e.getFloat32(t,!0),e.getFloat32(t+4,!0),e.getFloat32(t+8,!0)],toNil:()=>[0,0,0]}}static{this.vec4_le={size:16,write:(e,t,s)=>{e.setFloat32(t,s[0],!0),e.setFloat32(t+4,s[1],!0),e.setFloat32(t+8,s[2],!0),e.setFloat32(t+12,s[3],!0)},read:(e,t)=>[e.getFloat32(t,!0),e.getFloat32(t+4,!0),e.getFloat32(t+8,!0),e.getFloat32(t+12,!0)],toNil:()=>[0,0,0,0]}}},x=class extends S{static{this.u8=y.u8}static{this.u16=y.u16}static{this.u32=y.u32}static{this.i8=y.i8}static{this.i16=y.i16}static{this.i32=y.i32}static{this.f32=y.f32}static{this.bool=y.bool}static{this.string=y.string}static{this.vec2=y.vec2}static{this.vec3=y.vec3}static{this.color=y.color}static encode(e,t){return this.encodeInto(e,t)}static decode(e,t,s){return this.decodeInto(e,t,s)}};var D=class{constructor({events:e}){this.callbacks=new Map,this.events=e;for(let t of this.events)this.callbacks.set(t,new Set)}on(e,t){let s=this.callbacks.get(e);if(!s)return console.warn(`Event "${e}" does not exist.`);s.add(t)}once(e,t){let s=r=>{t(r),this.off(e,s)};this.on(e,s)}emit(e,t){let s=this.callbacks.get(e);if(!s)return console.warn(`Event "${e}" does not exist.`);for(let r of s)r(t)}off(e,t){let s=this.callbacks.get(e);if(!s)return console.warn(`Event "${e}" does not exist.`);s.delete(t)}clear(e){if(!e){this.callbacks.clear();for(let s of this.events)this.callbacks.set(s,new Set);return}let t=this.callbacks.get(e);if(!t)return console.warn(`Event "${e}" does not exist.`);t.clear()}};var _=class{constructor({rate:e,onTick:t}){this.accumulator=0;this._tickCount=0;this.rate=e,this.intervalMs=1e3/this.rate,this.onTick=t,this.maxTicksPerFrame=Math.max(1,Math.floor(e/2))}getTicks(e){this.accumulator+=e*1e3;let t=0;for(;this.accumulator>=this.intervalMs&&t<this.maxTicksPerFrame;)this.accumulator-=this.intervalMs,t++;let s=Math.floor(this.accumulator/this.intervalMs);return s>0&&this.onTickSkipped&&this.onTickSkipped(s),t}tick(e){let t=this.getTicks(e);for(let s=0;s<t;s++)this.onTick(1/this.rate,this._tickCount++)}get tickCount(){return this._tickCount}resetTickCount(){this._tickCount=0}get accumulatedTime(){return this.accumulator/1e3}get alpha(){return Math.min(this.accumulatedTime/(1/this.rate),1)}};function me(l={}){let{prefix:e="",size:t=16}=l,s=Math.max(t-e.length,8),r=Math.ceil(s/8),n=crypto.getRandomValues(new Uint32Array(r)).reduce((i,a)=>i+a.toString(16).padStart(8,"0"),"");return n=n.slice(0,s).padStart(s,"0"),`${e}${n}`}function xe(l,e,t){return l+(e-l)*t}var v=class{constructor(e){this.update=e;this.last=performance.now();this.running=!1;this.loop=()=>{if(!this.running)return;let e=performance.now(),t=(e-this.last)/1e3;this.last=e,this.update(t),setImmediate(this.loop)}}start(){this.running=!0,this.last=performance.now(),this.loop()}stop(){this.running=!1}};var w=class{constructor(e){this.update=e;this.last=performance.now();this.running=!1;this.rafId=null;this.loop=()=>{if(!this.running)return;let e=performance.now(),t=(e-this.last)/1e3;this.last=e,this.update(t),requestAnimationFrame(this.loop)}}start(){this.running=!0,this.last=performance.now(),this.rafId=requestAnimationFrame(this.loop)}stop(){this.running=!1,this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}};var te=1,T=class{constructor(e){this.update=e;this.last=performance.now();this.running=!1;this.loop=()=>{if(!this.running)return;let e=performance.now(),t=(e-this.last)/1e3;this.last=e,this.update(t),setTimeout(this.loop,te)}}start(){this.running=!0,this.last=performance.now(),this.loop()}stop(){this.running=!1}};function Ue(l,e){return l==="server-immediate"?new v(e):l==="server-timeout"?new T(e):new w(e)}var se=[{x:1,y:0},{x:-1,y:0},{x:0,y:1},{x:0,y:-1}],z=l=>({x:Math.floor(l.x),y:Math.floor(l.y)}),L=l=>({x:l.x+.5,y:l.y+.5}),re=(()=>{let l=1;return()=>l++})(),b=(l,e)=>l&65535|(e&65535)<<16,M=l=>({x:l<<16>>16,y:l>>16}),F=class{constructor(e){this.scoreFn=e;this.heap=[]}push(e){this.heap.push(e),this.bubbleUp(this.heap.length-1)}pop(){let e=this.heap[0],t=this.heap.pop();return this.heap.length>0&&t!==void 0&&(this.heap[0]=t,this.sinkDown(0)),e}get size(){return this.heap.length}bubbleUp(e){let t=this.heap[e],s=this.scoreFn(t);for(;e>0;){let r=(e+1>>1)-1,o=this.heap[r];if(s>=this.scoreFn(o))break;this.heap[r]=t,this.heap[e]=o,e=r}}sinkDown(e){let t=this.heap.length,s=this.heap[e],r=this.scoreFn(s);for(;;){let o=e+1<<1,n=o-1,i=null,a;if(n<t){let c=this.heap[n];a=this.scoreFn(c),a<r&&(i=n)}if(o<t){let c=this.heap[o];this.scoreFn(c)<(i===null?r:a)&&(i=o)}if(i===null)break;this.heap[e]=this.heap[i],this.heap[i]=s,e=i}}},P=class{constructor(e=1){this.grid=new Map;this.obstacleCells=new Map;this.cellSize=e}hash(e,t){let s=Math.floor(e/this.cellSize),r=Math.floor(t/this.cellSize);return b(s,r)}add(e,t){let s=this.getCellsForObstacle(t);for(let r of s)this.grid.has(r)||this.grid.set(r,new Set),this.grid.get(r).add(e);this.obstacleCells.set(e,s)}remove(e){let t=this.obstacleCells.get(e);if(t){for(let s of t){let r=this.grid.get(s);r&&(r.delete(e),r.size===0&&this.grid.delete(s))}this.obstacleCells.delete(e)}}query(e){let t=this.hash(e.x,e.y);return this.grid.get(t)||new Set}clear(){this.grid.clear(),this.obstacleCells.clear()}getCellsForObstacle(e){let t=new Set;if(e.type==="circle"){let s=e.radius,r=Math.floor((e.pos.x-s)/this.cellSize),o=Math.floor((e.pos.x+s)/this.cellSize),n=Math.floor((e.pos.y-s)/this.cellSize),i=Math.floor((e.pos.y+s)/this.cellSize);for(let a=r;a<=o;a++)for(let c=n;c<=i;c++)t.add(b(a,c))}else if(e.type==="rect"){let s=e.pos.x+e.size.x/2,r=e.pos.y+e.size.y/2,o=e.size.x/2,n=e.size.y/2,i=Math.sqrt(o*o+n*n),a=Math.floor((s-i)/this.cellSize),c=Math.floor((s+i)/this.cellSize),u=Math.floor((r-i)/this.cellSize),d=Math.floor((r+i)/this.cellSize);for(let h=a;h<=c;h++)for(let f=u;f<=d;f++)t.add(b(h,f))}else if(e.type==="polygon"){let s=B(e),r=Math.floor(s.minX/this.cellSize),o=Math.floor(s.maxX/this.cellSize),n=Math.floor(s.minY/this.cellSize),i=Math.floor(s.maxY/this.cellSize);for(let a=r;a<=o;a++)for(let c=n;c<=i;c++)t.add(b(a,c))}return t}};function Y(l,e){let t=l.x-e.pos.x,s=l.y-e.pos.y;return t*t+s*s<=e.radius*e.radius}function X(l,e){let t=e.pos.x+e.size.x/2,s=e.pos.y+e.size.y/2;if(e.rotation){let r=Math.cos(-e.rotation),o=Math.sin(-e.rotation),n=l.x-t,i=l.y-s,a=n*r-i*o,c=n*o+i*r;return Math.abs(a)<=e.size.x/2&&Math.abs(c)<=e.size.y/2}return l.x>=e.pos.x&&l.y>=e.pos.y&&l.x<=e.pos.x+e.size.x&&l.y<=e.pos.y+e.size.y}function K(l,e){let t=!1,s=e.points,r=e.rotation?Math.cos(e.rotation):1,o=e.rotation?Math.sin(e.rotation):0;for(let n=0,i=s.length-1;n<s.length;i=n++){let a=s[n].x,c=s[n].y,u=s[i].x,d=s[i].y;if(e.rotation){let f=a*r-c*o,m=a*o+c*r,p=u*r-d*o,k=u*o+d*r;a=f,c=m,u=p,d=k}a+=e.pos.x,c+=e.pos.y,u+=e.pos.x,d+=e.pos.y,c>l.y!=d>l.y&&l.x<(u-a)*(l.y-c)/(d-c)+a&&(t=!t)}return t}function B(l){let e=1/0,t=1/0,s=-1/0,r=-1/0,o=l.rotation?Math.cos(l.rotation):1,n=l.rotation?Math.sin(l.rotation):0;for(let i of l.points){let a=i.x,c=i.y;if(l.rotation){let u=a*o-c*n,d=a*n+c*o;a=u,c=d}a+=l.pos.x,c+=l.pos.y,e=Math.min(e,a),t=Math.min(t,c),s=Math.max(s,a),r=Math.max(r,c)}return{minX:e,minY:t,maxX:s,maxY:r}}var U=class{constructor(){this.items=new Map;this.spatial=new P(1);this._cachedItems=[];this.dirty=!0;this.version=0}add(e){let t=re(),s={...e,id:t};return this.items.set(t,s),this.spatial.add(t,s),this.dirty=!0,this.version++,t}move(e,t){let s=this.items.get(e);if(!s)return;this.spatial.remove(e);let r={...s,pos:{...t}};this.items.set(e,r),this.spatial.add(e,r),this.dirty=!0,this.version++}remove(e){this.spatial.remove(e),this.items.delete(e),this.dirty=!0,this.version++}at(e){let t=this.spatial.query(e);for(let s of t){let r=this.items.get(s);if(!(!r||r.solid===!1)&&(r.type==="circle"&&Y(e,r)||r.type==="rect"&&X(e,r)||r.type==="polygon"&&K(e,r)))return r}}get values(){return this.dirty?(this._cachedItems=[...this.items.values()],this.dirty=!1,this._cachedItems):this._cachedItems}},I=class{constructor(e){this.obstacles=e;this.blocked=new Set}rebuild(){this.blocked.clear();for(let e of this.obstacles.values)if(e.solid!==!1){if(e.type==="circle"){let t=Math.ceil(e.radius),s=Math.floor(e.pos.x),r=Math.floor(e.pos.y);for(let o=-t;o<=t;o++)for(let n=-t;n<=t;n++){let i=s+o,a=r+n,c={x:i+.5,y:a+.5};Y(c,e)&&this.blocked.add(b(i,a))}}else if(e.type==="rect"){let t=e.pos.x+e.size.x/2,s=e.pos.y+e.size.y/2,r=e.size.x/2,o=e.size.y/2,n=Math.sqrt(r*r+o*o),i=Math.floor(t-n),a=Math.ceil(t+n),c=Math.floor(s-n),u=Math.ceil(s+n);for(let d=i;d<=a;d++)for(let h=c;h<=u;h++){let f={x:d+.5,y:h+.5};X(f,e)&&this.blocked.add(b(d,h))}}else if(e.type==="polygon"){let t=B(e),s=Math.floor(t.minX),r=Math.ceil(t.maxX),o=Math.floor(t.minY),n=Math.ceil(t.maxY);for(let i=s;i<=r;i++)for(let a=o;a<=n;a++){let c={x:i+.5,y:a+.5};K(c,e)&&this.blocked.add(b(i,a))}}}}findPath(e,t){return $(z(e),z(t),(s,r)=>!this.blocked.has(b(s,r))).map(L)}},V=class{constructor(e){this.obstacles=e}rebuild(){}findPath(e,t){let s=Math.ceil(Math.hypot(t.x-e.x,t.y-e.y)*2),r=!1;for(let n=1;n<=s;n++){let i=n/s,a={x:e.x+(t.x-e.x)*i,y:e.y+(t.y-e.y)*i};if(this.obstacles.at(a)){r=!0;break}}return r?$(z(e),z(t),(n,i)=>{let a={x:n+.5,y:i+.5};return!this.obstacles.at(a)}).map(L):[e,t]}},q=class{constructor(e,t){this.type=e;this.lastVersion=-1;this.pendingPaths=0;this.AUTO_WORKER_THRESHOLD=20;this.obstacles=new U,this.options={workers:t?.workers??!1,workerPoolSize:t?.workerPoolSize??4,workerPath:t?.workerPath??"./navmesh.worker.js"},e==="grid"&&(this.grid=new I(this.obstacles)),e==="graph"&&(this.graph=new V(this.obstacles)),this.options.workers===!0&&this.initWorkerPool()}async initWorkerPool(){if(!this.workerPool)try{let{NavMeshWorkerPool:e}=await Promise.resolve().then(()=>(j(),W));this.workerPool=new e(this.options.workerPoolSize,this.options.workerPath,this.type,this.obstacles.values),await this.workerPool.init()}catch(e){console.warn("Failed to initialize worker pool, falling back to sync:",e),this.options.workers=!1}}shouldUseWorkers(){return this.options.workers===!1?!1:this.options.workers===!0?!0:this.pendingPaths>=this.AUTO_WORKER_THRESHOLD}addObstacle(e){return this.obstacles.add(e)}moveObstacle(e,t){this.obstacles.move(e,t)}removeObstacle(e){this.obstacles.remove(e)}getObstacles(){return this.obstacles.values}findPath({from:e,to:t}){return this.shouldUseWorkers()&&this.workerPool?(this.pendingPaths++,this.findPathAsync(e,t).finally(()=>{this.pendingPaths--})):(this.rebuild(),this.type==="grid"?this.grid.findPath(e,t):this.graph.findPath(e,t))}async findPathAsync(e,t){return this.options.workers==="auto"&&!this.workerPool&&await this.initWorkerPool(),this.workerPool?this.workerPool.findPath(e,t):(this.rebuild(),this.type==="grid"?this.grid.findPath(e,t):this.graph.findPath(e,t))}rebuild(){this.lastVersion!==this.obstacles.version&&(this.grid?.rebuild(),this.graph?.rebuild(),this.lastVersion=this.obstacles.version)}dispose(){this.workerPool&&(this.workerPool.terminate(),this.workerPool=void 0)}getWorkerStatus(){return{workersEnabled:this.options.workers,workerPoolActive:!!this.workerPool,pendingPaths:this.pendingPaths,usingWorkersNow:this.shouldUseWorkers()}}};function $(l,e,t){let s=new Map,r=new Map,o=new Set,n=new Set,i=d=>b(d.x,d.y),a=(d,h)=>Math.abs(d.x-h.x)+Math.abs(d.y-h.y),c=new F(d=>{let h=M(d);return r.get(d)+a(h,e)}),u=i(l);for(r.set(u,0),c.push(u),n.add(u);c.size>0;){let d=c.pop();n.delete(d);let h=M(d);if(h.x===e.x&&h.y===e.y)return ne(s,h);o.add(d);for(let f of se){let m={x:h.x+f.x,y:h.y+f.y};if(!t(m.x,m.y))continue;let p=i(m);if(o.has(p))continue;let k=r.get(d)+1;k<(r.get(p)??1/0)&&(r.set(p,k),s.set(p,d),n.has(p)||(c.push(p),n.add(p)))}}return[]}function ne(l,e){let t=[e],s=b(e.x,e.y);for(;l.has(s);)s=l.get(s),t.push(M(s));return t.reverse()}var g=class{constructor(e){this.factory=e;this.pool=[]}acquire(){return this.pool.pop()??this.factory()}release(e){this.pool.push(e)}releaseAll(e){this.pool.push(...e)}},O=class{constructor(e){this.schema=e;this.pool=new g(()=>this.createNil())}createNil(){let e={};for(let t of Object.keys(this.schema)){let s=this.schema[t];e[t]="toNil"in s?s.toNil():void 0}return e}decode(e){let t=this.pool.acquire();return this.decodeInto(e,t),t}decodeInto(e,t){let s=0;for(let r of Object.keys(this.schema)){let o=this.schema[r];if("decodeAll"in o){let n=o.decodeAll(e.subarray(s));t[r]=n.value,s+=n.bytesRead}else if("decodeField"in o){let n=o.decodeField(e.subarray(s));t[r]=n.value,s+=n.bytesRead}else if("decode"in o){let n=o.decode(e.subarray(s));t[r]=n.value,s+=n.bytesRead}else{let n=o.size||0,i=e.subarray(s,s+n);x.decodeInto({[r]:o},i,t),s+=n}}}release(e){this.pool.release(e)}},H=class{constructor(e){this.pooledDecoder=new O(e)}decodeAll(e){return e.map(t=>this.pooledDecoder.decode(t))}releaseAll(e){e.forEach(t=>this.pooledDecoder.release(t))}},A=class{constructor(e,t=1024){this.schema=e;this.bufferSize=t;this.pool=new g(()=>new Uint8Array(t))}encode(e){let t=this.pool.acquire(),s=0;for(let r of Object.keys(this.schema)){let o=this.schema[r];if("encode"in o){let n=o.encode(e[r]);t.set(n,s),s+=n.length}else if("encodeAll"in o){let n=o.encodeAll(e[r]),i=0;for(let a of n)t.set(a,s+i),i+=a.length;s+=i}else{let n=x.encode({[r]:o},{[r]:e[r]});t.set(n,s),s+=n.length}}return t.subarray(0,s)}release(e){this.pool.release(e)}},G=class{constructor(e){this.schema=e;this.encoder=new A(e),this.decoder=new O(e)}calculateSize(e){let t=0;for(let s of Object.keys(this.schema)){let r=this.schema[s];"size"in r?t+=r.size:"calculateSize"in r&&(t+=r.calculateSize(e[s]))}return t}encodeInto(e,t,s){let r=new DataView(t.buffer,t.byteOffset),o=s;for(let n of Object.keys(this.schema)){let i=this.schema[n];if("write"in i)i.write(r,o,e[n]),o+=i.size;else if("encodeInto"in i){let a=i.encodeInto(e[n],t,o);o+=a}else if("encode"in i){let a=i.encode(e[n]);t.set(a,o),o+=a.length}}return o-s}encode(e){return this.encoder.encode(e)}decode(e){return this.decoder.decode(e)}release(e){this.decoder.release(e)}static array(e){let t=0;for(let a of Object.keys(e)){let c=e[a];t+=c.size||0}let s=new g(()=>new Uint8Array(16384)),r=new g(()=>{let a={};for(let c of Object.keys(e)){let u=e[c];a[c]="toNil"in u?u.toNil():void 0}return a}),o=new g(()=>[]),n=null,i=null;return{__arrayType:void 0,calculateSize(a){return 2+a.length*t},encodeInto(a,c,u){let d=new DataView(c.buffer,c.byteOffset);d.setUint16(u,a.length,!1);let h=u+2;for(let f of a)for(let m of Object.keys(e)){let p=e[m];p.write(d,h,f[m]),h+=p.size}return h-u},encode(a){let c=2+a.length*t,u=s.acquire();u.length<c&&(s.release(u),u=new Uint8Array(Math.max(c,u.length*2))),(!n||n.buffer!==u.buffer)&&(n=new DataView(u.buffer,u.byteOffset)),n.setUint16(0,a.length,!1);let d=2;for(let f of a)for(let m of Object.keys(e)){let p=e[m];p.write(n,d,f[m]),d+=p.size}let h=new Uint8Array(d);return h.set(u.subarray(0,d)),s.release(u),h},decodeField(a){let c=a[0]<<8|a[1],u=o.acquire();u.length=c,(!i||i.buffer!==a.buffer||i.byteOffset!==a.byteOffset)&&(i=new DataView(a.buffer,a.byteOffset));let d=2;for(let h=0;h<c;h++){let f=r.acquire();for(let m of Object.keys(e)){let p=e[m];f[m]=p.read(i,d),d+=p.size}u[h]=f}return{value:u,bytesRead:d}},decode(a){return this.decodeField(a).value},toNil(){return[]}}}};var R=class{constructor(){this.tracker=new Map}get size(){return this.tracker.size}track(e,t){return this.tracker.has(e)||this.tracker.set(e,[]),this.tracker.get(e).push(t),t}dropUpTo(e){let t=[];for(let[s,r]of this.tracker)s<=e?this.tracker.delete(s):t.push([s,r]);return t.sort(([s],[r])=>s-r),t.map(([s,r])=>r).flat()}values(){return Array.from(this.tracker.entries()).sort(([e],[t])=>e-t).map(([e,t])=>t).flat()}},Z=class{constructor(e){this.options=e;this.tracker=new R}trackIntent(e,t){this.tracker.track(e,t)}onSnapshot(e){this.options.onLoadState(e.state);let t=this.tracker.dropUpTo(e.tick);t.length>0&&this.options.onReplay(t)}replay(e){this.options.onReplay(e)}};export{S as BaseBinaryCodec,x as BinaryCodec,y as BinaryPrimitives,D as EventSystem,_ as FixedTicker,v as ImmediateDriver,R as IntentTracker,q as NavMesh,g as ObjectPool,H as PooledArrayDecoder,G as PooledCodec,O as PooledDecoder,A as PooledEncoder,w as RafDriver,Z as Reconciliator,T as TimeoutDriver,Ue as createDriver,me as generateId,xe as lerp};
|