mirror of
				https://github.com/tobspr/shapez.io.git
				synced 2025-06-13 13:04:03 +00:00 
			
		
		
		
	Improve item ejector system
This commit is contained in:
		
							parent
							
								
									c0c624135b
								
							
						
					
					
						commit
						746f4935ad
					
				| @ -40,9 +40,9 @@ export class StaleAreaDetector { | ||||
|      * Makes this detector recompute the area of an entity whenever | ||||
|      * it changes in any way | ||||
|      * @param {Array<typeof Component>} components | ||||
|      * @param {number} tilesAround | ||||
|      * @param {number} tilesAround How many tiles arround to expand the area | ||||
|      */ | ||||
|     recomputeOnComponentsChanged(components, tilesAround = 1) { | ||||
|     recomputeOnComponentsChanged(components, tilesAround) { | ||||
|         const componentIds = components.map(component => component.getId()); | ||||
| 
 | ||||
|         /** | ||||
| @ -50,6 +50,10 @@ export class StaleAreaDetector { | ||||
|          * @param {Entity} entity | ||||
|          */ | ||||
|         const checker = entity => { | ||||
|             if (!this.root.gameInitialized) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Check for all components
 | ||||
|             for (let i = 0; i < componentIds.length; ++i) { | ||||
|                 if (entity.components[componentIds[i]]) { | ||||
|  | ||||
| @ -2,8 +2,11 @@ import { globalConfig } from "../../core/config"; | ||||
| import { DrawParameters } from "../../core/draw_parameters"; | ||||
| import { createLogger } from "../../core/logging"; | ||||
| import { Rectangle } from "../../core/rectangle"; | ||||
| import { StaleAreaDetector } from "../../core/stale_area_detector"; | ||||
| import { enumDirection, enumDirectionToVector } from "../../core/vector"; | ||||
| import { BaseItem } from "../base_item"; | ||||
| import { BeltComponent } from "../components/belt"; | ||||
| import { ItemAcceptorComponent } from "../components/item_acceptor"; | ||||
| import { ItemEjectorComponent } from "../components/item_ejector"; | ||||
| import { Entity } from "../entity"; | ||||
| import { GameSystemWithFilter } from "../game_system_with_filter"; | ||||
| @ -15,102 +18,52 @@ export class ItemEjectorSystem extends GameSystemWithFilter { | ||||
|     constructor(root) { | ||||
|         super(root, [ItemEjectorComponent]); | ||||
| 
 | ||||
|         this.root.signals.entityAdded.add(this.checkForCacheInvalidation, this); | ||||
|         this.root.signals.entityDestroyed.add(this.checkForCacheInvalidation, this); | ||||
|         this.root.signals.postLoadHook.add(this.recomputeCache, this); | ||||
|         this.staleAreaDetector = new StaleAreaDetector({ | ||||
|             root: this.root, | ||||
|             name: "item-ejector", | ||||
|             recomputeMethod: this.recomputeArea.bind(this), | ||||
|         }); | ||||
| 
 | ||||
|         /** | ||||
|          * @type {Rectangle} | ||||
|          */ | ||||
|         this.areaToRecompute = null; | ||||
|         this.staleAreaDetector.recomputeOnComponentsChanged( | ||||
|             [ItemEjectorComponent, ItemAcceptorComponent, BeltComponent], | ||||
|             1 | ||||
|         ); | ||||
| 
 | ||||
|         this.root.signals.postLoadHook.add(this.recomputeCacheFull, this); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * | ||||
|      * @param {Entity} entity | ||||
|      * Recomputes an area after it changed | ||||
|      * @param {Rectangle} area | ||||
|      */ | ||||
|     checkForCacheInvalidation(entity) { | ||||
|         if (!this.root.gameInitialized) { | ||||
|             return; | ||||
|         } | ||||
|         if (!entity.components.StaticMapEntity) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Optimize for the common case: adding or removing one building at a time. Clicking
 | ||||
|         // and dragging can cause up to 4 add/remove signals.
 | ||||
|         const staticComp = entity.components.StaticMapEntity; | ||||
|         const bounds = staticComp.getTileSpaceBounds(); | ||||
|         const expandedBounds = bounds.expandedInAllDirections(2); | ||||
| 
 | ||||
|         if (this.areaToRecompute) { | ||||
|             this.areaToRecompute = this.areaToRecompute.getUnion(expandedBounds); | ||||
|         } else { | ||||
|             this.areaToRecompute = expandedBounds; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Precomputes the cache, which makes up for a huge performance improvement | ||||
|      */ | ||||
|     recomputeCache() { | ||||
|         if (this.areaToRecompute) { | ||||
|             logger.log("Recomputing cache using rectangle"); | ||||
|             if (G_IS_DEV && globalConfig.debug.renderChanges) { | ||||
|                 this.root.hud.parts.changesDebugger.renderChange( | ||||
|                     "ejector-area", | ||||
|                     this.areaToRecompute, | ||||
|                     "#fe50a6" | ||||
|                 ); | ||||
|             } | ||||
|             this.recomputeAreaCache(); | ||||
|             this.areaToRecompute = null; | ||||
|         } else { | ||||
|             logger.log("Full cache recompute"); | ||||
|             if (G_IS_DEV && globalConfig.debug.renderChanges) { | ||||
|                 this.root.hud.parts.changesDebugger.renderChange( | ||||
|                     "ejector-full", | ||||
|                     new Rectangle(-1000, -1000, 2000, 2000), | ||||
|                     "#fe50a6" | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             // Try to find acceptors for every ejector
 | ||||
|             for (let i = 0; i < this.allEntities.length; ++i) { | ||||
|                 const entity = this.allEntities[i]; | ||||
|                 this.recomputeSingleEntityCache(entity); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recomputes the cache in the given area | ||||
|      */ | ||||
|     recomputeAreaCache() { | ||||
|         const area = this.areaToRecompute; | ||||
|         let entryCount = 0; | ||||
| 
 | ||||
|         logger.log("Recomputing area:", area.x, area.y, "/", area.w, area.h); | ||||
| 
 | ||||
|         // Store the entities we already recomputed, so we don't do work twice
 | ||||
|         const recomputedEntities = new Set(); | ||||
| 
 | ||||
|         for (let x = area.x; x < area.right(); ++x) { | ||||
|             for (let y = area.y; y < area.bottom(); ++y) { | ||||
|                 const entities = this.root.map.getLayersContentsMultipleXY(x, y); | ||||
|                 for (let i = 0; i < entities.length; ++i) { | ||||
|                     const entity = entities[i]; | ||||
| 
 | ||||
|                     // Recompute the entity in case its relevant for this system and it
 | ||||
|                     // hasn't already been computed
 | ||||
|                     if (!recomputedEntities.has(entity.uid) && entity.components.ItemEjector) { | ||||
|                         recomputedEntities.add(entity.uid); | ||||
|                         this.recomputeSingleEntityCache(entity); | ||||
|     recomputeArea(area) { | ||||
|         /** @type {Set<number>} */ | ||||
|         const seenUids = new Set(); | ||||
|         for (let x = 0; x < area.w; ++x) { | ||||
|             for (let y = 0; y < area.h; ++y) { | ||||
|                 const tileX = area.x + x; | ||||
|                 const tileY = area.y + y; | ||||
|                 // @NOTICE: Item ejector currently only supports regular layer
 | ||||
|                 const contents = this.root.map.getLayerContentXY(tileX, tileY, "regular"); | ||||
|                 if (contents && contents.components.ItemEjector) { | ||||
|                     if (!seenUids.has(contents.uid)) { | ||||
|                         seenUids.add(contents.uid); | ||||
|                         this.recomputeSingleEntityCache(contents); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return entryCount; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recomputes the whole cache after the game has loaded | ||||
|      */ | ||||
|     recomputeCacheFull() { | ||||
|         logger.log("Full cache recompute in post load hook"); | ||||
|         for (let i = 0; i < this.allEntities.length; ++i) { | ||||
|             const entity = this.allEntities[i]; | ||||
|             this.recomputeSingleEntityCache(entity); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -183,9 +136,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter { | ||||
|     } | ||||
| 
 | ||||
|     update() { | ||||
|         if (this.areaToRecompute) { | ||||
|             this.recomputeCache(); | ||||
|         } | ||||
|         this.staleAreaDetector.update(); | ||||
| 
 | ||||
|         // Precompute effective belt speed
 | ||||
|         let progressGrowth = 2 * this.root.dynamicTickrate.deltaSeconds; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user