import { ComponentHandle } from './Component2.js'; import { Entity } from './Entity.js'; import { OneOf, Changed, Filter, not, Not } from './filters.js'; import { Game } from './Game.js'; import { Query, QueryComponentFilter } from './Query.js'; type FilterNots | ComponentHandle> = CompUnion extends Not ? never : CompUnion; type UnwrapAnys | ComponentHandle> = CompUnion extends OneOf ? never : CompUnion; type UnwrapFilters< CompUnion extends Filter | ComponentHandle, > = CompUnion extends Filter ? C : CompUnion; type DefiniteComponentsFromFilter = UnwrapFilters>>; export type EntityImpostorFor = Entity< DefiniteComponentsFromFilter >; export class QueryIterator implements Iterator> { private archetypeIndex = 0; private archetypeIterator: Iterator> | null = null; private result: IteratorResult> = { done: true, value: null as any, }; private changedFilters: Changed[]; constructor( private query: Query, private game: Game, ) { this.changedFilters = query.filter.filter( (f) => f.kind === 'changed', ) as Changed[]; } private checkChangeFilter() { if (this.changedFilters.length === 0) return true; return this.changedFilters.some((filter) => { this.game.componentManager.wasChangedLastFrame( this.result.value.get(filter.Component).id, ); }); } next() { while (this.archetypeIndex < this.query.archetypes.length) { if (!this.archetypeIterator) { this.archetypeIterator = this.query.archetypes[this.archetypeIndex][Symbol.iterator](); } this.result = this.archetypeIterator.next(); // if changed() filter(s) are present, ensure a change has // occurred in the specified components if (!this.result.done && !this.checkChangeFilter()) { continue; } // result is assigned from the current archetype iterator result - // if the archetype is done, we move on to the next archetype until // we run out if (this.result.done) { this.archetypeIndex++; this.archetypeIterator = null; continue; } return this.result; } this.result.done = true; this.archetypeIndex = 0; return this.result; } first() { this.archetypeIndex = 0; this.archetypeIterator = null; const first = this.next(); // reset stateful bits this.archetypeIndex = 0; this.archetypeIterator = null; if (first.done) { return null; } return first.value; } }