refactor query into yielding api
This commit is contained in:
parent
6bf8f60a45
commit
976a99baa1
5 changed files with 70 additions and 54 deletions
|
@ -257,7 +257,7 @@ export function wait(ms: number) {
|
|||
}
|
||||
|
||||
export async function run(cmd: string, ...args: string[]) {
|
||||
const command = new Deno.Command(cmd, { args, stdout: "piped" });
|
||||
const command = new Deno.Command(cmd, { args, stdin: "inherit", stdout: "piped" });
|
||||
const output = await command.output();
|
||||
if (!output.success) throw new Error();
|
||||
return new TextDecoder().decode(output.stdout);
|
||||
|
|
|
@ -1,6 +1,25 @@
|
|||
import { v2 } from "../../common/utils.ts";
|
||||
import { range, Vec2 } from "../../common/utils.ts";
|
||||
import { Engine } from "../engine.ts";
|
||||
import { query_in_rect } from "./world.ts";
|
||||
|
||||
export class CompDisplay {
|
||||
display;
|
||||
constructor(display: string) {
|
||||
this.display = display;
|
||||
}
|
||||
}
|
||||
|
||||
export function sys_render_world(center: Vec2, size: Vec2) {
|
||||
return (engine: Engine) => {
|
||||
const radius = size.scale(0.5);
|
||||
const result = Array.from(range(0, size.y())).map(() => Array.from(range(0, size.x())).map(() => " "));
|
||||
const min = center.sub(radius);
|
||||
const max = center.add(radius).sub(v2(1, 1));
|
||||
for (const [pos, display] of engine.query_all(query_in_rect(min, max).with(CompDisplay))) {
|
||||
const local_pos = pos.position.sub(min);
|
||||
result[local_pos.y()][local_pos.x()] = display.display;
|
||||
}
|
||||
return result.map((line) => line.join("")).toReversed().join("\n");
|
||||
};
|
||||
}
|
||||
|
|
|
@ -61,11 +61,11 @@ Deno.test("test_displacement", () => {
|
|||
});
|
||||
|
||||
export function query_at(pos: Vec2) {
|
||||
return Query.filter(CompPos, (c) => c.position.overlaps(pos));
|
||||
return Query.with(CompPos).filter(([c]) => c.position.overlaps(pos));
|
||||
}
|
||||
|
||||
export function query_in_rect(min: Vec2, max: Vec2) {
|
||||
return Query.filter(CompPos, (c) => c.position.inside(min, max));
|
||||
return Query.with(CompPos).filter(([c]) => c.position.inside(min, max));
|
||||
}
|
||||
|
||||
class CompStructure {}
|
||||
|
|
|
@ -60,11 +60,11 @@ export class Engine {
|
|||
}
|
||||
}
|
||||
|
||||
*query_all(query: Query) {
|
||||
*query_all<O extends QueryRes>(query: Query<O>) {
|
||||
yield* query.run(this.entities.values());
|
||||
}
|
||||
|
||||
query_one(query: Query) {
|
||||
query_one<O extends QueryRes>(query: Query<O>) {
|
||||
return first(this.query_all(query));
|
||||
}
|
||||
|
||||
|
@ -85,41 +85,52 @@ export class Engine {
|
|||
}
|
||||
}
|
||||
|
||||
export class Query {
|
||||
private test;
|
||||
type QueryRes<T = unknown> = readonly T[];
|
||||
export class Query<O extends QueryRes> {
|
||||
extractor;
|
||||
|
||||
constructor(test: (entity: Entity) => boolean) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
and(query: Query) {
|
||||
return new Query((entity) => this.test(entity) && query.test(entity));
|
||||
}
|
||||
|
||||
static with(...components: Constructible[]) {
|
||||
return new Query((entity) => {
|
||||
for (const comp of components) if (!entity.components.has(comp)) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
with(...components: Constructible[]) {
|
||||
return this.and(Query.with(...components));
|
||||
}
|
||||
|
||||
static filter<I>(component: Constructible<I>, filter: (comp: I, entity: Entity) => boolean) {
|
||||
return new Query((entity) => {
|
||||
const comp = entity.get(component);
|
||||
if (comp === null) return false;
|
||||
return filter(comp, entity);
|
||||
});
|
||||
}
|
||||
|
||||
filter<I>(component: Constructible<I>, filter: (comp: I, entity: Entity) => boolean) {
|
||||
return this.and(Query.filter(component, filter));
|
||||
constructor(extractor: (entity: Entity) => O | null) {
|
||||
this.extractor = extractor;
|
||||
}
|
||||
|
||||
*run(entities: Iterable<Entity>) {
|
||||
for (const entity of entities) if (this.test(entity)) yield entity;
|
||||
for (const entity of entities) {
|
||||
const extracted = this.extractor(entity);
|
||||
if (extracted !== null) yield extracted;
|
||||
}
|
||||
}
|
||||
|
||||
and<Q extends QueryRes>(other: Query<Q>) {
|
||||
const this_extractor = this.extractor;
|
||||
return new Query((entity) => {
|
||||
const this_extracted = this_extractor(entity);
|
||||
if (this_extracted === null) return null;
|
||||
const other_extracted = other.extractor(entity);
|
||||
if (other_extracted === null) return null;
|
||||
return [...this_extracted, ...other_extracted] as const;
|
||||
});
|
||||
}
|
||||
|
||||
static with<I>(comp: Constructible<I>) {
|
||||
function extract(entity: Entity) {
|
||||
const extracted = entity.get(comp);
|
||||
if (extracted === null) return null;
|
||||
return [extracted] as const;
|
||||
}
|
||||
return new Query(extract);
|
||||
}
|
||||
|
||||
with<I>(comp: Constructible<I>) {
|
||||
return this.and(Query.with(comp));
|
||||
}
|
||||
|
||||
filter(predicate: (comps: O) => boolean) {
|
||||
const this_extract = this.extractor;
|
||||
return new Query((entity) => {
|
||||
const extracted = this_extract(entity);
|
||||
if (extracted === null) return null;
|
||||
if (predicate(extracted)) return extracted;
|
||||
else return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { mts } from "../../common/mod.ts";
|
||||
import { log_from, range, v2, Vec2 } from "../../common/utils.ts";
|
||||
import { CompDisplay } from "../components/display.ts";
|
||||
import { CompPos, query_in_rect, sys_find_free_pos } from "../components/world.ts";
|
||||
import { log_from, v2, Vec2 } from "../../common/utils.ts";
|
||||
import { CompDisplay, sys_render_world } from "../components/display.ts";
|
||||
import { CompPos, sys_find_free_pos } from "../components/world.ts";
|
||||
import { Engine, Entity } from "../engine.ts";
|
||||
import { ClientInterface } from "../network.ts";
|
||||
const log = log_from(import.meta);
|
||||
|
@ -58,20 +58,6 @@ export class Session {
|
|||
}
|
||||
}
|
||||
|
||||
export function sys_render_world(center: Vec2, size: Vec2) {
|
||||
return (engine: Engine) => {
|
||||
const radius = size.scale(0.5);
|
||||
const result = Array.from(range(0, size.y())).map(() => Array.from(range(0, size.x())).map(() => " "));
|
||||
const min = center.sub(radius);
|
||||
const max = center.add(radius);
|
||||
for (const entity of engine.query_all(query_in_rect(min, max).with(CompDisplay))) {
|
||||
const local_pos = entity.get_force(CompPos).position.sub(min);
|
||||
result[local_pos.y()][local_pos.x()] = entity.get_force(CompDisplay).display;
|
||||
}
|
||||
return result.map((line) => line.join("")).toReversed().join("\n");
|
||||
};
|
||||
}
|
||||
|
||||
export function sys_spawn_player(position: Vec2) {
|
||||
return (engine: Engine) => {
|
||||
return engine.spawn((entity) =>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue