From 9701a143ecea83d6fd5c6b5874f7fa9ae876056f Mon Sep 17 00:00:00 2001 From: tobspr Date: Mon, 10 Aug 2020 22:53:02 +0200 Subject: [PATCH] Only store changed properties for all components --- src/js/game/buildings/belt_base.js | 11 ++--- src/js/game/buildings/hub.js | 7 +-- src/js/game/component_registry.js | 4 -- src/js/game/components/belt.js | 6 --- src/js/game/components/belt_underlays.js | 11 ----- src/js/game/components/item_acceptor.js | 12 ----- src/js/game/components/item_ejector.js | 2 - src/js/game/components/item_processor.js | 3 -- src/js/game/components/miner.js | 1 - .../game/components/replaceable_map_entity.js | 15 ------ src/js/game/components/static_map_entity.js | 10 +++- src/js/game/components/storage.js | 2 - src/js/game/components/underground_belt.js | 2 - src/js/game/components/unremovable.js | 15 ------ src/js/game/components/wired_pins.js | 11 ----- src/js/game/entity.js | 3 +- src/js/game/entity_components.js | 34 ++++---------- src/js/game/logic.js | 14 ++++-- src/js/game/meta_building.js | 15 ++++++ src/js/game/systems/wired_pins.js | 10 ++-- src/js/savegame/serialization_data_types.js | 18 +++++--- src/js/savegame/serializer_internal.js | 46 ++++++++++++------- 22 files changed, 100 insertions(+), 152 deletions(-) delete mode 100644 src/js/game/components/replaceable_map_entity.js delete mode 100644 src/js/game/components/unremovable.js diff --git a/src/js/game/buildings/belt_base.js b/src/js/game/buildings/belt_base.js index 116350d5..7727a996 100644 --- a/src/js/game/buildings/belt_base.js +++ b/src/js/game/buildings/belt_base.js @@ -3,12 +3,9 @@ import { enumAngleToDirection, enumDirection, Vector } from "../../core/vector"; import { SOUNDS } from "../../platform/sound"; import { T } from "../../translations"; import { BeltComponent } from "../components/belt"; -import { ItemAcceptorComponent } from "../components/item_acceptor"; -import { ItemEjectorComponent } from "../components/item_ejector"; -import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; -import { GameRoot, enumLayer } from "../root"; +import { GameRoot } from "../root"; export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right]; @@ -43,6 +40,10 @@ export class MetaBeltBaseBuilding extends MetaBuilding { return null; } + getIsReplaceable() { + return true; + } + /** * Creates the entity at the given location * @param {Entity} entity @@ -53,8 +54,6 @@ export class MetaBeltBaseBuilding extends MetaBuilding { direction: enumDirection.top, // updated later }) ); - // Make this entity replaceable - entity.addComponent(new ReplaceableMapEntityComponent()); } /** diff --git a/src/js/game/buildings/hub.js b/src/js/game/buildings/hub.js index 07ca4360..f67032b7 100644 --- a/src/js/game/buildings/hub.js +++ b/src/js/game/buildings/hub.js @@ -3,7 +3,6 @@ import { enumItemType } from "../base_item"; import { HubComponent } from "../components/hub"; import { ItemAcceptorComponent } from "../components/item_acceptor"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; -import { UnremovableComponent } from "../components/unremovable"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins"; @@ -34,6 +33,10 @@ export class MetaHubBuilding extends MetaBuilding { return null; } + getIsRemovable() { + return false; + } + /** * Creates the entity at the given location * @param {Entity} entity @@ -47,8 +50,6 @@ export class MetaHubBuilding extends MetaBuilding { }) ); - entity.addComponent(new UnremovableComponent()); - entity.addComponent( new WiredPinsComponent({ slots: [ diff --git a/src/js/game/component_registry.js b/src/js/game/component_registry.js index 4d28e757..2c64b5f4 100644 --- a/src/js/game/component_registry.js +++ b/src/js/game/component_registry.js @@ -5,9 +5,7 @@ import { ItemEjectorComponent } from "./components/item_ejector"; import { ItemAcceptorComponent } from "./components/item_acceptor"; import { MinerComponent } from "./components/miner"; import { ItemProcessorComponent } from "./components/item_processor"; -import { ReplaceableMapEntityComponent } from "./components/replaceable_map_entity"; import { UndergroundBeltComponent } from "./components/underground_belt"; -import { UnremovableComponent } from "./components/unremovable"; import { HubComponent } from "./components/hub"; import { StorageComponent } from "./components/storage"; import { WiredPinsComponent } from "./components/wired_pins"; @@ -20,9 +18,7 @@ export function initComponentRegistry() { gComponentRegistry.register(ItemAcceptorComponent); gComponentRegistry.register(MinerComponent); gComponentRegistry.register(ItemProcessorComponent); - gComponentRegistry.register(ReplaceableMapEntityComponent); gComponentRegistry.register(UndergroundBeltComponent); - gComponentRegistry.register(UnremovableComponent); gComponentRegistry.register(HubComponent); gComponentRegistry.register(StorageComponent); gComponentRegistry.register(WiredPinsComponent); diff --git a/src/js/game/components/belt.js b/src/js/game/components/belt.js index 0c90d24a..02197822 100644 --- a/src/js/game/components/belt.js +++ b/src/js/game/components/belt.js @@ -40,12 +40,6 @@ export class BeltComponent extends Component { return "Belt"; } - static getSchema() { - return { - direction: types.string, - }; - } - duplicateWithoutContents() { return new BeltComponent({ direction: this.direction }); } diff --git a/src/js/game/components/belt_underlays.js b/src/js/game/components/belt_underlays.js index cdc3473f..cb516b1a 100644 --- a/src/js/game/components/belt_underlays.js +++ b/src/js/game/components/belt_underlays.js @@ -7,17 +7,6 @@ export class BeltUnderlaysComponent extends Component { return "BeltUnderlays"; } - static getSchema() { - return { - underlays: types.array( - types.structured({ - pos: types.vector, - direction: types.enum(enumDirection), - }) - ), - }; - } - duplicateWithoutContents() { const beltUnderlaysCopy = []; for (let i = 0; i < this.underlays.length; ++i) { diff --git a/src/js/game/components/item_acceptor.js b/src/js/game/components/item_acceptor.js index 3e3ecbeb..c51093ff 100644 --- a/src/js/game/components/item_acceptor.js +++ b/src/js/game/components/item_acceptor.js @@ -28,18 +28,6 @@ export class ItemAcceptorComponent extends Component { return "ItemAcceptor"; } - static getSchema() { - return { - slots: types.array( - types.structured({ - pos: types.vector, - directions: types.array(types.enum(enumDirection)), - filter: types.nullable(types.enum(enumItemType)), - }) - ), - }; - } - duplicateWithoutContents() { const slotsCopy = []; for (let i = 0; i < this.slots.length; ++i) { diff --git a/src/js/game/components/item_ejector.js b/src/js/game/components/item_ejector.js index b42eac7a..281cf91e 100644 --- a/src/js/game/components/item_ejector.js +++ b/src/js/game/components/item_ejector.js @@ -29,8 +29,6 @@ export class ItemEjectorComponent extends Component { return { slots: types.array( types.structured({ - pos: types.vector, - direction: types.enum(enumDirection), item: types.nullable(types.obj(gItemRegistry)), progress: types.float, }) diff --git a/src/js/game/components/item_processor.js b/src/js/game/components/item_processor.js index 3bc7c53a..eeb045a9 100644 --- a/src/js/game/components/item_processor.js +++ b/src/js/game/components/item_processor.js @@ -29,9 +29,6 @@ export class ItemProcessorComponent extends Component { static getSchema() { return { nextOutputSlot: types.uint, - type: types.enum(enumItemProcessorTypes), - inputsPerCharge: types.uint, - inputSlots: types.array( types.structured({ item: types.obj(gItemRegistry), diff --git a/src/js/game/components/miner.js b/src/js/game/components/miner.js index 74a4b616..411e49b9 100644 --- a/src/js/game/components/miner.js +++ b/src/js/game/components/miner.js @@ -15,7 +15,6 @@ export class MinerComponent extends Component { // cachedMinedItem is not serialized. return { lastMiningTime: types.ufloat, - chainable: types.bool, itemChainBuffer: types.array(types.obj(gItemRegistry)), }; } diff --git a/src/js/game/components/replaceable_map_entity.js b/src/js/game/components/replaceable_map_entity.js deleted file mode 100644 index 78861caf..00000000 --- a/src/js/game/components/replaceable_map_entity.js +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from "../component"; - -/** - * Marks an entity as replaceable, so that when other buildings are placed above him it - * simply gets deleted - */ -export class ReplaceableMapEntityComponent extends Component { - static getId() { - return "ReplaceableMapEntity"; - } - - duplicateWithoutContents() { - return new ReplaceableMapEntityComponent(); - } -} diff --git a/src/js/game/components/static_map_entity.js b/src/js/game/components/static_map_entity.js index 2c80b43b..f43dca3c 100644 --- a/src/js/game/components/static_map_entity.js +++ b/src/js/game/components/static_map_entity.js @@ -6,6 +6,7 @@ import { enumDirection, Vector } from "../../core/vector"; import { types } from "../../savegame/serialization"; import { Component } from "../component"; import { getBuildingDataFromCode } from "../building_codes"; +import { MetaBuilding } from "../meta_building"; export class StaticMapEntityComponent extends Component { static getId() { @@ -15,7 +16,6 @@ export class StaticMapEntityComponent extends Component { static getSchema() { return { origin: types.tileVector, - tileSize: types.tileVector, rotation: types.float, originalRotation: types.float, @@ -56,6 +56,14 @@ export class StaticMapEntityComponent extends Component { return getBuildingDataFromCode(this.code).silhouetteColor; } + /** + * Returns the meta building + * @returns {MetaBuilding} + */ + getMetaBuilding() { + return getBuildingDataFromCode(this.code).metaInstance; + } + duplicateWithoutContents() { return new StaticMapEntityComponent({ origin: this.origin.copy(), diff --git a/src/js/game/components/storage.js b/src/js/game/components/storage.js index e7b40a77..acc68a51 100644 --- a/src/js/game/components/storage.js +++ b/src/js/game/components/storage.js @@ -12,10 +12,8 @@ export class StorageComponent extends Component { static getSchema() { return { - maximumStorage: types.uint, storedCount: types.uint, storedItem: types.nullable(types.obj(gItemRegistry)), - overlayOpacity: types.ufloat, }; } diff --git a/src/js/game/components/underground_belt.js b/src/js/game/components/underground_belt.js index 68420b20..b09927ce 100644 --- a/src/js/game/components/underground_belt.js +++ b/src/js/game/components/underground_belt.js @@ -26,9 +26,7 @@ export class UndergroundBeltComponent extends Component { static getSchema() { return { - mode: types.enum(enumUndergroundBeltMode), pendingItems: types.array(types.pair(types.obj(gItemRegistry), types.float)), - tier: types.uint, }; } diff --git a/src/js/game/components/unremovable.js b/src/js/game/components/unremovable.js deleted file mode 100644 index f3864cf8..00000000 --- a/src/js/game/components/unremovable.js +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from "../component"; - -export class UnremovableComponent extends Component { - static getId() { - return "Unremovable"; - } - - static getSchema() { - return {}; - } - - duplicateWithoutContents() { - return new UnremovableComponent(); - } -} diff --git a/src/js/game/components/wired_pins.js b/src/js/game/components/wired_pins.js index 17314639..227bff09 100644 --- a/src/js/game/components/wired_pins.js +++ b/src/js/game/components/wired_pins.js @@ -29,17 +29,6 @@ export class WiredPinsComponent extends Component { return "WiredPins"; } - static getSchema() { - return { - slots: types.array( - types.structured({ - pos: types.vector, - type: types.enum(enumPinSlotType), - }) - ), - }; - } - /** * * @param {object} param0 diff --git a/src/js/game/entity.js b/src/js/game/entity.js index 1086a677..943683fb 100644 --- a/src/js/game/entity.js +++ b/src/js/game/entity.js @@ -76,8 +76,7 @@ export class Entity extends BasicSerializableObject { static getSchema() { return { uid: types.uint, - components: types.keyValueMap(types.objData(gComponentRegistry)), - layer: types.enum(enumLayer), + components: types.keyValueMap(types.objData(gComponentRegistry), false), }; } diff --git a/src/js/game/entity_components.js b/src/js/game/entity_components.js index f670b227..6d04346d 100644 --- a/src/js/game/entity_components.js +++ b/src/js/game/entity_components.js @@ -1,19 +1,15 @@ /* typehints:start */ -import { StaticMapEntityComponent } from "./components/static_map_entity"; import { BeltComponent } from "./components/belt"; -import { ItemEjectorComponent } from "./components/item_ejector"; -import { ItemAcceptorComponent } from "./components/item_acceptor"; -import { MinerComponent } from "./components/miner"; -import { ItemProcessorComponent } from "./components/item_processor"; -import { ReplaceableMapEntityComponent } from "./components/replaceable_map_entity"; -import { UndergroundBeltComponent } from "./components/underground_belt"; -import { UnremovableComponent } from "./components/unremovable"; -import { HubComponent } from "./components/hub"; -import { StorageComponent } from "./components/storage"; -import { EnergyGeneratorComponent } from "./components/energy_generator"; -import { WiredPinsComponent } from "./components/wired_pins"; -import { EnergyConsumerComponent } from "./components/energy_consumer"; import { BeltUnderlaysComponent } from "./components/belt_underlays"; +import { HubComponent } from "./components/hub"; +import { ItemAcceptorComponent } from "./components/item_acceptor"; +import { ItemEjectorComponent } from "./components/item_ejector"; +import { ItemProcessorComponent } from "./components/item_processor"; +import { MinerComponent } from "./components/miner"; +import { StaticMapEntityComponent } from "./components/static_map_entity"; +import { StorageComponent } from "./components/storage"; +import { UndergroundBeltComponent } from "./components/underground_belt"; +import { WiredPinsComponent } from "./components/wired_pins"; /* typehints:end */ /** @@ -42,30 +38,18 @@ export class EntityComponentStorage { /** @type {ItemProcessorComponent} */ this.ItemProcessor; - /** @type {ReplaceableMapEntityComponent} */ - this.ReplaceableMapEntity; - /** @type {UndergroundBeltComponent} */ this.UndergroundBelt; - /** @type {UnremovableComponent} */ - this.Unremovable; - /** @type {HubComponent} */ this.Hub; /** @type {StorageComponent} */ this.Storage; - /** @type {EnergyGeneratorComponent} */ - this.EnergyGenerator; - /** @type {WiredPinsComponent} */ this.WiredPins; - /** @type {EnergyConsumerComponent} */ - this.EnergyConsumer; - /** @type {BeltUnderlaysComponent} */ this.BeltUnderlays; diff --git a/src/js/game/logic.js b/src/js/game/logic.js index c90803cf..0997d686 100644 --- a/src/js/game/logic.js +++ b/src/js/game/logic.js @@ -63,9 +63,12 @@ export class GameLogic { for (let y = rect.y; y < rect.y + rect.h; ++y) { // Check if there is any direct collision const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer); - if (otherEntity && !otherEntity.components.ReplaceableMapEntity) { - // This one is a direct blocker - return false; + if (otherEntity) { + const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding(); + if (!metaClass.getIsReplaceable()) { + // This one is a direct blocker + return false; + } } } } @@ -121,7 +124,7 @@ export class GameLogic { const contents = this.root.map.getLayerContentXY(x, y, entity.layer); if (contents) { assertAlways( - contents.components.ReplaceableMapEntity, + contents.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(), "Tried to replace non-repleaceable entity" ); if (!this.tryDeleteBuilding(contents)) { @@ -158,7 +161,8 @@ export class GameLogic { * @param {Entity} building */ canDeleteBuilding(building) { - return building.components.StaticMapEntity && !building.components.Unremovable; + const staticComp = building.components.StaticMapEntity; + return staticComp.getMetaBuilding().getIsRemovable(); } /** diff --git a/src/js/game/meta_building.js b/src/js/game/meta_building.js index 722dca13..08754cff 100644 --- a/src/js/game/meta_building.js +++ b/src/js/game/meta_building.js @@ -64,6 +64,13 @@ export class MetaBuilding { return []; } + /** + * Returns whether this building can get replaced + */ + getIsReplaceable() { + return false; + } + /** * Whether to flip the orientation after a building has been placed - useful * for tunnels. @@ -80,6 +87,14 @@ export class MetaBuilding { return false; } + /** + * Returns whether this building is removable + * @returns {boolean} + */ + getIsRemovable() { + return true; + } + /** * Returns the placement sound * @returns {string} diff --git a/src/js/game/systems/wired_pins.js b/src/js/game/systems/wired_pins.js index 022e49b9..64f9a7a0 100644 --- a/src/js/game/systems/wired_pins.js +++ b/src/js/game/systems/wired_pins.js @@ -52,7 +52,7 @@ export class WiredPinsSystem extends GameSystemWithFilter { continue; } - if (otherEntity.components.ReplaceableMapEntity) { + if (staticComp.getMetaBuilding().getIsReplaceable()) { // Don't mind here, even if there would be a collision we // could replace it continue; @@ -105,8 +105,10 @@ export class WiredPinsSystem extends GameSystemWithFilter { const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, enumLayer.wires); // If there's an entity, and it can't get removed -> That's a collision - if (collidingEntity && !collidingEntity.components.ReplaceableMapEntity) { - return true; + if (collidingEntity) { + if (!collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable()) { + return true; + } } } return false; @@ -130,7 +132,7 @@ export class WiredPinsSystem extends GameSystemWithFilter { const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, enumLayer.wires); if (collidingEntity) { assertAlways( - collidingEntity.components.ReplaceableMapEntity, + collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(), "Tried to replace non-repleaceable entity for pins" ); if (!this.root.logic.tryDeleteBuilding(collidingEntity)) { diff --git a/src/js/savegame/serialization_data_types.js b/src/js/savegame/serialization_data_types.js index 0f9b4542..c9ab570d 100644 --- a/src/js/savegame/serialization_data_types.js +++ b/src/js/savegame/serialization_data_types.js @@ -871,14 +871,17 @@ export class TypeArray extends BaseDataType { * @returns {string|void} String error code or null on success */ deserialize(value, targetObject, targetKey, root) { - const result = new Array(value.length); + let destination = targetObject[targetKey]; + if (!destination) { + targetObject[targetKey] = destination = new Array(value.length); + } + for (let i = 0; i < value.length; ++i) { - const errorStatus = this.innerType.deserializeWithVerify(value[i], result, i, root); + const errorStatus = this.innerType.deserializeWithVerify(value[i], destination, i, root); if (errorStatus) { return errorStatus; } } - targetObject[targetKey] = result; } getAsJsonSchemaUncached() { @@ -1226,15 +1229,18 @@ export class TypeStructuredObject extends BaseDataType { * @returns {string|void} String error code or null on success */ deserialize(value, targetObject, targetKey, root) { - let result = {}; + let target = targetObject[targetKey]; + if (!target) { + targetObject[targetKey] = target = {}; + } + for (const key in value) { const valueType = this.descriptor[key]; - const errorCode = valueType.deserializeWithVerify(value[key], result, key, root); + const errorCode = valueType.deserializeWithVerify(value[key], target, key, root); if (errorCode) { return errorCode; } } - targetObject[targetKey] = result; } getAsJsonSchemaUncached() { diff --git a/src/js/savegame/serializer_internal.js b/src/js/savegame/serializer_internal.js index 8df6f6e4..506d54aa 100644 --- a/src/js/savegame/serializer_internal.js +++ b/src/js/savegame/serializer_internal.js @@ -1,6 +1,10 @@ -import { gComponentRegistry } from "../core/global_registries"; +import { createLogger } from "../core/logging"; +import { Vector } from "../core/vector"; +import { getBuildingDataFromCode } from "../game/building_codes"; import { Entity } from "../game/entity"; -import { enumLayer, GameRoot } from "../game/root"; +import { GameRoot } from "../game/root"; + +const logger = createLogger("serializer_internal"); // Internal serializer methods export class SerializerInternal { @@ -37,19 +41,27 @@ export class SerializerInternal { * @param {Entity} payload */ deserializeEntity(root, payload) { - const entity = new Entity(root); - this.deserializeComponents(entity, payload.components); - entity.layer = payload.layer; + const staticData = payload.components.StaticMapEntity; + assert(staticData, "entity has no static data"); - if (!enumLayer[payload.layer]) { - assert(false, "Invalid layer: " + payload.layer); - } + const code = staticData.code; + const data = getBuildingDataFromCode(code); + + const metaBuilding = data.metaInstance; + + const entity = metaBuilding.createEntity({ + root, + origin: Vector.fromSerializedObject(staticData.origin), + rotation: staticData.rotation, + originalRotation: staticData.originalRotation, + rotationVariant: data.rotationVariant, + variant: data.variant, + }); + + this.deserializeComponents(entity, payload.components); root.entityMgr.registerEntity(entity, payload.uid); - - if (entity.components.StaticMapEntity) { - root.map.placeStaticEntity(entity); - } + root.map.placeStaticEntity(entity); } /////// COMPONENTS //// @@ -62,10 +74,12 @@ export class SerializerInternal { */ deserializeComponents(entity, data) { for (const componentId in data) { - const componentClass = gComponentRegistry.findById(componentId); - const componentHandle = new componentClass({}); - entity.addComponent(componentHandle); - const errorStatus = componentHandle.deserialize(data[componentId]); + if (!entity.components[componentId]) { + logger.warn("Entity no longer has component:", componentId); + continue; + } + + const errorStatus = entity.components[componentId].deserialize(data[componentId]); if (errorStatus) { return errorStatus; }