mirror of
				https://github.com/tobspr/shapez.io.git
				synced 2025-06-13 13:04:03 +00:00 
			
		
		
		
	Remove ejector cache; use slot caches instead
This is a small refactoring that removes the main ejector cache. The cache is now tracked by slots and ejector components. It avoids a large array allocation and many small object allocations, but adds many small array allocations. It's net neutral for performance.
This commit is contained in:
		
							parent
							
								
									b753187cde
								
							
						
					
					
						commit
						36cf28029e
					
				| @ -3,13 +3,16 @@ import { BaseItem } from "../base_item"; | ||||
| import { Component } from "../component"; | ||||
| import { types } from "../../savegame/serialization"; | ||||
| import { gItemRegistry } from "../../core/global_registries"; | ||||
| import { Entity } from "../entity"; | ||||
| 
 | ||||
| /** | ||||
|  * @typedef {{ | ||||
|  *    pos: Vector, | ||||
|  *    direction: enumDirection, | ||||
|  *    item: BaseItem, | ||||
|  *    progress: number? | ||||
|  *    progress: number?, | ||||
|  *    cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot, | ||||
|  *    cachedTargetEntity?: Entity | ||||
|  * }} ItemEjectorSlot | ||||
|  */ | ||||
| 
 | ||||
| @ -19,6 +22,8 @@ export class ItemEjectorComponent extends Component { | ||||
|     } | ||||
| 
 | ||||
|     static getSchema() { | ||||
|         // The cachedDestSlot, cachedTargetEntity, and cachedConnectedSlots fields
 | ||||
|         // are not serialized.
 | ||||
|         return { | ||||
|             instantEject: types.bool, | ||||
|             slots: types.array( | ||||
| @ -61,6 +66,9 @@ export class ItemEjectorComponent extends Component { | ||||
|         this.instantEject = instantEject; | ||||
| 
 | ||||
|         this.setSlots(slots); | ||||
| 
 | ||||
|         /** @type {ItemEjectorSlot[]} */ | ||||
|         this.cachedConnectedSlots = null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -76,6 +84,8 @@ export class ItemEjectorComponent extends Component { | ||||
|                 direction: slot.direction, | ||||
|                 item: null, | ||||
|                 progress: 0, | ||||
|                 cachedDestSlot: null, | ||||
|                 cachedTargetEntity: null, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -14,15 +14,6 @@ export class ItemEjectorSystem extends GameSystemWithFilter { | ||||
|     constructor(root) { | ||||
|         super(root, [ItemEjectorComponent]); | ||||
| 
 | ||||
|         /** | ||||
|          * @type {Array<{ | ||||
|          *  targetEntity: Entity, | ||||
|          *  sourceSlot: import("../components/item_ejector").ItemEjectorSlot, | ||||
|          *  destSlot: import("../components/item_acceptor").ItemAcceptorLocatedSlot | ||||
|          * }>} | ||||
|          */ | ||||
|         this.cache = []; | ||||
| 
 | ||||
|         this.cacheNeedsUpdate = true; | ||||
| 
 | ||||
|         this.root.signals.entityAdded.add(this.invalidateCache, this); | ||||
| @ -39,18 +30,24 @@ export class ItemEjectorSystem extends GameSystemWithFilter { | ||||
|     recomputeCache() { | ||||
|         logger.log("Recomputing cache"); | ||||
| 
 | ||||
|         const cache = []; | ||||
| 
 | ||||
|         // Try to find acceptors for every ejector
 | ||||
|         let entryCount = 0; | ||||
|         for (let i = 0; i < this.allEntities.length; ++i) { | ||||
|             const entity = this.allEntities[i]; | ||||
|             const ejectorComp = entity.components.ItemEjector; | ||||
|             const staticComp = entity.components.StaticMapEntity; | ||||
| 
 | ||||
|             // Clear the old cache.
 | ||||
|             ejectorComp.cachedConnectedSlots = null; | ||||
| 
 | ||||
|             // For every ejector slot, try to find an acceptor
 | ||||
|             for (let ejectorSlotIndex = 0; ejectorSlotIndex < ejectorComp.slots.length; ++ejectorSlotIndex) { | ||||
|                 const ejectorSlot = ejectorComp.slots[ejectorSlotIndex]; | ||||
| 
 | ||||
|                 // Clear the old cache.
 | ||||
|                 ejectorSlot.cachedDestSlot = null; | ||||
|                 ejectorSlot.cachedTargetEntity = null; | ||||
| 
 | ||||
|                 // Figure out where and into which direction we eject items
 | ||||
|                 const ejectSlotWsTile = staticComp.localTileToWorld(ejectorSlot.pos); | ||||
|                 const ejectSlotWsDirection = staticComp.localDirectionToWorld(ejectorSlot.direction); | ||||
| @ -82,16 +79,18 @@ export class ItemEjectorSystem extends GameSystemWithFilter { | ||||
|                 } | ||||
| 
 | ||||
|                 // Ok we found a connection
 | ||||
|                 cache.push({ | ||||
|                     targetEntity, | ||||
|                     sourceSlot: ejectorSlot, | ||||
|                     destSlot: matchingSlot, | ||||
|                 }); | ||||
|                 if (ejectorComp.cachedConnectedSlots) { | ||||
|                     ejectorComp.cachedConnectedSlots.push(ejectorSlot); | ||||
|                 } else { | ||||
|                     ejectorComp.cachedConnectedSlots = [ejectorSlot]; | ||||
|                 } | ||||
|                 ejectorSlot.cachedTargetEntity = targetEntity; | ||||
|                 ejectorSlot.cachedDestSlot = matchingSlot; | ||||
|                 entryCount += 1; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this.cache = cache; | ||||
|         logger.log("Found", cache.length, "entries to update"); | ||||
|         logger.log("Found", entryCount, "entries to update"); | ||||
|     } | ||||
| 
 | ||||
|     update() { | ||||
| @ -109,35 +108,45 @@ export class ItemEjectorSystem extends GameSystemWithFilter { | ||||
|         } | ||||
| 
 | ||||
|         // Go over all cache entries
 | ||||
|         for (let i = 0; i < this.cache.length; ++i) { | ||||
|             const { sourceSlot, destSlot, targetEntity } = this.cache[i]; | ||||
|             const item = sourceSlot.item; | ||||
| 
 | ||||
|             if (!item) { | ||||
|                 // No item available to be ejected
 | ||||
|         for (let i = 0; i < this.allEntities.length; ++i) { | ||||
|             const sourceEntity = this.allEntities[i]; | ||||
|             const sourceEjectorComp = sourceEntity.components.ItemEjector; | ||||
|             if (!sourceEjectorComp.cachedConnectedSlots) { | ||||
|                 continue; | ||||
|             } | ||||
|             for (let j = 0; j < sourceEjectorComp.cachedConnectedSlots.length; j++) { | ||||
|                 const sourceSlot = sourceEjectorComp.cachedConnectedSlots[j]; | ||||
|                 const destSlot = sourceSlot.cachedDestSlot; | ||||
|                 const targetEntity = sourceSlot.cachedTargetEntity; | ||||
| 
 | ||||
|             // Advance items on the slot
 | ||||
|             sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth); | ||||
|                 const item = sourceSlot.item; | ||||
| 
 | ||||
|             // Check if we are still in the process of ejecting, can't proceed then
 | ||||
|             if (sourceSlot.progress < 1.0) { | ||||
|                 continue; | ||||
|             } | ||||
|                 if (!item) { | ||||
|                     // No item available to be ejected
 | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|             // Check if the target acceptor can actually accept this item
 | ||||
|             const targetAcceptorComp = targetEntity.components.ItemAcceptor; | ||||
|             if (!targetAcceptorComp.canAcceptItem(destSlot.index, item)) { | ||||
|                 continue; | ||||
|             } | ||||
|                 // Advance items on the slot
 | ||||
|                 sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth); | ||||
| 
 | ||||
|             // Try to hand over the item
 | ||||
|             if (this.tryPassOverItem(item, targetEntity, destSlot.index)) { | ||||
|                 // Handover successful, clear slot
 | ||||
|                 targetAcceptorComp.onItemAccepted(destSlot.index, destSlot.acceptedDirection, item); | ||||
|                 sourceSlot.item = null; | ||||
|                 continue; | ||||
|                 // Check if we are still in the process of ejecting, can't proceed then
 | ||||
|                 if (sourceSlot.progress < 1.0) { | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 // Check if the target acceptor can actually accept this item
 | ||||
|                 const targetAcceptorComp = targetEntity.components.ItemAcceptor; | ||||
|                 if (!targetAcceptorComp.canAcceptItem(destSlot.index, item)) { | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 // Try to hand over the item
 | ||||
|                 if (this.tryPassOverItem(item, targetEntity, destSlot.index)) { | ||||
|                     // Handover successful, clear slot
 | ||||
|                     targetAcceptorComp.onItemAccepted(destSlot.index, destSlot.acceptedDirection, item); | ||||
|                     sourceSlot.item = null; | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user