@codehz/ecs 0.6.8 → 0.6.10

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/builder.d.mts CHANGED
@@ -64,10 +64,11 @@ declare function decodeRelationId(relationId: RelationId<any>): {
64
64
  };
65
65
  //#endregion
66
66
  //#region src/core/component-registry.d.ts
67
+ type ComponentMerge<T = any> = (prev: T, next: T) => T;
67
68
  /**
68
69
  * Component options that define intrinsic properties
69
70
  */
70
- interface ComponentOptions {
71
+ interface ComponentOptions<T = any> {
71
72
  /**
72
73
  * Optional name for the component (for serialization/debugging)
73
74
  */
@@ -93,6 +94,10 @@ interface ComponentOptions {
93
94
  * Inspired by Flecs' DontFragment trait.
94
95
  */
95
96
  dontFragment?: boolean;
97
+ /**
98
+ * Custom merge behavior for repeated set() of the same componentType in a single sync batch.
99
+ */
100
+ merge?: ComponentMerge<T>;
96
101
  }
97
102
  /**
98
103
  * Allocate a new component ID from the global allocator.
@@ -108,7 +113,7 @@ interface ComponentOptions {
108
113
  * // With name and options
109
114
  * const ChildOf = component({ name: "ChildOf", exclusive: true });
110
115
  */
111
- declare function component<T = void>(nameOrOptions?: string | ComponentOptions): ComponentId<T>;
116
+ declare function component<T = void>(nameOrOptions?: string | ComponentOptions<T>): ComponentId<T>;
112
117
  /**
113
118
  * Get a component ID by its registered name
114
119
  * @param name The component name
@@ -163,13 +168,21 @@ declare class ComponentChangeset {
163
168
  //#region src/commands/command-buffer.d.ts
164
169
  /**
165
170
  * Command for deferred execution
171
+ * Uses discriminated union for type safety
166
172
  */
167
- interface Command {
168
- type: "set" | "delete" | "destroy";
173
+ type Command = {
174
+ type: "set";
169
175
  entityId: EntityId;
170
- componentType?: EntityId<any>;
171
- component?: any;
172
- }
176
+ componentType: EntityId<any>;
177
+ component: any;
178
+ } | {
179
+ type: "delete";
180
+ entityId: EntityId;
181
+ componentType: EntityId<any>;
182
+ } | {
183
+ type: "destroy";
184
+ entityId: EntityId;
185
+ };
173
186
  //#endregion
174
187
  //#region src/core/types.d.ts
175
188
  /**
@@ -181,7 +194,7 @@ interface LegacyLifecycleHook<T = unknown> {
181
194
  */
182
195
  on_init?: (entityId: EntityId, componentType: EntityId<T>, component: T) => void;
183
196
  /**
184
- * Called when a component is added to an entity
197
+ * Called when a component is updated on an entity
185
198
  */
186
199
  on_set?: (entityId: EntityId, componentType: EntityId<T>, component: T) => void;
187
200
  /**
@@ -235,6 +248,10 @@ declare class Archetype {
235
248
  * The component types that define this archetype
236
249
  */
237
250
  readonly componentTypes: EntityId<any>[];
251
+ /**
252
+ * Set version of componentTypes for O(1) lookups in hot paths
253
+ */
254
+ readonly componentTypeSet: ReadonlySet<EntityId<any>>;
238
255
  /**
239
256
  * List of entities in this archetype
240
257
  */
@@ -254,9 +271,6 @@ declare class Archetype {
254
271
  * Stored in World to avoid migration overhead when entities change archetypes
255
272
  */
256
273
  private dontFragmentRelations;
257
- /**
258
- * Cache for pre-computed component data sources to avoid repeated calculations
259
- */
260
274
  /**
261
275
  * Multi-hooks that match this archetype
262
276
  */
@@ -267,10 +281,17 @@ declare class Archetype {
267
281
  private componentDataSourcesCache;
268
282
  constructor(componentTypes: EntityId<any>[], dontFragmentRelations: Map<EntityId, Map<EntityId<any>, any>>);
269
283
  get size(): number;
284
+ /**
285
+ * Check if the given component types match this archetype
286
+ * @param componentTypes - Component types to check (can be in any order)
287
+ * @returns true if the types match this archetype's component set
288
+ * @note This method handles unsorted input by internally sorting for comparison
289
+ */
270
290
  matches(componentTypes: EntityId<any>[]): boolean;
271
291
  addEntity(entityId: EntityId, componentData: Map<EntityId<any>, any>): void;
272
292
  private addDontFragmentRelations;
273
293
  getEntity(entityId: EntityId): Map<EntityId<any>, any> | undefined;
294
+ getEntityDontFragmentRelations(entityId: EntityId): Map<EntityId<any>, any> | undefined;
274
295
  dump(): Array<{
275
296
  entity: EntityId;
276
297
  components: Map<EntityId<any>, any>;
@@ -320,6 +341,8 @@ declare class Query {
320
341
  private filter;
321
342
  private cachedArchetypes;
322
343
  private isDisposed;
344
+ /** Cache key assigned by World for O(1) releaseQuery lookup */
345
+ _cacheKey: string | undefined;
323
346
  /** Cached wildcard component types for faster entity filtering */
324
347
  private wildcardTypes;
325
348
  /** Cached specific dontFragment relation types that need entity-level filtering */
@@ -401,9 +424,16 @@ type SerializedEntityId = number | string | {
401
424
  component: string;
402
425
  target: number | string | "*";
403
426
  };
427
+ /**
428
+ * Serialized state of EntityIdManager
429
+ */
430
+ interface SerializedEntityIdManager {
431
+ nextId: number;
432
+ freelist?: number[];
433
+ }
404
434
  type SerializedWorld = {
405
435
  version: number;
406
- entityManager: any;
436
+ entityManager: SerializedEntityIdManager;
407
437
  entities: SerializedEntity[];
408
438
  componentEntities?: SerializedEntity[];
409
439
  };
@@ -433,9 +463,14 @@ declare class World {
433
463
  private relationEntityIdsByTarget;
434
464
  private queries;
435
465
  private queryCache;
436
- private commandBuffer;
437
466
  private legacyHooks;
438
467
  private hooks;
468
+ private commandBuffer;
469
+ private readonly _changeset;
470
+ /** Cached command processor context to avoid per-entity object allocation */
471
+ private readonly _commandCtx;
472
+ /** Cached hooks context to avoid per-entity object allocation */
473
+ private readonly _hooksCtx;
439
474
  constructor(snapshot?: SerializedWorld);
440
475
  private deserializeSnapshot;
441
476
  private createArchetypeSignature;
@@ -471,6 +506,12 @@ declare class World {
471
506
  * }
472
507
  */
473
508
  exists(entityId: EntityId): boolean;
509
+ private assertEntityExists;
510
+ private assertComponentTypeValid;
511
+ private assertSetComponentTypeValid;
512
+ private resolveSetOperation;
513
+ private resolveRemoveOperation;
514
+ private getComponentEntityWildcardRelations;
474
515
  /**
475
516
  * Adds or updates a component on an entity (or marks void component as present).
476
517
  * The change is buffered and takes effect after calling `world.sync()`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codehz/ecs",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "repository": {
5
5
  "url": "https://github.com/codehz/ecs"
6
6
  },