/**
 * Entity Component System module
 */ import Entity from "./entity" ; import System from "./system" ; import performance from "./performance" ; import { fastSplice } from "./utils" ; import { RNG , createRNG } from "@thorium/rng" ; import { ServerDataModel } from "server/src/classes/ServerDataModel" ; class ECS { /**
     * Store all entities of the ECS.
     */ entities : Entity [ ] = [ ] ; /**
     * Store entities which need to be tested at beginning of next tick.
     */ entitiesSystemsDirty : Entity [ ] = [ ] ; /**
     * Store all systems of the ECS.
     */ systems : System [ ] = [ ] ; /**
     * Count how many updates have been done.
     */ updateCounter = 0 ; lastUpdate = performance . now ( ) ; rng : RNG ; constructor ( public server , seed = "thorium" , skip ? ) { this . rng = createRNG ( seed , skip ) ; } /**
     * Retrieve an entity by id
     */ getEntityById ( id ) { for ( let i = 0 , entity ; ( entity = this . entities [ i ] ) ; i += 1 ) { if ( entity . id === id ) { return entity ; } } return null ; } /**
     * Add an entity to the ecs.
     */ addEntity ( entity ) { this . entities . push ( entity ) ; entity . addToECS ( this ) ; } /**
     * Remove an entity from the ecs by reference.
     */ removeEntity ( entity ) { let index = this . entities . findIndex ( e => e . id === entity . id ) ; let entityRemoved = null ; if ( index !== - 1 ) { entityRemoved = this . entities [ index ] ; entity . dispose ( ) ; this . removeEntityIfDirty ( entityRemoved ) ; fastSplice ( this . entities , index , 1 ) ; } return entityRemoved ; } /**
     * Remove an entity from the ecs by entity id.
     */ removeEntityById ( entityId ) { for ( let i = 0 , entity ; ( entity = this . entities [ i ] ) ; i += 1 ) { if ( entity . id === entityId ) { entity . dispose ( ) ; this . removeEntity ( entity ) ; fastSplice ( this . entities , i , 1 ) ; return entity ; } } return null ; } /**
     * Remove an entity from dirty entities by reference.
     */ removeEntityIfDirty ( entity ) { let index = this . entitiesSystemsDirty . indexOf ( entity ) ; if ( index !== - 1 ) { fastSplice ( this . entities , index , 1 ) ; } } /**
     * Add a system to the ecs.
     */ addSystem ( system ) { system . ecs = this ; this . systems . push ( system ) ; for ( let i = 0 , entity ; ( entity = this . entities [ i ] ) ; i += 1 ) { if ( system . test ( entity ) ) { system . addEntity ( entity ) ; } } } /**
     * Remove a system from the ecs.
     */ removeSystem ( system ) { let index = this . systems . indexOf ( system ) ; if ( index !== - 1 ) { fastSplice ( this . systems , index , 1 ) ; system . dispose ( ) ; } } /**
     * "Clean" entities flagged as dirty by removing unecessary systems and
     * adding missing systems.
     */ cleanDirtyEntities ( ) { for ( let i = 0 , entity ; ( entity = this . entitiesSystemsDirty [ i ] ) ; i += 1 ) { for ( let s = 0 , system ; ( system = this . systems [ s ] ) ; s += 1 ) { let index = entity . systems . indexOf ( system ) ; let entityTest = system . test ( entity ) ; if ( index === - 1 && entityTest ) { system . addEntity ( entity ) ; } else if ( index !== - 1 && ! entityTest ) { system . removeEntity ( entity ) ; } } entity . systemsDirty = false ; } this . entitiesSystemsDirty = [ ] ; } method update ( testElapsed ? ) { let now = performance . now ( ) ; let elapsed = testElapsed ?? now - this . lastUpdate ; for ( let i = 0 , system ; ( system = this . systems [ i ] ) ; i += 1 ) { if ( this . updateCounter % system . frequency > 0 ) { break ; } if ( this . entitiesSystemsDirty . length ) { this . cleanDirtyEntities ( ) ; } system . updateAll ( elapsed ) ; } this . updateCounter += 1 ; this . lastUpdate = now ; } } export default ECS ;