Skip to content

Commit

Permalink
feat(sort): implement sorting of components inside a query
Browse files Browse the repository at this point in the history
  • Loading branch information
minecrawler committed May 22, 2024
1 parent 3499aba commit afa971e
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 25 deletions.
3 changes: 3 additions & 0 deletions src/query/_.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export const addEntitySym: unique symbol = Symbol();
export const clearEntitiesSym: unique symbol = Symbol();
export const removeEntitySym: unique symbol = Symbol();
export const runSortSym: unique symbol = Symbol();
export const setEntitiesSym: unique symbol = Symbol();

export const accessDescSym: unique symbol = Symbol();
export const existenceDescSym: unique symbol = Symbol();

export const entitySym: unique symbol = Symbol();
10 changes: 7 additions & 3 deletions src/query/components-query.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {
import {
IAccessDescriptor,
IAccessQuery,
IComponentsQuery,
Expand All @@ -9,7 +9,7 @@ import {EQueryType, ETargetType} from "./query.spec.ts";
import {Query} from "./query.ts";
import type {TObjectProto} from "../_.spec.ts";
import type {IEntity, TTag} from "../entity/entity.spec.ts";
import {accessDescSym, addEntitySym} from "./_.ts";
import {accessDescSym, addEntitySym, entitySym} from "./_.ts";

export class ComponentsQuery<DESC extends IAccessQuery<TObjectProto>> extends Query<DESC, TAccessQueryData<DESC>> implements IComponentsQuery<DESC> {
constructor(
Expand All @@ -20,7 +20,11 @@ export class ComponentsQuery<DESC extends IAccessQuery<TObjectProto>> extends Qu

[addEntitySym](entity: Readonly<IEntity>): void {
if (this.matchesEntity(entity)) {
this.queryResult.set(entity, this.getComponentDataFromEntity(entity, this.queryDescriptor));
this.isSortDirty = true;
this.queryResult.push({
[entitySym]: entity,
...this.getComponentDataFromEntity(entity, this.queryDescriptor),
});
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/query/entities-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {IEntitiesQuery, TExistenceQuery} from "./query.spec.ts";
import {EExistence, EQueryType, ETargetType} from "./query.spec.ts";
import {Query} from "./query.ts";
import type {IEntity, TTag} from "../entity/entity.spec.ts";
import {addEntitySym, existenceDescSym} from "./_.ts";
import {addEntitySym, entitySym, existenceDescSym} from "./_.ts";
import type {TObjectProto} from "../_.spec.ts";

export class EntitiesQuery extends Query<TExistenceQuery<TObjectProto>, IEntity> implements IEntitiesQuery {
Expand All @@ -14,7 +14,8 @@ export class EntitiesQuery extends Query<TExistenceQuery<TObjectProto>, IEntity>

[addEntitySym](entity: Readonly<IEntity>): void {
if (this.matchesEntity(entity)) {
this.queryResult.set(entity, entity);
this.isSortDirty = true;
this.queryResult.push({ [entitySym]: entity, ...entity });
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/query/query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export type TAccessQueryData<DESC extends IAccessQuery<TObjectProto>> = {
: (Required<Omit<InstanceType<DESC[P]>, keyof IAccessDescriptor<object>>> | undefined)
}

export type TComparator<DATA> = (a: DATA, b: DATA) => number;

export interface IAccessDescriptor<C extends object | undefined> {
/**
* @internal
Expand Down Expand Up @@ -82,5 +84,11 @@ export interface IQuery<DESC, DATA> {
toArray(): Array<DATA>
}

export interface IQueryDescriptor<DESC, DATA> extends IQuery<DESC, DATA> {
sort(comparator: TComparator<DATA>): IQueryDescriptor<DESC, DATA>
}

export interface IComponentsQuery<DESC extends IAccessQuery<TObjectProto>> extends IQuery<DESC, TAccessQueryData<DESC>> {}
export interface IComponentsQueryDescriptor<DESC extends IAccessQuery<TObjectProto>> extends IQueryDescriptor<DESC, TAccessQueryData<DESC>> {}
export interface IEntitiesQuery extends IQuery<TExistenceQuery<TObjectProto>, IEntity> {}
export interface IEntitiesQueryDescriptor extends IQueryDescriptor<TExistenceQuery<TObjectProto>, IEntity> {}
55 changes: 39 additions & 16 deletions src/query/query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {EQueryType, type IQuery} from "./query.spec.ts";
import type {IEntity} from "../entity/entity.ts";
import {addEntitySym, clearEntitiesSym, removeEntitySym, setEntitiesSym} from "./_.ts";
import {EQueryType, type IQuery, IQueryDescriptor, TComparator} from "./query.spec.ts";
import type {IEntity} from "../entity/entity.spec.ts";
import {addEntitySym, clearEntitiesSym, entitySym, removeEntitySym, runSortSym, setEntitiesSym} from "./_.ts";

export * from "./query.spec.ts";
export {
Expand All @@ -16,10 +16,12 @@ export {
} from "./query.util.ts";


export abstract class Query<DESC, DATA> implements IQuery<DESC, DATA> {
protected queryResult: Map<IEntity, DATA> = new Map();
export abstract class Query<DESC, DATA> implements IQuery<DESC, DATA>, IQueryDescriptor<DESC, DATA> {
protected isSortDirty = false;
protected queryResult: Array<DATA & { [entitySym]: IEntity }> = [];
protected sortComparator: TComparator<DATA> | undefined;

constructor(
protected constructor(
protected _queryType: EQueryType,
protected queryDescriptor: Readonly<DESC>,
) {}
Expand All @@ -33,42 +35,58 @@ export abstract class Query<DESC, DATA> implements IQuery<DESC, DATA> {
}

get resultLength(): number {
return this.queryResult.size;
return this.queryResult.length;
}

/** @internal */
abstract [addEntitySym](entity: Readonly<IEntity>): void;

/** @internal */
[clearEntitiesSym]() {
this.queryResult.clear();
this.queryResult.length = 0;
}

/** @internal */
[removeEntitySym](entity: Readonly<IEntity>) {
this.queryResult.delete(entity)
[removeEntitySym](entity: Readonly<IEntity>): void {
const entityIndex = this.queryResult.findIndex(data => data[entitySym] === entity);

if (entityIndex < 0) {
return;
}

this.queryResult.splice(entityIndex, 1);
}

/** @internal */
[runSortSym](): void {
if (!this.isSortDirty || !this.sortComparator) {
return;
}

this.queryResult = this.queryResult.sort(this.sortComparator);
this.isSortDirty = false;
}

/** @internal */
[setEntitiesSym](entities: Readonly<IterableIterator<Readonly<IEntity>>>) {
[setEntitiesSym](entities: Readonly<IterableIterator<Readonly<IEntity>>>): void {
let entity;

this.queryResult.clear();
this[clearEntitiesSym]();

for (entity of entities) {
this[addEntitySym](entity);
}
}

async execute(handler: (data: DATA) => Promise<void> | void): Promise<void> {
let data: DATA;
for (data of this.queryResult.values()) {
let data;
for (data of this.queryResult) {
await handler(data);
}
}

getFirst(): DATA | undefined {
return this.queryResult.values().next().value;
return this.queryResult[0];
}

iter(): IterableIterator<DATA> {
Expand All @@ -77,7 +95,12 @@ export abstract class Query<DESC, DATA> implements IQuery<DESC, DATA> {

abstract matchesEntity(entity: Readonly<IEntity>): boolean;

sort(comparator: TComparator<DATA>): IQueryDescriptor<DESC, DATA> {
this.sortComparator = comparator;
return this;
}

toArray(): DATA[] {
return Array.from(this.queryResult.values());
return [...this.queryResult];
}
}
10 changes: 7 additions & 3 deletions src/system/system.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type {IAccessQuery, IComponentsQuery, IEntitiesQuery} from "../query/query.spec.ts";
import type {
IAccessQuery,
IComponentsQueryDescriptor,
IEntitiesQueryDescriptor
} from "../query/query.spec.ts";
import type {TObjectProto, TTypeProto} from "../_.spec.ts";
import type {ISystemActions} from "../world/actions.spec.ts";
import {systemEventReaderSym, systemEventWriterSym, systemResourceTypeSym, systemRunParamSym} from "./_.ts";
Expand All @@ -7,9 +11,9 @@ import type {IEventWriter} from "../events/event-writer.spec.ts";
import type {IRuntimeWorld} from "../world/runtime/runtime-world.spec.ts";

export type TSystemParameter =
IEntitiesQuery
IEntitiesQueryDescriptor
| IEventReader<TObjectProto>
| IComponentsQuery<IAccessQuery<TObjectProto>>
| IComponentsQueryDescriptor<IAccessQuery<TObjectProto>>
| ISystemActions
| ISystemResource<TObjectProto>
| ISystemStorage;
Expand Down
9 changes: 8 additions & 1 deletion src/world/runtime/runtime-world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {Commands} from "./commands/commands.ts";
import type {ISystemActions, ITransitionActions} from "../actions.spec.ts";
import {getQueriesFromSystem} from "../../system/system.ts";
import type {ISystem} from "../../system/system.spec.ts";
import {setEntitiesSym} from "../../query/_.ts";
import {runSortSym, setEntitiesSym} from "../../query/_.ts";
import type {IRuntimeWorldData} from "./runtime-world.spec.ts";
import {Query} from "../../query/query.ts";
import {SimECSPDAPushStateEvent} from "../../events/internal-events.ts";
Expand Down Expand Up @@ -249,6 +249,13 @@ export class RuntimeWorld implements IRuntimeWorld, IMutableWorld {
throw error;
}
}

{
let query;
for (query of this.queries) {
query[runSortSym]();
}
}
}

const pushStateHandler: TSubscriber<TTypeProto<SimECSPDAPushStateEvent>> = event => {
Expand Down

0 comments on commit afa971e

Please sign in to comment.