@phalanx-engine/ecs 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 (89) hide show
  1. package/README.md +666 -0
  2. package/dist/Component.d.ts +7 -0
  3. package/dist/Component.d.ts.map +1 -0
  4. package/dist/Component.js +7 -0
  5. package/dist/Entity.d.ts +25 -0
  6. package/dist/Entity.d.ts.map +1 -0
  7. package/dist/Entity.js +58 -0
  8. package/dist/EntityManager.d.ts +36 -0
  9. package/dist/EntityManager.d.ts.map +1 -0
  10. package/dist/EntityManager.js +218 -0
  11. package/dist/EventBus.d.ts +15 -0
  12. package/dist/EventBus.d.ts.map +1 -0
  13. package/dist/EventBus.js +69 -0
  14. package/dist/GameSystem.d.ts +23 -0
  15. package/dist/GameSystem.d.ts.map +1 -0
  16. package/dist/GameSystem.js +43 -0
  17. package/dist/GameWorld.d.ts +69 -0
  18. package/dist/GameWorld.d.ts.map +1 -0
  19. package/dist/GameWorld.js +237 -0
  20. package/dist/IAbilitySystem.d.ts +18 -0
  21. package/dist/IAbilitySystem.d.ts.map +1 -0
  22. package/dist/IAbilitySystem.js +1 -0
  23. package/dist/IPhysicsWorld.d.ts +21 -0
  24. package/dist/IPhysicsWorld.d.ts.map +1 -0
  25. package/dist/IPhysicsWorld.js +1 -0
  26. package/dist/ISystemLifecycleHooks.d.ts +18 -0
  27. package/dist/ISystemLifecycleHooks.d.ts.map +1 -0
  28. package/dist/ISystemLifecycleHooks.js +12 -0
  29. package/dist/ITickFrameProvider.d.ts +24 -0
  30. package/dist/ITickFrameProvider.d.ts.map +1 -0
  31. package/dist/ITickFrameProvider.js +1 -0
  32. package/dist/SoAComponent.d.ts +22 -0
  33. package/dist/SoAComponent.d.ts.map +1 -0
  34. package/dist/SoAComponent.js +59 -0
  35. package/dist/SoAComponentStore.d.ts +41 -0
  36. package/dist/SoAComponentStore.d.ts.map +1 -0
  37. package/dist/SoAComponentStore.js +253 -0
  38. package/dist/SoASchema.d.ts +22 -0
  39. package/dist/SoASchema.d.ts.map +1 -0
  40. package/dist/SoASchema.js +33 -0
  41. package/dist/SystemContext.d.ts +18 -0
  42. package/dist/SystemContext.d.ts.map +1 -0
  43. package/dist/SystemContext.js +18 -0
  44. package/dist/SystemRegistry.d.ts +20 -0
  45. package/dist/SystemRegistry.d.ts.map +1 -0
  46. package/dist/SystemRegistry.js +73 -0
  47. package/dist/TickFrameManager.d.ts +35 -0
  48. package/dist/TickFrameManager.d.ts.map +1 -0
  49. package/dist/TickFrameManager.js +130 -0
  50. package/dist/debug/DebugDataProvider.d.ts +26 -0
  51. package/dist/debug/DebugDataProvider.d.ts.map +1 -0
  52. package/dist/debug/DebugDataProvider.js +128 -0
  53. package/dist/debug/DebugPanel.d.ts +57 -0
  54. package/dist/debug/DebugPanel.d.ts.map +1 -0
  55. package/dist/debug/DebugPanel.js +482 -0
  56. package/dist/debug/index.d.ts +4 -0
  57. package/dist/debug/index.d.ts.map +1 -0
  58. package/dist/debug/index.js +2 -0
  59. package/dist/debug/types.d.ts +47 -0
  60. package/dist/debug/types.d.ts.map +1 -0
  61. package/dist/debug/types.js +1 -0
  62. package/dist/index.d.ts +27 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +15 -0
  65. package/dist/pool/EntityPool.d.ts +21 -0
  66. package/dist/pool/EntityPool.d.ts.map +1 -0
  67. package/dist/pool/EntityPool.js +86 -0
  68. package/dist/pool/IPoolable.d.ts +4 -0
  69. package/dist/pool/IPoolable.d.ts.map +1 -0
  70. package/dist/pool/IPoolable.js +1 -0
  71. package/dist/pool/IPoolableComponent.d.ts +7 -0
  72. package/dist/pool/IPoolableComponent.d.ts.map +1 -0
  73. package/dist/pool/IPoolableComponent.js +4 -0
  74. package/dist/pool/IPoolableEntity.d.ts +6 -0
  75. package/dist/pool/IPoolableEntity.d.ts.map +1 -0
  76. package/dist/pool/IPoolableEntity.js +1 -0
  77. package/dist/pool/ObjectPool.d.ts +20 -0
  78. package/dist/pool/ObjectPool.d.ts.map +1 -0
  79. package/dist/pool/ObjectPool.js +76 -0
  80. package/dist/pool/PoolManager.d.ts +20 -0
  81. package/dist/pool/PoolManager.d.ts.map +1 -0
  82. package/dist/pool/PoolManager.js +92 -0
  83. package/dist/pool/index.d.ts +10 -0
  84. package/dist/pool/index.d.ts.map +1 -0
  85. package/dist/pool/index.js +5 -0
  86. package/dist/pool/types.d.ts +31 -0
  87. package/dist/pool/types.d.ts.map +1 -0
  88. package/dist/pool/types.js +8 -0
  89. package/package.json +46 -0
@@ -0,0 +1,47 @@
1
+ import type { PoolStats } from '../pool/types';
2
+ import type { SoAFieldType } from '../SoASchema';
3
+ export interface DebugComponentSnapshot {
4
+ typeName: string;
5
+ typeSymbol: symbol;
6
+ data: Record<string, unknown>;
7
+ }
8
+ export interface DebugEntitySnapshot {
9
+ id: number;
10
+ destroyed: boolean;
11
+ components: DebugComponentSnapshot[];
12
+ }
13
+ export interface DebugSoAStoreSnapshot {
14
+ name: string;
15
+ fieldNames: string[];
16
+ fieldTypes: Record<string, SoAFieldType>;
17
+ count: number;
18
+ capacity: number;
19
+ bytesPerEntity: number;
20
+ entities: {
21
+ entityId: number;
22
+ fields: Record<string, number | bigint>;
23
+ }[];
24
+ }
25
+ export interface DebugPoolSnapshot {
26
+ typeKey: string;
27
+ stats: PoolStats;
28
+ }
29
+ export interface DebugSnapshot {
30
+ timestamp: number;
31
+ world: {
32
+ entityCount: number;
33
+ soaStoreCount: number;
34
+ paused: boolean;
35
+ };
36
+ entities: DebugEntitySnapshot[];
37
+ soaStores: DebugSoAStoreSnapshot[];
38
+ pools: DebugPoolSnapshot[];
39
+ }
40
+ export interface DebugDataProviderConfig {
41
+ updateInterval?: number;
42
+ }
43
+ export interface DebugPanelConfig {
44
+ toggleKey?: string;
45
+ startCollapsed?: boolean;
46
+ }
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/debug/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,MAAM,WAAW,sBAAsB;IAErC,QAAQ,EAAE,MAAM,CAAC;IAEjB,UAAU,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAKD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACtC;AAKD,MAAM,WAAW,qBAAqB;IAEpC,IAAI,EAAE,MAAM,CAAC;IAEb,UAAU,EAAE,MAAM,EAAE,CAAC;IAErB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEzC,KAAK,EAAE,MAAM,CAAC;IAEd,QAAQ,EAAE,MAAM,CAAC;IAEjB,cAAc,EAAE,MAAM,CAAC;IAEvB,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;KACzC,EAAE,CAAC;CACL;AAKD,MAAM,WAAW,iBAAiB;IAEhC,OAAO,EAAE,MAAM,CAAC;IAEhB,KAAK,EAAE,SAAS,CAAC;CAClB;AASD,MAAM,WAAW,aAAa;IAE5B,SAAS,EAAE,MAAM,CAAC;IAGlB,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE,OAAO,CAAC;KACjB,CAAC;IAGF,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAGhC,SAAS,EAAE,qBAAqB,EAAE,CAAC;IAGnC,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC5B;AAKD,MAAM,WAAW,uBAAuB;IAMtC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAKD,MAAM,WAAW,gBAAgB;IAE/B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ export { EntityManager } from './EntityManager';
2
+ export { EventBus, globalEventBus } from './EventBus';
3
+ export { SystemRegistry } from './SystemRegistry';
4
+ export { SystemContext } from './SystemContext';
5
+ export { GameSystem } from './GameSystem';
6
+ export { GameWorld, GameWorldEvents } from './GameWorld';
7
+ export type { GameWorldConfig, GameWorldHooks } from './GameWorld';
8
+ export { Entity, resetEntityIdCounter, nextEntityId } from './Entity';
9
+ export { IComponent, createComponentTypeRegistry } from './Component';
10
+ export type { IComponent as Component } from './Component';
11
+ export { ObjectPool, EntityPool, PoolManager, isPoolableComponent, } from './pool';
12
+ export type { IPoolable, IPoolableEntity, SpawnArgsOf, IPoolableComponent, PoolConfig, PoolStats, EntityTypeConfig, PoolingConfig, } from './pool';
13
+ export { SoAComponentStore } from './SoAComponentStore';
14
+ export type { SoAComponentStoreOptions } from './SoAComponentStore';
15
+ export { SoAComponent } from './SoAComponent';
16
+ export { defineSoASchema, calculateSchemaByteSize, TYPED_ARRAY_CONSTRUCTORS, FIELD_BYTE_SIZES, } from './SoASchema';
17
+ export type { SoASchema, SoASchemaDefinition, SoAFieldType, SoAFieldsOf, SoAArraysOf, SoAValueType, SoAArrayType, TypedArrayLike, } from './SoASchema';
18
+ export { DebugDataProvider, DebugPanel } from './debug';
19
+ export type { DebugSnapshot, DebugEntitySnapshot, DebugComponentSnapshot, DebugSoAStoreSnapshot, DebugPoolSnapshot, DebugDataProviderConfig, DebugPanelConfig, } from './debug';
20
+ export type { IBeforeTick, IAfterTick, IBeforeFrame, IAfterFrame } from './ISystemLifecycleHooks';
21
+ export { isBeforeTick, isAfterTick, isBeforeFrame, isAfterFrame } from './ISystemLifecycleHooks';
22
+ export type { IAbilitySystem } from './IAbilitySystem';
23
+ export type { IPhysicsWorld, InterpolatedTransformSample } from './IPhysicsWorld';
24
+ export { TickFrameManager } from './TickFrameManager';
25
+ export type { TickFrameManagerConfig } from './TickFrameManager';
26
+ export type { ITickFrameProvider, TickHandler, FrameHandler, Unsubscribe, CommandsBatch, PlayerCommand, PauseHandler, } from './ITickFrameProvider';
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGnE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AACtE,YAAY,EAAE,UAAU,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AAG3D,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,EACX,mBAAmB,GACpB,MAAM,QAAQ,CAAC;AAChB,YAAY,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,GACd,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxD,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGjG,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,YAAY,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAGlF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export { EntityManager } from './EntityManager';
2
+ export { EventBus, globalEventBus } from './EventBus';
3
+ export { SystemRegistry } from './SystemRegistry';
4
+ export { SystemContext } from './SystemContext';
5
+ export { GameSystem } from './GameSystem';
6
+ export { GameWorld, GameWorldEvents } from './GameWorld';
7
+ export { Entity, resetEntityIdCounter, nextEntityId } from './Entity';
8
+ export { createComponentTypeRegistry } from './Component';
9
+ export { ObjectPool, EntityPool, PoolManager, isPoolableComponent, } from './pool';
10
+ export { SoAComponentStore } from './SoAComponentStore';
11
+ export { SoAComponent } from './SoAComponent';
12
+ export { defineSoASchema, calculateSchemaByteSize, TYPED_ARRAY_CONSTRUCTORS, FIELD_BYTE_SIZES, } from './SoASchema';
13
+ export { DebugDataProvider, DebugPanel } from './debug';
14
+ export { isBeforeTick, isAfterTick, isBeforeFrame, isAfterFrame } from './ISystemLifecycleHooks';
15
+ export { TickFrameManager } from './TickFrameManager';
@@ -0,0 +1,21 @@
1
+ import type { Entity } from '../Entity';
2
+ import type { PoolConfig, PoolStats } from './types';
3
+ export declare class EntityPool<T extends Entity = Entity> {
4
+ private readonly available;
5
+ private readonly entityFactory;
6
+ private readonly config;
7
+ private _totalCreated;
8
+ private _acquireCount;
9
+ private _releaseCount;
10
+ private _missCount;
11
+ constructor(entityFactory: () => T, config?: PoolConfig);
12
+ acquire(): T;
13
+ release(entity: T): void;
14
+ prewarm(count: number): void;
15
+ drain(): void;
16
+ get availableCount(): number;
17
+ get stats(): PoolStats;
18
+ private createEntity;
19
+ private growBatch;
20
+ }
21
+ //# sourceMappingURL=EntityPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityPool.d.ts","sourceRoot":"","sources":["../../src/pool/EntityPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAsB,MAAM,SAAS,CAAC;AAWzE,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAE5C,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAa;gBAEnB,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU;IASvD,OAAO,IAAI,CAAC;IAgCZ,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI;IAYxB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAW5B,KAAK,IAAI,IAAI;IAIb,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,KAAK,IAAI,SAAS,CAQrB;IAED,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,SAAS;CASlB"}
@@ -0,0 +1,86 @@
1
+ import { resolvePoolConfig } from './types';
2
+ export class EntityPool {
3
+ available = [];
4
+ entityFactory;
5
+ config;
6
+ _totalCreated = 0;
7
+ _acquireCount = 0;
8
+ _releaseCount = 0;
9
+ _missCount = 0;
10
+ constructor(entityFactory, config) {
11
+ this.entityFactory = entityFactory;
12
+ this.config = resolvePoolConfig(config);
13
+ }
14
+ acquire() {
15
+ this._acquireCount++;
16
+ let entity;
17
+ let fromPool = false;
18
+ if (this.available.length > 0) {
19
+ entity = this.available.pop();
20
+ fromPool = true;
21
+ }
22
+ else {
23
+ this._missCount++;
24
+ if (this.config.growthStrategy === 'grow') {
25
+ this.growBatch();
26
+ }
27
+ if (this.available.length > 0) {
28
+ entity = this.available.pop();
29
+ fromPool = true;
30
+ }
31
+ else {
32
+ entity = this.createEntity();
33
+ }
34
+ }
35
+ if (fromPool) {
36
+ entity._revive();
37
+ }
38
+ return entity;
39
+ }
40
+ release(entity) {
41
+ this._releaseCount++;
42
+ if (this.config.maxSize > 0 && this.available.length >= this.config.maxSize) {
43
+ entity.dispose();
44
+ return;
45
+ }
46
+ this.available.push(entity);
47
+ }
48
+ prewarm(count) {
49
+ const toCreate = count - this.available.length;
50
+ for (let i = 0; i < toCreate; i++) {
51
+ if (this.config.maxSize > 0 && this.available.length >= this.config.maxSize) {
52
+ break;
53
+ }
54
+ this.available.push(this.createEntity());
55
+ }
56
+ }
57
+ drain() {
58
+ this.available.length = 0;
59
+ }
60
+ get availableCount() {
61
+ return this.available.length;
62
+ }
63
+ get stats() {
64
+ return {
65
+ available: this.available.length,
66
+ totalCreated: this._totalCreated,
67
+ acquireCount: this._acquireCount,
68
+ releaseCount: this._releaseCount,
69
+ missCount: this._missCount,
70
+ };
71
+ }
72
+ createEntity() {
73
+ const entity = this.entityFactory();
74
+ this._totalCreated++;
75
+ return entity;
76
+ }
77
+ growBatch() {
78
+ const batchSize = this.config.growthBatchSize;
79
+ for (let i = 0; i < batchSize; i++) {
80
+ if (this.config.maxSize > 0 && this.available.length >= this.config.maxSize) {
81
+ break;
82
+ }
83
+ this.available.push(this.createEntity());
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,4 @@
1
+ export interface IPoolable {
2
+ reset(): void;
3
+ }
4
+ //# sourceMappingURL=IPoolable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IPoolable.d.ts","sourceRoot":"","sources":["../../src/pool/IPoolable.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IAMxB,KAAK,IAAI,IAAI,CAAC;CACf"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { IComponent } from '../Component';
2
+ export interface IPoolableComponent extends IComponent {
3
+ onSpawn(): void;
4
+ onDespawn(): void;
5
+ }
6
+ export declare function isPoolableComponent(c: IComponent): c is IPoolableComponent;
7
+ //# sourceMappingURL=IPoolableComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IPoolableComponent.d.ts","sourceRoot":"","sources":["../../src/pool/IPoolableComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAU/C,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IAEpD,OAAO,IAAI,IAAI,CAAC;IAEhB,SAAS,IAAI,IAAI,CAAC;CACnB;AAGD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,IAAI,kBAAkB,CAG1E"}
@@ -0,0 +1,4 @@
1
+ export function isPoolableComponent(c) {
2
+ return typeof c.onSpawn === 'function'
3
+ && typeof c.onDespawn === 'function';
4
+ }
@@ -0,0 +1,6 @@
1
+ export interface IPoolableEntity<TSpawnArgs = void> {
2
+ onSpawn(args: TSpawnArgs): void;
3
+ onDespawn(): void;
4
+ }
5
+ export type SpawnArgsOf<T> = T extends IPoolableEntity<infer A> ? (A extends void ? [] : [args: A]) : never;
6
+ //# sourceMappingURL=IPoolableEntity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IPoolableEntity.d.ts","sourceRoot":"","sources":["../../src/pool/IPoolableEntity.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe,CAAC,UAAU,GAAG,IAAI;IAOhD,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAOhC,SAAS,IAAI,IAAI,CAAC;CACnB;AAGD,MAAM,MAAM,WAAW,CAAC,CAAC,IACvB,CAAC,SAAS,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { IPoolable } from './IPoolable';
2
+ import type { PoolConfig, PoolStats } from './types';
3
+ export declare class ObjectPool<T extends IPoolable> {
4
+ private readonly available;
5
+ private readonly factory;
6
+ private readonly config;
7
+ private _totalCreated;
8
+ private _acquireCount;
9
+ private _releaseCount;
10
+ private _missCount;
11
+ constructor(factory: () => T, config?: PoolConfig);
12
+ acquire(): T;
13
+ release(obj: T): void;
14
+ prewarm(count: number): void;
15
+ drain(): void;
16
+ get availableCount(): number;
17
+ get totalCreated(): number;
18
+ get stats(): PoolStats;
19
+ }
20
+ //# sourceMappingURL=ObjectPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObjectPool.d.ts","sourceRoot":"","sources":["../../src/pool/ObjectPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAsB,MAAM,SAAS,CAAC;AAOzE,qBAAa,UAAU,CAAC,CAAC,SAAS,SAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAE5C,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAa;gBAEnB,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU;IAMjD,OAAO,IAAI,CAAC;IAiCZ,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI;IAWrB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAY5B,KAAK,IAAI,IAAI;IAIb,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,KAAK,IAAI,SAAS,CAQrB;CACF"}
@@ -0,0 +1,76 @@
1
+ import { resolvePoolConfig } from './types';
2
+ export class ObjectPool {
3
+ available = [];
4
+ factory;
5
+ config;
6
+ _totalCreated = 0;
7
+ _acquireCount = 0;
8
+ _releaseCount = 0;
9
+ _missCount = 0;
10
+ constructor(factory, config) {
11
+ this.factory = factory;
12
+ this.config = resolvePoolConfig(config);
13
+ }
14
+ acquire() {
15
+ this._acquireCount++;
16
+ if (this.available.length === 0) {
17
+ this._missCount++;
18
+ if (this.config.growthStrategy === 'grow') {
19
+ const batch = this.config.growthBatchSize;
20
+ for (let i = 0; i < batch; i++) {
21
+ if (this.config.maxSize > 0 && this.available.length >= this.config.maxSize)
22
+ break;
23
+ const obj = this.factory();
24
+ obj.reset();
25
+ this._totalCreated++;
26
+ this.available.push(obj);
27
+ }
28
+ }
29
+ if (this.available.length === 0) {
30
+ this._totalCreated++;
31
+ const obj = this.factory();
32
+ obj.reset();
33
+ return obj;
34
+ }
35
+ }
36
+ const obj = this.available.pop();
37
+ obj.reset();
38
+ return obj;
39
+ }
40
+ release(obj) {
41
+ this._releaseCount++;
42
+ obj.reset();
43
+ if (this.config.maxSize === 0 || this.available.length < this.config.maxSize) {
44
+ this.available.push(obj);
45
+ }
46
+ }
47
+ prewarm(count) {
48
+ const toCreate = count - this.available.length;
49
+ for (let i = 0; i < toCreate; i++) {
50
+ if (this.config.maxSize > 0 && this.available.length >= this.config.maxSize)
51
+ break;
52
+ const obj = this.factory();
53
+ obj.reset();
54
+ this._totalCreated++;
55
+ this.available.push(obj);
56
+ }
57
+ }
58
+ drain() {
59
+ this.available.length = 0;
60
+ }
61
+ get availableCount() {
62
+ return this.available.length;
63
+ }
64
+ get totalCreated() {
65
+ return this._totalCreated;
66
+ }
67
+ get stats() {
68
+ return {
69
+ available: this.available.length,
70
+ totalCreated: this._totalCreated,
71
+ acquireCount: this._acquireCount,
72
+ releaseCount: this._releaseCount,
73
+ missCount: this._missCount,
74
+ };
75
+ }
76
+ }
@@ -0,0 +1,20 @@
1
+ import type { Entity } from '../Entity';
2
+ import type { EntityManager } from '../EntityManager';
3
+ import type { IPoolableEntity, SpawnArgsOf } from './IPoolableEntity';
4
+ import type { EntityTypeConfig, PoolStats } from './types';
5
+ export declare class PoolManager {
6
+ private readonly entityManager;
7
+ private readonly pools;
8
+ private readonly initialSizes;
9
+ constructor(entityManager: EntityManager);
10
+ registerEntityType<T extends Entity & IPoolableEntity<any>>(typeKey: string, config: EntityTypeConfig<T>): void;
11
+ spawn<T extends Entity & IPoolableEntity<any>>(typeKey: string, ...args: SpawnArgsOf<T>): T;
12
+ despawn(entity: Entity): void;
13
+ prewarmAll(): void;
14
+ prewarm(typeKey: string, count: number): void;
15
+ drainAll(): void;
16
+ getStats(): Map<string, PoolStats>;
17
+ getPoolStats(typeKey: string): PoolStats | undefined;
18
+ private runDespawnHooks;
19
+ }
20
+ //# sourceMappingURL=PoolManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PoolManager.d.ts","sourceRoot":"","sources":["../../src/pool/PoolManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAS3D,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,aAAa;IAH1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8C;IACpE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;gBAElC,aAAa,EAAE,aAAa;IAOzD,kBAAkB,CAAC,CAAC,SAAS,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,EACxD,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC1B,IAAI;IAkBP,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,EAC3C,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,GACtB,CAAC;IAqBJ,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAiB7B,UAAU,IAAI,IAAI;IAYlB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAS7C,QAAQ,IAAI,IAAI;IAOhB,QAAQ,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;IASlC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAKpD,OAAO,CAAC,eAAe;CAMxB"}
@@ -0,0 +1,92 @@
1
+ import { isPoolableComponent } from './IPoolableComponent';
2
+ import { EntityPool } from './EntityPool';
3
+ export class PoolManager {
4
+ entityManager;
5
+ pools = new Map();
6
+ initialSizes = new Map();
7
+ constructor(entityManager) {
8
+ this.entityManager = entityManager;
9
+ }
10
+ registerEntityType(typeKey, config) {
11
+ if (this.pools.has(typeKey)) {
12
+ throw new Error(`Pool '${typeKey}' is already registered`);
13
+ }
14
+ const factory = () => {
15
+ const entity = config.factory();
16
+ entity._poolTypeKey = typeKey;
17
+ entity._inPool = true;
18
+ this.runDespawnHooks(entity);
19
+ return entity;
20
+ };
21
+ this.pools.set(typeKey, new EntityPool(factory, config.pool));
22
+ this.initialSizes.set(typeKey, config.pool?.initialSize ?? 0);
23
+ }
24
+ spawn(typeKey, ...args) {
25
+ const pool = this.pools.get(typeKey);
26
+ if (!pool) {
27
+ throw new Error(`Pool '${typeKey}' is not registered`);
28
+ }
29
+ const entity = pool.acquire();
30
+ entity._inPool = false;
31
+ for (const component of entity.getComponents().values()) {
32
+ if (isPoolableComponent(component))
33
+ component.onSpawn();
34
+ }
35
+ entity.onSpawn(args[0]);
36
+ this.entityManager.addEntity(entity);
37
+ return entity;
38
+ }
39
+ despawn(entity) {
40
+ const typeKey = entity._poolTypeKey;
41
+ if (!typeKey) {
42
+ throw new Error('despawn() called on an entity that was not created by PoolManager');
43
+ }
44
+ if (entity._inPool) {
45
+ return;
46
+ }
47
+ const pool = this.pools.get(typeKey);
48
+ this.entityManager.removeEntity(entity);
49
+ this.runDespawnHooks(entity);
50
+ entity._inPool = true;
51
+ pool.release(entity);
52
+ }
53
+ prewarmAll() {
54
+ for (const [typeKey, initialSize] of this.initialSizes) {
55
+ if (initialSize > 0) {
56
+ const pool = this.pools.get(typeKey);
57
+ if (pool) {
58
+ pool.prewarm(initialSize);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ prewarm(typeKey, count) {
64
+ const pool = this.pools.get(typeKey);
65
+ if (!pool) {
66
+ throw new Error(`Pool '${typeKey}' is not registered`);
67
+ }
68
+ pool.prewarm(count);
69
+ }
70
+ drainAll() {
71
+ for (const pool of this.pools.values()) {
72
+ pool.drain();
73
+ }
74
+ }
75
+ getStats() {
76
+ const result = new Map();
77
+ for (const [key, pool] of this.pools) {
78
+ result.set(key, pool.stats);
79
+ }
80
+ return result;
81
+ }
82
+ getPoolStats(typeKey) {
83
+ return this.pools.get(typeKey)?.stats;
84
+ }
85
+ runDespawnHooks(entity) {
86
+ entity.onDespawn();
87
+ for (const component of entity.getComponents().values()) {
88
+ if (isPoolableComponent(component))
89
+ component.onDespawn();
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,10 @@
1
+ export type { IPoolable } from './IPoolable';
2
+ export type { IPoolableEntity, SpawnArgsOf } from './IPoolableEntity';
3
+ export type { IPoolableComponent } from './IPoolableComponent';
4
+ export { isPoolableComponent } from './IPoolableComponent';
5
+ export type { PoolConfig, PoolStats, EntityTypeConfig, PoolingConfig, ResolvedPoolConfig, } from './types';
6
+ export { resolvePoolConfig } from './types';
7
+ export { ObjectPool } from './ObjectPool';
8
+ export { EntityPool } from './EntityPool';
9
+ export { PoolManager } from './PoolManager';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pool/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtE,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EACV,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,kBAAkB,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { isPoolableComponent } from './IPoolableComponent';
2
+ export { resolvePoolConfig } from './types';
3
+ export { ObjectPool } from './ObjectPool';
4
+ export { EntityPool } from './EntityPool';
5
+ export { PoolManager } from './PoolManager';
@@ -0,0 +1,31 @@
1
+ import type { Entity } from '../Entity';
2
+ import type { IPoolableEntity } from './IPoolableEntity';
3
+ export interface PoolConfig {
4
+ initialSize?: number;
5
+ maxSize?: number;
6
+ growthStrategy?: 'create' | 'grow';
7
+ growthBatchSize?: number;
8
+ }
9
+ export interface PoolStats {
10
+ available: number;
11
+ totalCreated: number;
12
+ acquireCount: number;
13
+ releaseCount: number;
14
+ missCount: number;
15
+ }
16
+ export interface EntityTypeConfig<T extends Entity & IPoolableEntity<any> = Entity & IPoolableEntity<any>> {
17
+ factory: () => T;
18
+ pool?: PoolConfig;
19
+ }
20
+ export interface PoolingConfig {
21
+ entityTypes: Record<string, EntityTypeConfig>;
22
+ autoPrewarm?: boolean;
23
+ }
24
+ export interface ResolvedPoolConfig {
25
+ initialSize: number;
26
+ maxSize: number;
27
+ growthStrategy: 'create' | 'grow';
28
+ growthBatchSize: number;
29
+ }
30
+ export declare function resolvePoolConfig(config?: PoolConfig): ResolvedPoolConfig;
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pool/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,UAAU;IAEzB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAEnC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC;IACvG,OAAO,EAAE,MAAM,CAAC,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAE9C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,QAAQ,GAAG,MAAM,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,kBAAkB,CAOzE"}
@@ -0,0 +1,8 @@
1
+ export function resolvePoolConfig(config) {
2
+ return {
3
+ initialSize: config?.initialSize ?? 0,
4
+ maxSize: config?.maxSize ?? 0,
5
+ growthStrategy: config?.growthStrategy ?? 'create',
6
+ growthBatchSize: config?.growthBatchSize ?? 8,
7
+ };
8
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@phalanx-engine/ecs",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight, renderer-agnostic Entity-Component-System library with optional multiplayer support via Phalanx Engine",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "keywords": [
15
+ "ecs",
16
+ "entity-component-system",
17
+ "game-engine",
18
+ "phalanx"
19
+ ],
20
+ "author": "",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/phaeton-forge/phalanx-engine.git",
25
+ "directory": "phalanx-ecs"
26
+ },
27
+ "bugs": "https://github.com/phaeton-forge/phalanx-engine/issues",
28
+ "homepage": "https://github.com/phaeton-forge/phalanx-engine/tree/main/phalanx-ecs#readme",
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "devDependencies": {
37
+ "happy-dom": "^20.8.4",
38
+ "typescript": "~5.9.3"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "clean": "rm -rf dist",
43
+ "rebuild": "npm run clean && npm run build",
44
+ "test": "vitest run"
45
+ }
46
+ }