Skip to content

Commit

Permalink
some performance improvements and query events
Browse files Browse the repository at this point in the history
  • Loading branch information
doman412 committed Jul 23, 2022
1 parent ef05587 commit d2af374
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 76 deletions.
2 changes: 2 additions & 0 deletions src/Component.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Entity } from './Entity'
import { Klass } from './Klass'
import { WritablePart } from './Utils'

Expand All @@ -15,6 +16,7 @@ export type ComponentInstance<C extends Component> = Required<Omit<C, HiddenProp
export type ComponentData<C extends Component> = Omit<WritablePart<C>, HiddenProperties>

export type GetComponent<C> = C extends ComponentConstructor<infer T> ? T : C
export type EntityComponents<E> = E extends Entity<infer C> ? C : never

export class Component {
static id: ComponentStaticProps['id'] = 0
Expand Down
5 changes: 3 additions & 2 deletions src/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export class Engine {

createEntity(name?: string): Entity {
const entity = this.entity_manager.createEntity(name)
this.query_manager.update()
// this.query_manager.update()
this.query_manager.onEntityAdded(entity)
if(import.meta.hot){
import.meta.hot.send('ein:create-entity', {
id: entity.id,
Expand Down Expand Up @@ -93,7 +94,7 @@ export class Engine {
this.time = time
if(this.enabled){
// console.log('engine : update')
this.query_manager.update(true)
this.query_manager.update()
this.system_manager.update(delta, time)
// this.system_manager.execute(delta, time, ()=>{
// // after each system execute, update the queries that are pending updates
Expand Down
3 changes: 2 additions & 1 deletion src/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class Entity<All extends Component=any> {
add<C extends Component>(cls: ComponentConstructor<C>, data?: ComponentData<C>): this {
// this.engine.component_manager.addComponent(this, cls, ...data)
const instance = this.engine.component_manager.getFreeComponent(cls, data)
this.engine.query_manager.onComponentAdded(this, cls)

this.mask = bitSet(this.mask, cls.mask)
// this.$components.set(cls, instance)
Expand Down Expand Up @@ -64,7 +65,7 @@ export class Entity<All extends Component=any> {
return this
}

get<C extends Component>(cls: ComponentConstructor<C>): C extends All ? ComponentInstance<C> : ComponentInstance<C>|undefined {
get<C extends Component>(cls: ComponentConstructor<C>): C extends All ? ComponentInstance<C> : Required<ComponentInstance<C>>|undefined {
// return this.$components.get(cls) as C
return COMPONENT_ENTITY_ID_MAP.get(cls)?.get(this.id) as any
}
Expand Down
41 changes: 37 additions & 4 deletions src/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ type QueryComponentOptions = {

export type QueryOptions = QueryComponentOptions

export type QueryEvent = 'added'|'removed'
export type QueryEvent = 'added'|'removed'|'updated'
export type QueryListener<C extends Component> = (entity: Entity<C>)=>void
export type QueryListenerDispose = ()=>void

export class Query<All extends Component=Component> {
entities: Set<Entity<All>> = new Set()
Expand All @@ -37,6 +39,8 @@ export class Query<All extends Component=Component> {
private readonly _all: number
private readonly _none: number

private listeners = new Map<QueryEvent, Set<QueryListener<All>>>()

// static isNameQuery(query: Query): query is Query<QueryOptionsByName> {
// return 'name' in query._options
// }
Expand Down Expand Up @@ -69,13 +73,15 @@ export class Query<All extends Component=Component> {
add(entity: Entity<any>){
if(!this.entities.has(entity)){
this.added.add(entity)
this.entities.add(entity)
this.notify('added', entity)
}
this.entities.add(entity)
}

remove(entity: Entity<any>){
if(this.entities.delete(entity)){
this.removed.add(entity)
this.notify('removed', entity)
}
}

Expand All @@ -92,8 +98,35 @@ export class Query<All extends Component=Component> {
this.removed.clear()
}

on(event: QueryEvent, fn: ()=>void){
console.log('query.on', event)
update(entities: Set<Entity<All>>){
for(let entity of entities){
if(this.matches(entity)){
this.add(entity)
} else {
this.remove(entity)
}
}
this.notify('updated')
}

on(event: 'updated', fn: ()=>void): QueryListenerDispose
on(event: 'added', fn: QueryListener<All>): QueryListenerDispose
on(event: 'removed', fn: QueryListener<All>): QueryListenerDispose
on(event: QueryEvent, fn: QueryListener<All>): QueryListenerDispose {
// if(event === 'added'){
// this.addedListeners.add(fn)
// } else if(event === 'removed') {
// this.removedListeners.add(fn)
// }
const listeners = this.listeners.get(event) ?? this.listeners.set(event, new Set()).get(event)!
listeners.add(fn)
return ()=>{
listeners.delete(fn)
}
}

private notify(event: QueryEvent, entity?: Entity){
const listeners = this.listeners.get(event)?.forEach(fn => fn(entity!))
}

}
101 changes: 33 additions & 68 deletions src/QueryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,13 @@ export class QueryManager {
engine: Engine

pendingUpdates: Set<ReactiveEffect> = new Set()
pendingEntities: Set<Entity> = new Set()

constructor(engine: Engine){
this.engine = engine
// this.query_to_entities = new Map()
}

// entitiesForQuery(query: Query): Entity[] {
// if(this.query_to_entities.has(query)){
// return this.query_to_entities.get(query)!
// }
// if(query.entity_name){
// let entities: Entity[] | undefined = this.engine.entity_manager.name_to_entities[query.entity_name]
// if(!!entities){
// this.query_to_entities.set(query, entities)
// } else {
// this.engine.entity_manager.name_to_entities[query.entity_name] = []
// entities = this.engine.entity_manager.name_to_entities[query.entity_name]
// this.query_to_entities.set(query, entities!)
// }
// return entities!
// } else {
// return []
// }
// }

createQuery<C extends Component>(options: QueryOptions): Query<C> {
const query = new Query(options)
// this.updateQuery(query)
Expand All @@ -64,62 +46,45 @@ export class QueryManager {
}

updateQuery(query: Query){
// query.clear()
// this.engine.entity_manager.entities.forEach((entity)=>{
// if(query.matches(entity)){
// query.add(entity)
// }
// })
query.reset()
for(let entity of this.engine.entity_manager.entities){
if(query.matches(entity)){
query.add(entity)
} else {
// console.log('qm.update', 'remove', entity)
query.remove(entity)
}
}
query.update(this.pendingEntities)
}

update(force: boolean = false){
if(force){
// force update all queries
// console.log('query manager : update', this.queries.size)
this.queries.forEach((query)=>{
this.updateQuery(query)
})
} else {
// console.log('querymanager.update', this.pendingUpdates.size)
this.pendingUpdates.forEach(job => {
// @ts-ignore
job()
})
this.pendingUpdates.clear()
}
}

// onComponentAdded<C extends Component>(entity: Entity, cls: ComponentConstructor, component: C){
// this.queries.forEach((query)=>{
// if(query.flush == 'immediate'){
// console.log('on comp added', query)
// this.updateQuery(query)
// }
// })
// }
onComponentRemoved<C extends Component>(entity: Entity<any>){
update(){
this.queries.forEach((query)=>{
if(query.matches(entity)){
query.add(entity)
} else {
query.remove(entity)
}
this.updateQuery(query)
})
this.pendingEntities.clear()
}

onEntityRemoved<C extends Component>(entity: Entity){
this.queries.forEach((query)=>{
query.remove(entity)
})
onComponentAdded<C extends Component>(entity: Entity, cls: ComponentConstructor<C>){
this.pendingEntities.add(entity)
}
onComponentRemoved(entity: Entity<any>){
this.pendingEntities.add(entity)
// this.queries.forEach((query)=>{
// if(query.matches(entity)){
// query.add(entity)
// } else {
// query.remove(entity)
// }
// })
}

onEntityAdded(entity: Entity){
this.pendingEntities.add(entity)
// this.queries.forEach((query)=>{
// if(query.matches(entity)){
// query.add(entity)
// }
// })
}

onEntityRemoved(entity: Entity){
this.pendingEntities.add(entity)
// this.queries.forEach((query)=>{
// query.remove(entity)
// })
}

}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export type { Klass } from './Klass'

export { Component } from './Component'
export type { ComponentInstance, ComponentData, ComponentConstructor } from './Component'
export type { ComponentInstance, ComponentData, ComponentConstructor, EntityComponents } from './Component'
export { ComponentManager } from './ComponentManager'

export { Entity } from './Entity'
Expand Down

0 comments on commit d2af374

Please sign in to comment.