@phalanx-engine/client 0.1.0

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.
Files changed (94) hide show
  1. package/README.md +1037 -0
  2. package/dist/DesyncDetector.d.ts +80 -0
  3. package/dist/DesyncDetector.d.ts.map +1 -0
  4. package/dist/DesyncDetector.js +93 -0
  5. package/dist/DesyncDetector.js.map +1 -0
  6. package/dist/DeterministicRandom.d.ts +78 -0
  7. package/dist/DeterministicRandom.d.ts.map +1 -0
  8. package/dist/DeterministicRandom.js +122 -0
  9. package/dist/DeterministicRandom.js.map +1 -0
  10. package/dist/EventEmitter.d.ts +65 -0
  11. package/dist/EventEmitter.d.ts.map +1 -0
  12. package/dist/EventEmitter.js +102 -0
  13. package/dist/EventEmitter.js.map +1 -0
  14. package/dist/FixedMath.d.ts +22 -0
  15. package/dist/FixedMath.d.ts.map +1 -0
  16. package/dist/FixedMath.js +26 -0
  17. package/dist/FixedMath.js.map +1 -0
  18. package/dist/PhalanxClient.d.ts +335 -0
  19. package/dist/PhalanxClient.d.ts.map +1 -0
  20. package/dist/PhalanxClient.js +844 -0
  21. package/dist/PhalanxClient.js.map +1 -0
  22. package/dist/RenderLoop.d.ts +95 -0
  23. package/dist/RenderLoop.d.ts.map +1 -0
  24. package/dist/RenderLoop.js +192 -0
  25. package/dist/RenderLoop.js.map +1 -0
  26. package/dist/SocketManager.d.ts +228 -0
  27. package/dist/SocketManager.d.ts.map +1 -0
  28. package/dist/SocketManager.js +584 -0
  29. package/dist/SocketManager.js.map +1 -0
  30. package/dist/StateHasher.d.ts +76 -0
  31. package/dist/StateHasher.d.ts.map +1 -0
  32. package/dist/StateHasher.js +129 -0
  33. package/dist/StateHasher.js.map +1 -0
  34. package/dist/auth/AuthManager.d.ts +188 -0
  35. package/dist/auth/AuthManager.d.ts.map +1 -0
  36. package/dist/auth/AuthManager.js +462 -0
  37. package/dist/auth/AuthManager.js.map +1 -0
  38. package/dist/auth/adapters/GoogleOAuthAdapter.d.ts +164 -0
  39. package/dist/auth/adapters/GoogleOAuthAdapter.d.ts.map +1 -0
  40. package/dist/auth/adapters/GoogleOAuthAdapter.js +521 -0
  41. package/dist/auth/adapters/GoogleOAuthAdapter.js.map +1 -0
  42. package/dist/auth/index.d.ts +45 -0
  43. package/dist/auth/index.d.ts.map +1 -0
  44. package/dist/auth/index.js +54 -0
  45. package/dist/auth/index.js.map +1 -0
  46. package/dist/auth/storage.d.ts +56 -0
  47. package/dist/auth/storage.d.ts.map +1 -0
  48. package/dist/auth/storage.js +78 -0
  49. package/dist/auth/storage.js.map +1 -0
  50. package/dist/auth/types.d.ts +212 -0
  51. package/dist/auth/types.d.ts.map +1 -0
  52. package/dist/auth/types.js +7 -0
  53. package/dist/auth/types.js.map +1 -0
  54. package/dist/index.d.ts +70 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +83 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/recovery/BrowserLifecycle.d.ts +33 -0
  59. package/dist/recovery/BrowserLifecycle.d.ts.map +1 -0
  60. package/dist/recovery/BrowserLifecycle.js +62 -0
  61. package/dist/recovery/BrowserLifecycle.js.map +1 -0
  62. package/dist/recovery/GuestPlayerIdStore.d.ts +17 -0
  63. package/dist/recovery/GuestPlayerIdStore.d.ts.map +1 -0
  64. package/dist/recovery/GuestPlayerIdStore.js +31 -0
  65. package/dist/recovery/GuestPlayerIdStore.js.map +1 -0
  66. package/dist/recovery/KeyValueStorage.d.ts +32 -0
  67. package/dist/recovery/KeyValueStorage.d.ts.map +1 -0
  68. package/dist/recovery/KeyValueStorage.js +58 -0
  69. package/dist/recovery/KeyValueStorage.js.map +1 -0
  70. package/dist/recovery/MobileTransport.d.ts +12 -0
  71. package/dist/recovery/MobileTransport.d.ts.map +1 -0
  72. package/dist/recovery/MobileTransport.js +24 -0
  73. package/dist/recovery/MobileTransport.js.map +1 -0
  74. package/dist/recovery/NetworkQuality.d.ts +22 -0
  75. package/dist/recovery/NetworkQuality.d.ts.map +1 -0
  76. package/dist/recovery/NetworkQuality.js +35 -0
  77. package/dist/recovery/NetworkQuality.js.map +1 -0
  78. package/dist/recovery/RoomPersistence.d.ts +55 -0
  79. package/dist/recovery/RoomPersistence.d.ts.map +1 -0
  80. package/dist/recovery/RoomPersistence.js +68 -0
  81. package/dist/recovery/RoomPersistence.js.map +1 -0
  82. package/dist/recovery/RoomRecoveryController.d.ts +146 -0
  83. package/dist/recovery/RoomRecoveryController.d.ts.map +1 -0
  84. package/dist/recovery/RoomRecoveryController.js +348 -0
  85. package/dist/recovery/RoomRecoveryController.js.map +1 -0
  86. package/dist/recovery/index.d.ts +13 -0
  87. package/dist/recovery/index.d.ts.map +1 -0
  88. package/dist/recovery/index.js +8 -0
  89. package/dist/recovery/index.js.map +1 -0
  90. package/dist/types.d.ts +501 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +6 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +66 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * DesyncDetector - Handles desync detection for lockstep synchronization
3
+ *
4
+ * Stores local state hashes and compares them with remote hashes
5
+ * received from other players via the server.
6
+ */
7
+ import { EventEmitter } from './EventEmitter.js';
8
+ /**
9
+ * Configuration for desync detection
10
+ */
11
+ export interface DesyncConfig {
12
+ /** Whether desync detection is enabled */
13
+ enabled: boolean;
14
+ /** Maximum number of hashes to store (default: 100) */
15
+ maxStoredHashes?: number;
16
+ }
17
+ /**
18
+ * Event emitted when a desync is detected
19
+ */
20
+ export interface DesyncEvent {
21
+ /** The tick where desync occurred */
22
+ tick: number;
23
+ /** The local hash for this tick */
24
+ localHash: string;
25
+ /** Hashes from all players (playerId -> hash) */
26
+ remoteHashes: Record<string, string>;
27
+ }
28
+ /**
29
+ * Events emitted by DesyncDetector
30
+ */
31
+ export interface DesyncDetectorEvents {
32
+ desync: (event: DesyncEvent) => void;
33
+ }
34
+ /**
35
+ * DesyncDetector - Internal class for managing desync detection
36
+ *
37
+ * The game computes state hashes and submits them via the client.
38
+ * This class stores local hashes and compares with remote hashes
39
+ * when the server broadcasts a comparison.
40
+ */
41
+ export declare class DesyncDetector extends EventEmitter<DesyncDetectorEvents> {
42
+ private config;
43
+ private hashHistory;
44
+ /**
45
+ * Configure the desync detector
46
+ */
47
+ configure(config: Partial<DesyncConfig>): void;
48
+ /**
49
+ * Check if desync detection is enabled
50
+ */
51
+ isEnabled(): boolean;
52
+ /**
53
+ * Record local hash (called by game via client.submitStateHash)
54
+ * @param tick - The tick this hash is for
55
+ * @param hash - Hash computed by game
56
+ */
57
+ recordLocalHash(tick: number, hash: string): void;
58
+ /**
59
+ * Get local hash for a specific tick
60
+ * @param tick - The tick to get hash for
61
+ * @returns The hash string or undefined if not found
62
+ */
63
+ getLocalHash(tick: number): string | undefined;
64
+ /**
65
+ * Compare local hash with remote hashes
66
+ * @param tick - The tick to compare
67
+ * @param remoteHashes - Hashes from all players (playerId -> hash)
68
+ * @returns true if all hashes match, false if desync detected
69
+ */
70
+ compareWithRemote(tick: number, remoteHashes: Record<string, string>): boolean;
71
+ /**
72
+ * Clear all stored hashes
73
+ */
74
+ clear(): void;
75
+ /**
76
+ * Get the current configuration
77
+ */
78
+ getConfig(): Required<DesyncConfig>;
79
+ }
80
+ //# sourceMappingURL=DesyncDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesyncDetector.d.ts","sourceRoot":"","sources":["../src/DesyncDetector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACtC;AAED;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IACpE,OAAO,CAAC,MAAM,CAGZ;IACF,OAAO,CAAC,WAAW,CAAkC;IAErD;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAS9C;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAYjD;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI9C;;;;;OAKG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO;IAiB9E;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,YAAY,CAAC;CAGpC"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * DesyncDetector - Handles desync detection for lockstep synchronization
3
+ *
4
+ * Stores local state hashes and compares them with remote hashes
5
+ * received from other players via the server.
6
+ */
7
+ import { EventEmitter } from './EventEmitter.js';
8
+ /**
9
+ * DesyncDetector - Internal class for managing desync detection
10
+ *
11
+ * The game computes state hashes and submits them via the client.
12
+ * This class stores local hashes and compares with remote hashes
13
+ * when the server broadcasts a comparison.
14
+ */
15
+ export class DesyncDetector extends EventEmitter {
16
+ config = {
17
+ enabled: true,
18
+ maxStoredHashes: 100,
19
+ };
20
+ hashHistory = new Map();
21
+ /**
22
+ * Configure the desync detector
23
+ */
24
+ configure(config) {
25
+ if (config.enabled !== undefined) {
26
+ this.config.enabled = config.enabled;
27
+ }
28
+ if (config.maxStoredHashes !== undefined) {
29
+ this.config.maxStoredHashes = config.maxStoredHashes;
30
+ }
31
+ }
32
+ /**
33
+ * Check if desync detection is enabled
34
+ */
35
+ isEnabled() {
36
+ return this.config.enabled;
37
+ }
38
+ /**
39
+ * Record local hash (called by game via client.submitStateHash)
40
+ * @param tick - The tick this hash is for
41
+ * @param hash - Hash computed by game
42
+ */
43
+ recordLocalHash(tick, hash) {
44
+ if (!this.config.enabled)
45
+ return;
46
+ this.hashHistory.set(tick, hash);
47
+ // Prune old hashes
48
+ if (this.hashHistory.size > this.config.maxStoredHashes) {
49
+ const oldestTick = Math.min(...this.hashHistory.keys());
50
+ this.hashHistory.delete(oldestTick);
51
+ }
52
+ }
53
+ /**
54
+ * Get local hash for a specific tick
55
+ * @param tick - The tick to get hash for
56
+ * @returns The hash string or undefined if not found
57
+ */
58
+ getLocalHash(tick) {
59
+ return this.hashHistory.get(tick);
60
+ }
61
+ /**
62
+ * Compare local hash with remote hashes
63
+ * @param tick - The tick to compare
64
+ * @param remoteHashes - Hashes from all players (playerId -> hash)
65
+ * @returns true if all hashes match, false if desync detected
66
+ */
67
+ compareWithRemote(tick, remoteHashes) {
68
+ const localHash = this.hashHistory.get(tick);
69
+ if (!localHash) {
70
+ // Can't compare - no local hash for this tick
71
+ return true;
72
+ }
73
+ const allMatch = Object.values(remoteHashes).every((h) => h === localHash);
74
+ if (!allMatch) {
75
+ this.emit('desync', { tick, localHash, remoteHashes });
76
+ return false;
77
+ }
78
+ return true;
79
+ }
80
+ /**
81
+ * Clear all stored hashes
82
+ */
83
+ clear() {
84
+ this.hashHistory.clear();
85
+ }
86
+ /**
87
+ * Get the current configuration
88
+ */
89
+ getConfig() {
90
+ return { ...this.config };
91
+ }
92
+ }
93
+ //# sourceMappingURL=DesyncDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesyncDetector.js","sourceRoot":"","sources":["../src/DesyncDetector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA+BjD;;;;;;GAMG;AACH,MAAM,OAAO,cAAe,SAAQ,YAAkC;IAC5D,MAAM,GAA2B;QACvC,OAAO,EAAE,IAAI;QACb,eAAe,EAAE,GAAG;KACrB,CAAC;IACM,WAAW,GAAwB,IAAI,GAAG,EAAE,CAAC;IAErD;;OAEG;IACH,SAAS,CAAC,MAA6B;QACrC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QACvC,CAAC;QACD,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;QACvD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,IAAY,EAAE,IAAY;QACxC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO;QAEjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEjC,mBAAmB;QACnB,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACxD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,IAAY;QACvB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,iBAAiB,CAAC,IAAY,EAAE,YAAoC;QAClE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,8CAA8C;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAE3E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;YACvD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,78 @@
1
+ import prand from 'pure-rand';
2
+ /**
3
+ * Deterministic Random Number Generator
4
+ *
5
+ * Wrapper around pure-rand library for deterministic pseudo-random number generation.
6
+ * All clients initialized with the same seed will produce identical sequences.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const rng = new DeterministicRandom(12345);
11
+ * const damage = rng.intRange(10, 20); // Same on all clients with same seed
12
+ * ```
13
+ */
14
+ export declare class DeterministicRandom {
15
+ private rng;
16
+ /**
17
+ * Create a new deterministic RNG with the given seed
18
+ * @param seed - A number seed value
19
+ */
20
+ constructor(seed: number);
21
+ /**
22
+ * Generate next random 32-bit integer and advance state
23
+ */
24
+ private nextInt;
25
+ /**
26
+ * Get next random float in range [0, 1)
27
+ */
28
+ float(): number;
29
+ /**
30
+ * Get next random float in range [min, max)
31
+ * @param min - Minimum value (inclusive)
32
+ * @param max - Maximum value (exclusive)
33
+ */
34
+ floatRange(min: number, max: number): number;
35
+ /**
36
+ * Get next random integer in range [min, max]
37
+ * @param min - Minimum value (inclusive)
38
+ * @param max - Maximum value (inclusive)
39
+ */
40
+ intRange(min: number, max: number): number;
41
+ /**
42
+ * Get next random integer in range [0, max)
43
+ * @param max - Maximum value (exclusive)
44
+ */
45
+ int(max: number): number;
46
+ /**
47
+ * Get next random boolean
48
+ * @param probability - Probability of true (default 0.5)
49
+ */
50
+ boolean(probability?: number): boolean;
51
+ /**
52
+ * Get a random element from an array
53
+ * @param array - Array to pick from
54
+ */
55
+ pick<T>(array: readonly T[]): T;
56
+ /**
57
+ * Shuffle an array in place using Fisher-Yates algorithm
58
+ * @param array - Array to shuffle
59
+ * @returns The same array, shuffled
60
+ */
61
+ shuffle<T>(array: T[]): T[];
62
+ /**
63
+ * Create a fork of this RNG with independent state
64
+ * Useful for parallel simulations that need separate random streams
65
+ */
66
+ fork(): DeterministicRandom;
67
+ /**
68
+ * Get current generator for serialization
69
+ * Note: pure-rand generators are immutable, so this returns a copy
70
+ */
71
+ getGenerator(): prand.RandomGenerator;
72
+ /**
73
+ * Set generator from previously saved state
74
+ * @param generator - Previously saved generator
75
+ */
76
+ setGenerator(generator: prand.RandomGenerator): void;
77
+ }
78
+ //# sourceMappingURL=DeterministicRandom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeterministicRandom.d.ts","sourceRoot":"","sources":["../src/DeterministicRandom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,WAAW,CAAC;AAE9B;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAwB;IAEnC;;;OAGG;gBACS,IAAI,EAAE,MAAM;IAKxB;;OAEG;IACH,OAAO,CAAC,OAAO;IAMf;;OAEG;IACH,KAAK,IAAI,MAAM;IAMf;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAI5C;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAQ1C;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIxB;;;OAGG;IACH,OAAO,CAAC,WAAW,GAAE,MAAY,GAAG,OAAO;IAI3C;;;OAGG;IACH,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC;IAO/B;;;;OAIG;IACH,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;IAU3B;;;OAGG;IACH,IAAI,IAAI,mBAAmB;IAM3B;;;OAGG;IACH,YAAY,IAAI,KAAK,CAAC,eAAe;IAIrC;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,eAAe,GAAG,IAAI;CAGrD"}
@@ -0,0 +1,122 @@
1
+ import prand from 'pure-rand';
2
+ /**
3
+ * Deterministic Random Number Generator
4
+ *
5
+ * Wrapper around pure-rand library for deterministic pseudo-random number generation.
6
+ * All clients initialized with the same seed will produce identical sequences.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const rng = new DeterministicRandom(12345);
11
+ * const damage = rng.intRange(10, 20); // Same on all clients with same seed
12
+ * ```
13
+ */
14
+ export class DeterministicRandom {
15
+ rng;
16
+ /**
17
+ * Create a new deterministic RNG with the given seed
18
+ * @param seed - A number seed value
19
+ */
20
+ constructor(seed) {
21
+ // Use xoroshiro128+ algorithm - fast and high quality
22
+ this.rng = prand.xoroshiro128plus(seed);
23
+ }
24
+ /**
25
+ * Generate next random 32-bit integer and advance state
26
+ */
27
+ nextInt() {
28
+ const [value, next] = this.rng.next();
29
+ this.rng = next;
30
+ return value;
31
+ }
32
+ /**
33
+ * Get next random float in range [0, 1)
34
+ */
35
+ float() {
36
+ // Use unsigned 32-bit integer for conversion
37
+ const value = this.nextInt() >>> 0;
38
+ return value / 0x100000000;
39
+ }
40
+ /**
41
+ * Get next random float in range [min, max)
42
+ * @param min - Minimum value (inclusive)
43
+ * @param max - Maximum value (exclusive)
44
+ */
45
+ floatRange(min, max) {
46
+ return min + this.float() * (max - min);
47
+ }
48
+ /**
49
+ * Get next random integer in range [min, max]
50
+ * @param min - Minimum value (inclusive)
51
+ * @param max - Maximum value (inclusive)
52
+ */
53
+ intRange(min, max) {
54
+ min = Math.floor(min);
55
+ max = Math.floor(max);
56
+ const [value, next] = prand.uniformIntDistribution(min, max)(this.rng);
57
+ this.rng = next;
58
+ return value;
59
+ }
60
+ /**
61
+ * Get next random integer in range [0, max)
62
+ * @param max - Maximum value (exclusive)
63
+ */
64
+ int(max) {
65
+ return this.intRange(0, max - 1);
66
+ }
67
+ /**
68
+ * Get next random boolean
69
+ * @param probability - Probability of true (default 0.5)
70
+ */
71
+ boolean(probability = 0.5) {
72
+ return this.float() < probability;
73
+ }
74
+ /**
75
+ * Get a random element from an array
76
+ * @param array - Array to pick from
77
+ */
78
+ pick(array) {
79
+ if (array.length === 0) {
80
+ throw new Error('Cannot pick from empty array');
81
+ }
82
+ return array[this.intRange(0, array.length - 1)];
83
+ }
84
+ /**
85
+ * Shuffle an array in place using Fisher-Yates algorithm
86
+ * @param array - Array to shuffle
87
+ * @returns The same array, shuffled
88
+ */
89
+ shuffle(array) {
90
+ for (let i = array.length - 1; i > 0; i--) {
91
+ const j = this.intRange(0, i);
92
+ const temp = array[i];
93
+ array[i] = array[j];
94
+ array[j] = temp;
95
+ }
96
+ return array;
97
+ }
98
+ /**
99
+ * Create a fork of this RNG with independent state
100
+ * Useful for parallel simulations that need separate random streams
101
+ */
102
+ fork() {
103
+ // Generate a new seed from current state
104
+ const newSeed = this.nextInt();
105
+ return new DeterministicRandom(newSeed >>> 0);
106
+ }
107
+ /**
108
+ * Get current generator for serialization
109
+ * Note: pure-rand generators are immutable, so this returns a copy
110
+ */
111
+ getGenerator() {
112
+ return this.rng;
113
+ }
114
+ /**
115
+ * Set generator from previously saved state
116
+ * @param generator - Previously saved generator
117
+ */
118
+ setGenerator(generator) {
119
+ this.rng = generator;
120
+ }
121
+ }
122
+ //# sourceMappingURL=DeterministicRandom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeterministicRandom.js","sourceRoot":"","sources":["../src/DeterministicRandom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * EventEmitter - Generic typed event emitter
3
+ *
4
+ * Provides a type-safe event subscription system with support for:
5
+ * - Multiple handlers per event
6
+ * - One-time handlers (once)
7
+ * - Unsubscribe functions
8
+ * - Removing all listeners
9
+ */
10
+ /**
11
+ * Generic event emitter with type-safe event handling
12
+ * @typeParam TEvents - Interface mapping event names to handler signatures
13
+ */
14
+ export declare class EventEmitter<TEvents extends {
15
+ [K in keyof TEvents]: (...args: any[]) => void;
16
+ }> {
17
+ private handlers;
18
+ /**
19
+ * Subscribe to an event
20
+ * @param event Event name
21
+ * @param handler Event handler function
22
+ * @returns Unsubscribe function
23
+ */
24
+ on<K extends keyof TEvents>(event: K, handler: TEvents[K]): () => void;
25
+ /**
26
+ * Subscribe to an event once (automatically unsubscribes after first call)
27
+ * @param event Event name
28
+ * @param handler Event handler function
29
+ */
30
+ once<K extends keyof TEvents>(event: K, handler: TEvents[K]): void;
31
+ /**
32
+ * Unsubscribe from an event
33
+ * @param event Event name
34
+ * @param handler Event handler function to remove
35
+ */
36
+ off<K extends keyof TEvents>(event: K, handler: TEvents[K]): void;
37
+ /**
38
+ * Remove all event listeners
39
+ */
40
+ removeAllListeners(): void;
41
+ /**
42
+ * Remove all listeners for a specific event
43
+ * @param event Event name
44
+ */
45
+ removeListeners<K extends keyof TEvents>(event: K): void;
46
+ /**
47
+ * Emit an event to all subscribers
48
+ * @param event Event name
49
+ * @param args Event arguments
50
+ */
51
+ protected emit<K extends keyof TEvents>(event: K, ...args: Parameters<TEvents[K]>): void;
52
+ /**
53
+ * Check if there are any listeners for an event
54
+ * @param event Event name
55
+ * @returns True if there are listeners
56
+ */
57
+ hasListeners<K extends keyof TEvents>(event: K): boolean;
58
+ /**
59
+ * Get the number of listeners for an event
60
+ * @param event Event name
61
+ * @returns Number of listeners
62
+ */
63
+ listenerCount<K extends keyof TEvents>(event: K): number;
64
+ }
65
+ //# sourceMappingURL=EventEmitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventEmitter.d.ts","sourceRoot":"","sources":["../src/EventEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AAEH,qBAAa,YAAY,CAEvB,OAAO,SAAS;KAAG,CAAC,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;CAAE;IAGlE,OAAO,CAAC,QAAQ,CAA2C;IAE3D;;;;;OAKG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAYtE;;;;OAIG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IASlE;;;;OAIG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAKjE;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;;OAGG;IACH,eAAe,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAIxD;;;;OAIG;IACH,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,OAAO,EACpC,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAC9B,IAAI;IAaP;;;;OAIG;IACH,YAAY,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO;IAKxD;;;;OAIG;IACH,aAAa,CAAC,CAAC,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM;CAGzD"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * EventEmitter - Generic typed event emitter
3
+ *
4
+ * Provides a type-safe event subscription system with support for:
5
+ * - Multiple handlers per event
6
+ * - One-time handlers (once)
7
+ * - Unsubscribe functions
8
+ * - Removing all listeners
9
+ */
10
+ /**
11
+ * Generic event emitter with type-safe event handling
12
+ * @typeParam TEvents - Interface mapping event names to handler signatures
13
+ */
14
+ export class EventEmitter {
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ handlers = new Map();
17
+ /**
18
+ * Subscribe to an event
19
+ * @param event Event name
20
+ * @param handler Event handler function
21
+ * @returns Unsubscribe function
22
+ */
23
+ on(event, handler) {
24
+ if (!this.handlers.has(event)) {
25
+ this.handlers.set(event, new Set());
26
+ }
27
+ this.handlers.get(event).add(handler);
28
+ return () => {
29
+ this.off(event, handler);
30
+ };
31
+ }
32
+ /**
33
+ * Subscribe to an event once (automatically unsubscribes after first call)
34
+ * @param event Event name
35
+ * @param handler Event handler function
36
+ */
37
+ once(event, handler) {
38
+ const wrapper = ((...args) => {
39
+ this.off(event, wrapper);
40
+ handler(...args);
41
+ });
42
+ this.on(event, wrapper);
43
+ }
44
+ /**
45
+ * Unsubscribe from an event
46
+ * @param event Event name
47
+ * @param handler Event handler function to remove
48
+ */
49
+ off(event, handler) {
50
+ const eventHandlers = this.handlers.get(event);
51
+ eventHandlers?.delete(handler);
52
+ }
53
+ /**
54
+ * Remove all event listeners
55
+ */
56
+ removeAllListeners() {
57
+ this.handlers.clear();
58
+ }
59
+ /**
60
+ * Remove all listeners for a specific event
61
+ * @param event Event name
62
+ */
63
+ removeListeners(event) {
64
+ this.handlers.delete(event);
65
+ }
66
+ /**
67
+ * Emit an event to all subscribers
68
+ * @param event Event name
69
+ * @param args Event arguments
70
+ */
71
+ emit(event, ...args) {
72
+ const eventHandlers = this.handlers.get(event);
73
+ if (eventHandlers) {
74
+ for (const handler of eventHandlers) {
75
+ try {
76
+ handler(...args);
77
+ }
78
+ catch (error) {
79
+ console.error(`Error in event handler for ${String(event)}:`, error);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Check if there are any listeners for an event
86
+ * @param event Event name
87
+ * @returns True if there are listeners
88
+ */
89
+ hasListeners(event) {
90
+ const eventHandlers = this.handlers.get(event);
91
+ return eventHandlers !== undefined && eventHandlers.size > 0;
92
+ }
93
+ /**
94
+ * Get the number of listeners for an event
95
+ * @param event Event name
96
+ * @returns Number of listeners
97
+ */
98
+ listenerCount(event) {
99
+ return this.handlers.get(event)?.size ?? 0;
100
+ }
101
+ }
102
+ //# sourceMappingURL=EventEmitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventEmitter.js","sourceRoot":"","sources":["../src/EventEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AAEH,MAAM,OAAO,YAAY;IAIvB,8DAA8D;IACtD,QAAQ,GAAiC,IAAI,GAAG,EAAE,CAAC;IAE3D;;;;;OAKG;IACH,EAAE,CAA0B,KAAQ,EAAE,OAAmB;QACvD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEvC,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC3B,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,IAAI,CAA0B,KAAQ,EAAE,OAAmB;QACzD,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,IAA4B,EAAE,EAAE;YACnD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACxB,OAAqD,CAAC,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC,CAAe,CAAC;QAEjB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,GAAG,CAA0B,KAAQ,EAAE,OAAmB;QACxD,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/C,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,eAAe,CAA0B,KAAQ;QAC/C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACO,IAAI,CACZ,KAAQ,EACR,GAAG,IAA4B;QAE/B,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,aAAa,EAAE,CAAC;YAClB,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpC,IAAI,CAAC;oBACF,OAAqD,CAAC,GAAG,IAAI,CAAC,CAAC;gBAClE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,YAAY,CAA0B,KAAQ;QAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/C,OAAO,aAAa,KAAK,SAAS,IAAI,aAAa,CAAC,IAAI,GAAG,CAAC,CAAC;IAC/D,CAAC;IAED;;;;OAIG;IACH,aAAa,CAA0B,KAAQ;QAC7C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;IAC7C,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Fixed-Point Math Module
3
+ *
4
+ * Re-exports from phalanx-math for convenience.
5
+ * The canonical implementation is in phalanx-math.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { FP, FPVector3 } from '@phalanx-engine/client';
10
+ *
11
+ * const position = FPVector3.FromFloat(10.5, 0, 20.3);
12
+ * const target = FPVector3.FromFloat(5.0, 0, 10.0);
13
+ *
14
+ * const distance = FPVector3.Distance(position, target);
15
+ *
16
+ * // Convert back to number for display
17
+ * console.log(FP.ToFloat(distance));
18
+ * ```
19
+ */
20
+ export { FixedPoint, FP, FPVector2, FPVector3, } from '@phalanx-engine/math';
21
+ export type { FPVector2 as FPVector2Interface, FPVector3 as FPVector3Interface } from '@phalanx-engine/math';
22
+ //# sourceMappingURL=FixedMath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FixedMath.d.ts","sourceRoot":"","sources":["../src/FixedMath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAEL,UAAU,EAEV,EAAE,EACF,SAAS,EACT,SAAS,GACV,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,SAAS,IAAI,kBAAkB,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Fixed-Point Math Module
3
+ *
4
+ * Re-exports from phalanx-math for convenience.
5
+ * The canonical implementation is in phalanx-math.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { FP, FPVector3 } from '@phalanx-engine/client';
10
+ *
11
+ * const position = FPVector3.FromFloat(10.5, 0, 20.3);
12
+ * const target = FPVector3.FromFloat(5.0, 0, 10.0);
13
+ *
14
+ * const distance = FPVector3.Distance(position, target);
15
+ *
16
+ * // Convert back to number for display
17
+ * console.log(FP.ToFloat(distance));
18
+ * ```
19
+ */
20
+ // Re-export everything from phalanx-math
21
+ export {
22
+ // Core type
23
+ FixedPoint,
24
+ // Unified API (Unity/Quantum style)
25
+ FP, FPVector2, FPVector3, } from '@phalanx-engine/math';
26
+ //# sourceMappingURL=FixedMath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FixedMath.js","sourceRoot":"","sources":["../src/FixedMath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,yCAAyC;AACzC,OAAO;AACL,YAAY;AACZ,UAAU;AACV,oCAAoC;AACpC,EAAE,EACF,SAAS,EACT,SAAS,GACV,MAAM,sBAAsB,CAAC"}