mirror of
				https://github.com/tobspr/shapez.io.git
				synced 2025-06-13 13:04:03 +00:00 
			
		
		
		
	Optimize performance by using singletons for items
This commit is contained in:
		
							parent
							
								
									3c34227c24
								
							
						
					
					
						commit
						8c39d31c5b
					
				| @ -1,14 +1,14 @@ | |||||||
| import { globalConfig } from "../core/config"; | import { globalConfig } from "../core/config"; | ||||||
| import { DrawParameters } from "../core/draw_parameters"; | import { DrawParameters } from "../core/draw_parameters"; | ||||||
| import { gItemRegistry } from "../core/global_registries"; |  | ||||||
| import { createLogger } from "../core/logging"; | import { createLogger } from "../core/logging"; | ||||||
| import { Rectangle } from "../core/rectangle"; | import { Rectangle } from "../core/rectangle"; | ||||||
| import { epsilonCompare, round4Digits } from "../core/utils"; | import { epsilonCompare, round4Digits } from "../core/utils"; | ||||||
| import { enumDirection, enumDirectionToVector, Vector, enumInvertedDirections } from "../core/vector"; | import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../core/vector"; | ||||||
| import { BasicSerializableObject, types } from "../savegame/serialization"; | import { BasicSerializableObject, types } from "../savegame/serialization"; | ||||||
| import { BaseItem } from "./base_item"; | import { BaseItem } from "./base_item"; | ||||||
| import { Entity } from "./entity"; | import { Entity } from "./entity"; | ||||||
| import { GameRoot, enumLayer } from "./root"; | import { typeItemSingleton } from "./item_resolver"; | ||||||
|  | import { enumLayer, GameRoot } from "./root"; | ||||||
| 
 | 
 | ||||||
| const logger = createLogger("belt_path"); | const logger = createLogger("belt_path"); | ||||||
| 
 | 
 | ||||||
| @ -29,7 +29,7 @@ export class BeltPath extends BasicSerializableObject { | |||||||
|     static getSchema() { |     static getSchema() { | ||||||
|         return { |         return { | ||||||
|             entityPath: types.array(types.entity), |             entityPath: types.array(types.entity), | ||||||
|             items: types.array(types.pair(types.ufloat, types.obj(gItemRegistry))), |             items: types.array(types.pair(types.ufloat, typeItemSingleton)), | ||||||
|             spacingToFirstItem: types.ufloat, |             spacingToFirstItem: types.ufloat, | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ import { gItemRegistry } from "../../core/global_registries"; | |||||||
| import { types } from "../../savegame/serialization"; | import { types } from "../../savegame/serialization"; | ||||||
| import { Component } from "../component"; | import { Component } from "../component"; | ||||||
| import { BaseItem } from "../base_item"; | import { BaseItem } from "../base_item"; | ||||||
|  | import { typeItemSingleton } from "../item_resolver"; | ||||||
| 
 | 
 | ||||||
| export class ConstantSignalComponent extends Component { | export class ConstantSignalComponent extends Component { | ||||||
|     static getId() { |     static getId() { | ||||||
| @ -10,7 +11,7 @@ export class ConstantSignalComponent extends Component { | |||||||
| 
 | 
 | ||||||
|     static getSchema() { |     static getSchema() { | ||||||
|         return { |         return { | ||||||
|             signal: types.nullable(types.obj(gItemRegistry)), |             signal: types.nullable(typeItemSingleton), | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| import { Vector, enumDirection, enumDirectionToVector } from "../../core/vector"; | import { enumDirection, enumDirectionToVector, Vector } from "../../core/vector"; | ||||||
| import { BaseItem } from "../base_item"; |  | ||||||
| import { Component } from "../component"; |  | ||||||
| import { types } from "../../savegame/serialization"; | import { types } from "../../savegame/serialization"; | ||||||
| import { gItemRegistry } from "../../core/global_registries"; | import { BaseItem } from "../base_item"; | ||||||
| import { Entity } from "../entity"; |  | ||||||
| import { enumLayer } from "../root"; |  | ||||||
| import { BeltPath } from "../belt_path"; | import { BeltPath } from "../belt_path"; | ||||||
|  | import { Component } from "../component"; | ||||||
|  | import { Entity } from "../entity"; | ||||||
|  | import { typeItemSingleton } from "../item_resolver"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @typedef {{ |  * @typedef {{ | ||||||
| @ -29,7 +28,7 @@ export class ItemEjectorComponent extends Component { | |||||||
|         return { |         return { | ||||||
|             slots: types.array( |             slots: types.array( | ||||||
|                 types.structured({ |                 types.structured({ | ||||||
|                     item: types.nullable(types.obj(gItemRegistry)), |                     item: types.nullable(typeItemSingleton), | ||||||
|                     progress: types.float, |                     progress: types.float, | ||||||
|                 }) |                 }) | ||||||
|             ), |             ), | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { gItemRegistry } from "../../core/global_registries"; |  | ||||||
| import { types } from "../../savegame/serialization"; | import { types } from "../../savegame/serialization"; | ||||||
| import { BaseItem } from "../base_item"; | import { BaseItem } from "../base_item"; | ||||||
| import { Component } from "../component"; | import { Component } from "../component"; | ||||||
|  | import { typeItemSingleton } from "../item_resolver"; | ||||||
| 
 | 
 | ||||||
| /** @enum {string} */ | /** @enum {string} */ | ||||||
| export const enumItemProcessorTypes = { | export const enumItemProcessorTypes = { | ||||||
| @ -32,13 +32,13 @@ export class ItemProcessorComponent extends Component { | |||||||
|             nextOutputSlot: types.uint, |             nextOutputSlot: types.uint, | ||||||
|             inputSlots: types.array( |             inputSlots: types.array( | ||||||
|                 types.structured({ |                 types.structured({ | ||||||
|                     item: types.obj(gItemRegistry), |                     item: typeItemSingleton, | ||||||
|                     sourceSlot: types.uint, |                     sourceSlot: types.uint, | ||||||
|                 }) |                 }) | ||||||
|             ), |             ), | ||||||
|             itemsToEject: types.array( |             itemsToEject: types.array( | ||||||
|                 types.structured({ |                 types.structured({ | ||||||
|                     item: types.obj(gItemRegistry), |                     item: typeItemSingleton, | ||||||
|                     requiredSlot: types.nullable(types.uint), |                     requiredSlot: types.nullable(types.uint), | ||||||
|                     preferredSlot: types.nullable(types.uint), |                     preferredSlot: types.nullable(types.uint), | ||||||
|                 }) |                 }) | ||||||
|  | |||||||
| @ -1,8 +1,7 @@ | |||||||
| import { globalConfig } from "../../core/config"; |  | ||||||
| import { types } from "../../savegame/serialization"; | import { types } from "../../savegame/serialization"; | ||||||
| import { Component } from "../component"; |  | ||||||
| import { BaseItem } from "../base_item"; | import { BaseItem } from "../base_item"; | ||||||
| import { gItemRegistry } from "../../core/global_registries"; | import { Component } from "../component"; | ||||||
|  | import { typeItemSingleton } from "../item_resolver"; | ||||||
| 
 | 
 | ||||||
| const chainBufferSize = 3; | const chainBufferSize = 3; | ||||||
| 
 | 
 | ||||||
| @ -15,7 +14,7 @@ export class MinerComponent extends Component { | |||||||
|         // cachedMinedItem is not serialized.
 |         // cachedMinedItem is not serialized.
 | ||||||
|         return { |         return { | ||||||
|             lastMiningTime: types.ufloat, |             lastMiningTime: types.ufloat, | ||||||
|             itemChainBuffer: types.array(types.obj(gItemRegistry)), |             itemChainBuffer: types.array(typeItemSingleton), | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,9 +1,7 @@ | |||||||
| import { Component } from "../component"; |  | ||||||
| import { types } from "../../savegame/serialization"; | import { types } from "../../savegame/serialization"; | ||||||
| import { gItemRegistry } from "../../core/global_registries"; |  | ||||||
| import { BaseItem, enumItemType } from "../base_item"; | import { BaseItem, enumItemType } from "../base_item"; | ||||||
| import { ColorItem } from "../items/color_item"; | import { Component } from "../component"; | ||||||
| import { ShapeItem } from "../items/shape_item"; | import { typeItemSingleton } from "../item_resolver"; | ||||||
| 
 | 
 | ||||||
| export class StorageComponent extends Component { | export class StorageComponent extends Component { | ||||||
|     static getId() { |     static getId() { | ||||||
| @ -13,7 +11,7 @@ export class StorageComponent extends Component { | |||||||
|     static getSchema() { |     static getSchema() { | ||||||
|         return { |         return { | ||||||
|             storedCount: types.uint, |             storedCount: types.uint, | ||||||
|             storedItem: types.nullable(types.obj(gItemRegistry)), |             storedItem: types.nullable(typeItemSingleton), | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,10 +1,9 @@ | |||||||
| import { BaseItem } from "../base_item"; |  | ||||||
| import { Component } from "../component"; |  | ||||||
| import { globalConfig } from "../../core/config"; | import { globalConfig } from "../../core/config"; | ||||||
| import { types } from "../../savegame/serialization"; | import { types } from "../../savegame/serialization"; | ||||||
| import { gItemRegistry } from "../../core/global_registries"; | import { BaseItem } from "../base_item"; | ||||||
|  | import { Component } from "../component"; | ||||||
| import { Entity } from "../entity"; | import { Entity } from "../entity"; | ||||||
| import { enumLayer } from "../root"; | import { typeItemSingleton } from "../item_resolver"; | ||||||
| 
 | 
 | ||||||
| /** @enum {string} */ | /** @enum {string} */ | ||||||
| export const enumUndergroundBeltMode = { | export const enumUndergroundBeltMode = { | ||||||
| @ -26,7 +25,7 @@ export class UndergroundBeltComponent extends Component { | |||||||
| 
 | 
 | ||||||
|     static getSchema() { |     static getSchema() { | ||||||
|         return { |         return { | ||||||
|             pendingItems: types.array(types.pair(types.obj(gItemRegistry), types.float)), |             pendingItems: types.array(types.pair(typeItemSingleton, types.float)), | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,7 +13,6 @@ import { randomInt, round2Digits } from "../core/utils"; | |||||||
| import { Vector } from "../core/vector"; | import { Vector } from "../core/vector"; | ||||||
| import { Savegame } from "../savegame/savegame"; | import { Savegame } from "../savegame/savegame"; | ||||||
| import { SavegameSerializer } from "../savegame/savegame_serializer"; | import { SavegameSerializer } from "../savegame/savegame_serializer"; | ||||||
| import { InGameState } from "../states/ingame"; |  | ||||||
| import { AutomaticSave } from "./automatic_save"; | import { AutomaticSave } from "./automatic_save"; | ||||||
| import { MetaHubBuilding } from "./buildings/hub"; | import { MetaHubBuilding } from "./buildings/hub"; | ||||||
| import { Camera } from "./camera"; | import { Camera } from "./camera"; | ||||||
| @ -67,7 +66,7 @@ export class GameCore { | |||||||
|     /** |     /** | ||||||
|      * Initializes the root object which stores all game related data. The state |      * Initializes the root object which stores all game related data. The state | ||||||
|      * is required as a back reference (used sometimes) |      * is required as a back reference (used sometimes) | ||||||
|      * @param {InGameState} parentState |      * @param {import("../states/ingame").InGameState} parentState | ||||||
|      * @param {Savegame} savegame |      * @param {Savegame} savegame | ||||||
|      */ |      */ | ||||||
|     initializeRoot(parentState, savegame) { |     initializeRoot(parentState, savegame) { | ||||||
|  | |||||||
							
								
								
									
										33
									
								
								src/js/game/item_resolver.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/js/game/item_resolver.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | import { types } from "../savegame/serialization"; | ||||||
|  | import { gItemRegistry } from "../core/global_registries"; | ||||||
|  | import { BooleanItem, BOOL_TRUE_SINGLETON, BOOL_FALSE_SINGLETON } from "./items/boolean_item"; | ||||||
|  | import { ShapeItem } from "./items/shape_item"; | ||||||
|  | import { ColorItem, COLOR_ITEM_SINGLETONS } from "./items/color_item"; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Resolves items so we share instances | ||||||
|  |  * @param {import("../savegame/savegame_serializer").GameRoot} root | ||||||
|  |  * @param {{$: string, data: any }} data | ||||||
|  |  */ | ||||||
|  | export function itemResolverSingleton(root, data) { | ||||||
|  |     const itemType = data.$; | ||||||
|  |     const itemData = data.data; | ||||||
|  | 
 | ||||||
|  |     switch (itemType) { | ||||||
|  |         case BooleanItem.getId(): { | ||||||
|  |             return itemData ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; | ||||||
|  |         } | ||||||
|  |         case ShapeItem.getId(): { | ||||||
|  |             return root.shapeDefinitionMgr.getShapeItemFromShortKey(itemData); | ||||||
|  |         } | ||||||
|  |         case ColorItem.getId(): { | ||||||
|  |             return COLOR_ITEM_SINGLETONS[itemData]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         default: { | ||||||
|  |             assertAlways(false, "Unknown item type: " + itemType); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const typeItemSingleton = types.obj(gItemRegistry, itemResolverSingleton); | ||||||
| @ -98,3 +98,13 @@ export class ColorItem extends BaseItem { | |||||||
|         context.fill(); |         context.fill(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Singleton instances | ||||||
|  |  * @type {Object<enumColors, ColorItem>} | ||||||
|  |  */ | ||||||
|  | export const COLOR_ITEM_SINGLETONS = {}; | ||||||
|  | 
 | ||||||
|  | for (const color in enumColors) { | ||||||
|  |     COLOR_ITEM_SINGLETONS[color] = new ColorItem(color); | ||||||
|  | } | ||||||
|  | |||||||
| @ -37,7 +37,6 @@ export class ShapeItem extends BaseItem { | |||||||
|      */ |      */ | ||||||
|     constructor(definition) { |     constructor(definition) { | ||||||
|         super(); |         super(); | ||||||
|         // logger.log("New shape item for shape definition", definition.generateId(), "created");
 |  | ||||||
| 
 | 
 | ||||||
|         /** |         /** | ||||||
|          * This property must not be modified on runtime, you have to clone the class in order to change the definition |          * This property must not be modified on runtime, you have to clone the class in order to change the definition | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ import { Vector } from "../core/vector"; | |||||||
| import { BaseItem } from "./base_item"; | import { BaseItem } from "./base_item"; | ||||||
| import { enumColors } from "./colors"; | import { enumColors } from "./colors"; | ||||||
| import { Entity } from "./entity"; | import { Entity } from "./entity"; | ||||||
| import { ColorItem } from "./items/color_item"; | import { COLOR_ITEM_SINGLETONS } from "./items/color_item"; | ||||||
| import { enumLayer, GameRoot } from "./root"; | import { enumLayer, GameRoot } from "./root"; | ||||||
| import { enumSubShape } from "./shape_definition"; | import { enumSubShape } from "./shape_definition"; | ||||||
| 
 | 
 | ||||||
| @ -139,7 +139,7 @@ export class MapChunk { | |||||||
|         if (distanceToOriginInChunks > 2) { |         if (distanceToOriginInChunks > 2) { | ||||||
|             availableColors.push(enumColors.blue); |             availableColors.push(enumColors.blue); | ||||||
|         } |         } | ||||||
|         this.internalGeneratePatch(rng, colorPatchSize, new ColorItem(rng.choice(availableColors))); |         this.internalGeneratePatch(rng, colorPatchSize, COLOR_ITEM_SINGLETONS[rng.choice(availableColors)]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -268,7 +268,7 @@ export class MapChunk { | |||||||
|      */ |      */ | ||||||
|     generatePredefined(rng) { |     generatePredefined(rng) { | ||||||
|         if (this.x === 0 && this.y === 0) { |         if (this.x === 0 && this.y === 0) { | ||||||
|             this.internalGeneratePatch(rng, 2, new ColorItem(enumColors.red), 7, 7); |             this.internalGeneratePatch(rng, 2, COLOR_ITEM_SINGLETONS[enumColors.red], 7, 7); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|         if (this.x === -1 && this.y === 0) { |         if (this.x === -1 && this.y === 0) { | ||||||
| @ -283,7 +283,7 @@ export class MapChunk { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this.x === -1 && this.y === -1) { |         if (this.x === -1 && this.y === -1) { | ||||||
|             this.internalGeneratePatch(rng, 2, new ColorItem(enumColors.green)); |             this.internalGeneratePatch(rng, 2, COLOR_ITEM_SINGLETONS[enumColors.green]); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,15 +1,14 @@ | |||||||
| import { ConstantSignalComponent } from "../components/constant_signal"; | import trim from "trim"; | ||||||
| import { GameSystemWithFilter } from "../game_system_with_filter"; |  | ||||||
| import { Entity } from "../entity"; |  | ||||||
| import { DialogWithForm } from "../../core/modal_dialog_elements"; | import { DialogWithForm } from "../../core/modal_dialog_elements"; | ||||||
| import { FormElementInput } from "../../core/modal_dialog_forms"; | import { FormElementInput } from "../../core/modal_dialog_forms"; | ||||||
| import { enumColors } from "../colors"; |  | ||||||
| import { ColorItem } from "../items/color_item"; |  | ||||||
| import trim from "trim"; |  | ||||||
| import { BOOL_TRUE_SINGLETON, BOOL_FALSE_SINGLETON } from "../items/boolean_item"; |  | ||||||
| import { ShapeDefinition } from "../shape_definition"; |  | ||||||
| import { ShapeItem } from "../items/shape_item"; |  | ||||||
| import { BaseItem } from "../base_item"; | import { BaseItem } from "../base_item"; | ||||||
|  | import { enumColors } from "../colors"; | ||||||
|  | import { ConstantSignalComponent } from "../components/constant_signal"; | ||||||
|  | import { Entity } from "../entity"; | ||||||
|  | import { GameSystemWithFilter } from "../game_system_with_filter"; | ||||||
|  | import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON } from "../items/boolean_item"; | ||||||
|  | import { COLOR_ITEM_SINGLETONS } from "../items/color_item"; | ||||||
|  | import { ShapeDefinition } from "../shape_definition"; | ||||||
| 
 | 
 | ||||||
| export class ConstantSignalSystem extends GameSystemWithFilter { | export class ConstantSignalSystem extends GameSystemWithFilter { | ||||||
|     constructor(root) { |     constructor(root) { | ||||||
| @ -111,7 +110,7 @@ export class ConstantSignalSystem extends GameSystemWithFilter { | |||||||
|         const codeLower = code.toLowerCase(); |         const codeLower = code.toLowerCase(); | ||||||
| 
 | 
 | ||||||
|         if (enumColors[codeLower]) { |         if (enumColors[codeLower]) { | ||||||
|             return new ColorItem(codeLower); |             return COLOR_ITEM_SINGLETONS[codeLower]; | ||||||
|         } |         } | ||||||
|         if (code === "1" || codeLower === "true") { |         if (code === "1" || codeLower === "true") { | ||||||
|             return BOOL_TRUE_SINGLETON; |             return BOOL_TRUE_SINGLETON; | ||||||
| @ -122,7 +121,7 @@ export class ConstantSignalSystem extends GameSystemWithFilter { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (ShapeDefinition.isValidShortKey(code)) { |         if (ShapeDefinition.isValidShortKey(code)) { | ||||||
|             return new ShapeItem(this.root.shapeDefinitionMgr.getShapeFromShortKey(code)); |             return this.root.shapeDefinitionMgr.getShapeItemFromShortKey(code); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return null; |         return null; | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| import { GameSystemWithFilter } from "../game_system_with_filter"; |  | ||||||
| import { HubComponent } from "../components/hub"; |  | ||||||
| import { DrawParameters } from "../../core/draw_parameters"; | import { DrawParameters } from "../../core/draw_parameters"; | ||||||
| import { Entity } from "../entity"; |  | ||||||
| import { formatBigNumber } from "../../core/utils"; |  | ||||||
| import { Loader } from "../../core/loader"; | import { Loader } from "../../core/loader"; | ||||||
|  | import { formatBigNumber } from "../../core/utils"; | ||||||
| import { T } from "../../translations"; | import { T } from "../../translations"; | ||||||
| import { ShapeItem } from "../items/shape_item"; | import { HubComponent } from "../components/hub"; | ||||||
|  | import { Entity } from "../entity"; | ||||||
|  | import { GameSystemWithFilter } from "../game_system_with_filter"; | ||||||
| 
 | 
 | ||||||
| export class HubSystem extends GameSystemWithFilter { | export class HubSystem extends GameSystemWithFilter { | ||||||
|     constructor(root) { |     constructor(root) { | ||||||
| @ -23,7 +22,9 @@ export class HubSystem extends GameSystemWithFilter { | |||||||
|             // Set hub goal
 |             // Set hub goal
 | ||||||
|             const entity = this.allEntities[i]; |             const entity = this.allEntities[i]; | ||||||
|             const pinsComp = entity.components.WiredPins; |             const pinsComp = entity.components.WiredPins; | ||||||
|             pinsComp.slots[0].value = new ShapeItem(this.root.hubGoals.currentGoal.definition); |             pinsComp.slots[0].value = this.root.shapeDefinitionMgr.getShapeItemFromDefinition( | ||||||
|  |                 this.root.hubGoals.currentGoal.definition | ||||||
|  |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/it | |||||||
| import { Entity } from "../entity"; | import { Entity } from "../entity"; | ||||||
| import { GameSystemWithFilter } from "../game_system_with_filter"; | import { GameSystemWithFilter } from "../game_system_with_filter"; | ||||||
| import { BOOL_TRUE_SINGLETON } from "../items/boolean_item"; | import { BOOL_TRUE_SINGLETON } from "../items/boolean_item"; | ||||||
| import { ColorItem } from "../items/color_item"; | import { ColorItem, COLOR_ITEM_SINGLETONS } from "../items/color_item"; | ||||||
| import { ShapeItem } from "../items/shape_item"; | import { ShapeItem } from "../items/shape_item"; | ||||||
| 
 | 
 | ||||||
| export class ItemProcessorSystem extends GameSystemWithFilter { | export class ItemProcessorSystem extends GameSystemWithFilter { | ||||||
| @ -134,7 +134,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                     const definition = cutDefinitions[i]; |                     const definition = cutDefinitions[i]; | ||||||
|                     if (!definition.isEntirelyEmpty()) { |                     if (!definition.isEntirelyEmpty()) { | ||||||
|                         outItems.push({ |                         outItems.push({ | ||||||
|                             item: new ShapeItem(definition), |                             item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition), | ||||||
|                             requiredSlot: i, |                             requiredSlot: i, | ||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
| @ -155,7 +155,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                     const definition = cutDefinitions[i]; |                     const definition = cutDefinitions[i]; | ||||||
|                     if (!definition.isEntirelyEmpty()) { |                     if (!definition.isEntirelyEmpty()) { | ||||||
|                         outItems.push({ |                         outItems.push({ | ||||||
|                             item: new ShapeItem(definition), |                             item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition), | ||||||
|                             requiredSlot: i, |                             requiredSlot: i, | ||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
| @ -172,7 +172,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
| 
 | 
 | ||||||
|                 const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition); |                 const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition); | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(rotatedDefinition), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition), | ||||||
|                 }); |                 }); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -185,7 +185,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
| 
 | 
 | ||||||
|                 const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(inputDefinition); |                 const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(inputDefinition); | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(rotatedDefinition), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition), | ||||||
|                 }); |                 }); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -198,7 +198,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
| 
 | 
 | ||||||
|                 const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(inputDefinition); |                 const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(inputDefinition); | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(rotatedDefinition), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition), | ||||||
|                 }); |                 }); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -217,7 +217,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                     upperItem.definition |                     upperItem.definition | ||||||
|                 ); |                 ); | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(stackedDefinition), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition), | ||||||
|                 }); |                 }); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @ -248,7 +248,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                     resultColor = mixedColor; |                     resultColor = mixedColor; | ||||||
|                 } |                 } | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ColorItem(resultColor), |                     item: COLOR_ITEM_SINGLETONS[resultColor], | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 break; |                 break; | ||||||
| @ -266,7 +266,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(colorizedDefinition), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition), | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 break; |                 break; | ||||||
| @ -293,11 +293,11 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                     colorItem.color |                     colorItem.color | ||||||
|                 ); |                 ); | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(colorizedDefinition1), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1), | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(colorizedDefinition2), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2), | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 break; |                 break; | ||||||
| @ -324,7 +324,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { | |||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 outItems.push({ |                 outItems.push({ | ||||||
|                     item: new ShapeItem(colorizedDefinition), |                     item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition), | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 break; |                 break; | ||||||
|  | |||||||
| @ -1,8 +1,11 @@ | |||||||
|  | import { createLogger } from "../core/logging"; | ||||||
| import { | import { | ||||||
|     BaseDataType, |     BaseDataType, | ||||||
|     TypeArray, |     TypeArray, | ||||||
|     TypeBoolean, |     TypeBoolean, | ||||||
|     TypeClass, |     TypeClass, | ||||||
|  |     TypeClassData, | ||||||
|  |     TypeClassFromMetaclass, | ||||||
|     TypeClassId, |     TypeClassId, | ||||||
|     TypeEntity, |     TypeEntity, | ||||||
|     TypeEntityWeakref, |     TypeEntityWeakref, | ||||||
| @ -17,12 +20,9 @@ import { | |||||||
|     TypePositiveInteger, |     TypePositiveInteger, | ||||||
|     TypePositiveNumber, |     TypePositiveNumber, | ||||||
|     TypeString, |     TypeString, | ||||||
|     TypeVector, |  | ||||||
|     TypeClassFromMetaclass, |  | ||||||
|     TypeClassData, |  | ||||||
|     TypeStructuredObject, |     TypeStructuredObject, | ||||||
|  |     TypeVector, | ||||||
| } from "./serialization_data_types"; | } from "./serialization_data_types"; | ||||||
| import { createLogger } from "../core/logging"; |  | ||||||
| 
 | 
 | ||||||
| const logger = createLogger("serialization"); | const logger = createLogger("serialization"); | ||||||
| 
 | 
 | ||||||
| @ -69,9 +69,10 @@ export const types = { | |||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @param {FactoryTemplate<*>} registry |      * @param {FactoryTemplate<*>} registry | ||||||
|  |      * @param {(GameRoot, any) => object=} resolver | ||||||
|      */ |      */ | ||||||
|     obj(registry) { |     obj(registry, resolver = null) { | ||||||
|         return new TypeClass(registry); |         return new TypeClass(registry, resolver); | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -190,12 +191,18 @@ export class BasicSerializableObject { | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** @returns {string|void} */ |     /** | ||||||
|     deserialize(data) { |      * @param {any} data | ||||||
|  |      * @param {import("./savegame_serializer").GameRoot} root | ||||||
|  |      * @returns {string|void} | ||||||
|  |      */ | ||||||
|  |     deserialize(data, root = null) { | ||||||
|         return deserializeSchema( |         return deserializeSchema( | ||||||
|             this, |             this, | ||||||
|             /** @type {typeof BasicSerializableObject} */ (this.constructor).getCachedSchema(), |             /** @type {typeof BasicSerializableObject} */ (this.constructor).getCachedSchema(), | ||||||
|             data |             data, | ||||||
|  |             null, | ||||||
|  |             root | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -253,9 +260,10 @@ export function serializeSchema(obj, schema, mergeWith = {}) { | |||||||
|  * @param {Schema} schema The schema to use |  * @param {Schema} schema The schema to use | ||||||
|  * @param {object} data The serialized data |  * @param {object} data The serialized data | ||||||
|  * @param {string|void|null=} baseclassErrorResult Convenience, if this is a string error code, do nothing and return it |  * @param {string|void|null=} baseclassErrorResult Convenience, if this is a string error code, do nothing and return it | ||||||
|  |  * @param {import("../game/root").GameRoot=} root Optional game root reference | ||||||
|  * @returns {string|void} String error code or nothing on success |  * @returns {string|void} String error code or nothing on success | ||||||
|  */ |  */ | ||||||
| export function deserializeSchema(obj, schema, data, baseclassErrorResult = null) { | export function deserializeSchema(obj, schema, data, baseclassErrorResult = null, root) { | ||||||
|     if (baseclassErrorResult) { |     if (baseclassErrorResult) { | ||||||
|         return baseclassErrorResult; |         return baseclassErrorResult; | ||||||
|     } |     } | ||||||
| @ -275,7 +283,7 @@ export function deserializeSchema(obj, schema, data, baseclassErrorResult = null | |||||||
|             return "Non-nullable entry is null: " + key + " of class " + obj.constructor.name; |             return "Non-nullable entry is null: " + key + " of class " + obj.constructor.name; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const errorStatus = schema[key].deserializeWithVerify(data[key], obj, key, obj.root); |         const errorStatus = schema[key].deserializeWithVerify(data[key], obj, key, obj.root || root); | ||||||
|         if (errorStatus) { |         if (errorStatus) { | ||||||
|             logger.error( |             logger.error( | ||||||
|                 "Deserialization failed with error '" + errorStatus + "' on object", |                 "Deserialization failed with error '" + errorStatus + "' on object", | ||||||
|  | |||||||
| @ -595,10 +595,12 @@ export class TypeClass extends BaseDataType { | |||||||
|     /** |     /** | ||||||
|      * |      * | ||||||
|      * @param {FactoryTemplate<*>} registry |      * @param {FactoryTemplate<*>} registry | ||||||
|  |      * @param {(GameRoot, object) => object} customResolver | ||||||
|      */ |      */ | ||||||
|     constructor(registry) { |     constructor(registry, customResolver = null) { | ||||||
|         super(); |         super(); | ||||||
|         this.registry = registry; |         this.registry = registry; | ||||||
|  |         this.customResolver = customResolver; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     serialize(value) { |     serialize(value) { | ||||||
| @ -640,14 +642,23 @@ export class TypeClass extends BaseDataType { | |||||||
|      * @returns {string|void} String error code or null on success |      * @returns {string|void} String error code or null on success | ||||||
|      */ |      */ | ||||||
|     deserialize(value, targetObject, targetKey, root) { |     deserialize(value, targetObject, targetKey, root) { | ||||||
|         const instanceClass = this.registry.findById(value.$); |         let instance; | ||||||
|         if (!instanceClass || !instanceClass.prototype) { | 
 | ||||||
|             return "Invalid class id (runtime-err): " + value.$ + "->" + instanceClass; |         if (this.customResolver) { | ||||||
|         } |             instance = this.customResolver(root, value); | ||||||
|         const instance = Object.create(instanceClass.prototype); |             if (!instance) { | ||||||
|         const errorState = instance.deserialize(value.data); |                 return "Failed to call custom resolver"; | ||||||
|         if (errorState) { |             } | ||||||
|             return errorState; |         } else { | ||||||
|  |             const instanceClass = this.registry.findById(value.$); | ||||||
|  |             if (!instanceClass || !instanceClass.prototype) { | ||||||
|  |                 return "Invalid class id (runtime-err): " + value.$ + "->" + instanceClass; | ||||||
|  |             } | ||||||
|  |             instance = Object.create(instanceClass.prototype); | ||||||
|  |             const errorState = instance.deserialize(value.data); | ||||||
|  |             if (errorState) { | ||||||
|  |                 return errorState; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         targetObject[targetKey] = instance; |         targetObject[targetKey] = instance; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ export class SerializerInternal { | |||||||
| 
 | 
 | ||||||
|         entity.uid = payload.uid; |         entity.uid = payload.uid; | ||||||
| 
 | 
 | ||||||
|         this.deserializeComponents(entity, payload.components); |         this.deserializeComponents(root, entity, payload.components); | ||||||
| 
 | 
 | ||||||
|         root.entityMgr.registerEntity(entity, payload.uid); |         root.entityMgr.registerEntity(entity, payload.uid); | ||||||
|         root.map.placeStaticEntity(entity); |         root.map.placeStaticEntity(entity); | ||||||
| @ -70,18 +70,19 @@ export class SerializerInternal { | |||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Deserializes components of an entity |      * Deserializes components of an entity | ||||||
|  |      * @param {GameRoot} root | ||||||
|      * @param {Entity} entity |      * @param {Entity} entity | ||||||
|      * @param {Object.<string, any>} data |      * @param {Object.<string, any>} data | ||||||
|      * @returns {string|void} |      * @returns {string|void} | ||||||
|      */ |      */ | ||||||
|     deserializeComponents(entity, data) { |     deserializeComponents(root, entity, data) { | ||||||
|         for (const componentId in data) { |         for (const componentId in data) { | ||||||
|             if (!entity.components[componentId]) { |             if (!entity.components[componentId]) { | ||||||
|                 logger.warn("Entity no longer has component:", componentId); |                 logger.warn("Entity no longer has component:", componentId); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const errorStatus = entity.components[componentId].deserialize(data[componentId]); |             const errorStatus = entity.components[componentId].deserialize(data[componentId], root); | ||||||
|             if (errorStatus) { |             if (errorStatus) { | ||||||
|                 return errorStatus; |                 return errorStatus; | ||||||
|             } |             } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user