Store wires state on save

pull/609/head
tobspr 4 years ago
parent b478f4be63
commit 091401e52b

@ -1,82 +1,79 @@
import { GameRoot } from "./root";
import { globalConfig, IS_DEBUG } from "../core/config";
import { createLogger } from "../core/logging";
// How important it is that a savegame is created
/**
* @enum {number}
*/
export const enumSavePriority = {
regular: 2,
asap: 100,
};
const logger = createLogger("autosave");
// Internals
let MIN_INTERVAL_SECS = 60;
export class AutomaticSave {
constructor(root) {
/** @type {GameRoot} */
this.root = root;
// Store the current maximum save importance
this.saveImportance = enumSavePriority.regular;
this.lastSaveAttempt = -1000;
}
setSaveImportance(importance) {
this.saveImportance = Math.max(this.saveImportance, importance);
}
doSave() {
if (G_IS_DEV && globalConfig.debug.disableSavegameWrite) {
return;
}
this.root.gameState.doSave();
this.saveImportance = enumSavePriority.regular;
}
update() {
if (!this.root.gameInitialized) {
// Bad idea
return;
}
const saveInterval = this.root.app.settings.getAutosaveIntervalSeconds();
if (!saveInterval) {
// Disabled
return;
}
// Check when the last save was, but make sure that if it fails, we don't spam
const lastSaveTime = Math.max(this.lastSaveAttempt, this.root.savegame.getRealLastUpdate());
const secondsSinceLastSave = (Date.now() - lastSaveTime) / 1000.0;
let shouldSave = false;
switch (this.saveImportance) {
case enumSavePriority.asap:
// High always should save
shouldSave = true;
break;
case enumSavePriority.regular:
// Could determine if there is a good / bad point here
shouldSave = secondsSinceLastSave > saveInterval;
break;
default:
assert(false, "Unknown save prio: " + this.saveImportance);
break;
}
if (shouldSave) {
logger.log("Saving automatically");
this.lastSaveAttempt = Date.now();
this.doSave();
}
}
}
import { globalConfig } from "../core/config";
import { createLogger } from "../core/logging";
import { GameRoot } from "./root";
// How important it is that a savegame is created
/**
* @enum {number}
*/
export const enumSavePriority = {
regular: 2,
asap: 100,
};
const logger = createLogger("autosave");
export class AutomaticSave {
constructor(root) {
/** @type {GameRoot} */
this.root = root;
// Store the current maximum save importance
this.saveImportance = enumSavePriority.regular;
this.lastSaveAttempt = -1000;
}
setSaveImportance(importance) {
this.saveImportance = Math.max(this.saveImportance, importance);
}
doSave() {
if (G_IS_DEV && globalConfig.debug.disableSavegameWrite) {
return;
}
this.root.gameState.doSave();
this.saveImportance = enumSavePriority.regular;
}
update() {
if (!this.root.gameInitialized) {
// Bad idea
return;
}
const saveInterval = this.root.app.settings.getAutosaveIntervalSeconds();
if (!saveInterval) {
// Disabled
return;
}
// Check when the last save was, but make sure that if it fails, we don't spam
const lastSaveTime = Math.max(this.lastSaveAttempt, this.root.savegame.getRealLastUpdate());
const secondsSinceLastSave = (Date.now() - lastSaveTime) / 1000.0;
let shouldSave = false;
switch (this.saveImportance) {
case enumSavePriority.asap:
// High always should save
shouldSave = true;
break;
case enumSavePriority.regular:
// Could determine if there is a good / bad point here
shouldSave = secondsSinceLastSave > saveInterval;
break;
default:
assert(false, "Unknown save prio: " + this.saveImportance);
break;
}
if (shouldSave) {
logger.log("Saving automatically");
this.lastSaveAttempt = Date.now();
this.doSave();
}
}
}

@ -142,14 +142,14 @@ export class GameSystemManager {
// WIRES section
add("lever", LeverSystem);
// Wires must be before all gate, signal etc logic!
add("wire", WireSystem);
// IMPORTANT: We have 2 phases: In phase 1 we compute the output values of all gates,
// processors etc. In phase 2 we propagate it through the wires network
add("logicGate", LogicGateSystem);
add("beltReader", BeltReaderSystem);
// Wires must be after all gate, signal etc logic!
add("wire", WireSystem);
add("display", DisplaySystem);
add("itemProcessorOverlays", ItemProcessorOverlaysSystem);

@ -120,6 +120,7 @@ export class WireSystem extends GameSystemWithFilter {
this.root.signals.entityAdded.add(this.queueRecomputeIfWire, this);
this.needsRecompute = true;
this.isFirstRecompute = true;
this.staleArea = new StaleAreaDetector({
root: this.root,
@ -157,23 +158,28 @@ export class WireSystem extends GameSystemWithFilter {
this.networks = [];
// Clear all network references
const wireEntities = this.root.entityMgr.getAllWithComponent(WireComponent);
for (let i = 0; i < wireEntities.length; ++i) {
wireEntities[i].components.Wire.linkedNetwork = null;
}
const tunnelEntities = this.root.entityMgr.getAllWithComponent(WireTunnelComponent);
for (let i = 0; i < tunnelEntities.length; ++i) {
tunnelEntities[i].components.WireTunnel.linkedNetworks = [];
}
const pinEntities = this.root.entityMgr.getAllWithComponent(WiredPinsComponent);
for (let i = 0; i < pinEntities.length; ++i) {
const slots = pinEntities[i].components.WiredPins.slots;
for (let k = 0; k < slots.length; ++k) {
slots[k].linkedNetwork = null;
// Clear all network references, but not on the first update since thats the deserializing one
if (!this.isFirstRecompute) {
for (let i = 0; i < wireEntities.length; ++i) {
wireEntities[i].components.Wire.linkedNetwork = null;
}
for (let i = 0; i < tunnelEntities.length; ++i) {
tunnelEntities[i].components.WireTunnel.linkedNetworks = [];
}
for (let i = 0; i < pinEntities.length; ++i) {
const slots = pinEntities[i].components.WiredPins.slots;
for (let k = 0; k < slots.length; ++k) {
slots[k].linkedNetwork = null;
}
}
} else {
logger.log("Recomputing wires first time");
this.isFirstRecompute = false;
}
VERBOSE_WIRES && logger.log("Recomputing slots");

@ -1,91 +1,91 @@
import { createLogger } from "../core/logging";
import { Vector } from "../core/vector";
import { getBuildingDataFromCode } from "../game/building_codes";
import { Entity } from "../game/entity";
import { GameRoot } from "../game/root";
const logger = createLogger("serializer_internal");
// Internal serializer methods
export class SerializerInternal {
/**
* Serializes an array of entities
* @param {Array<Entity>} array
*/
serializeEntityArray(array) {
const serialized = [];
for (let i = 0; i < array.length; ++i) {
const entity = array[i];
if (!entity.queuedForDestroy && !entity.destroyed) {
serialized.push(entity.serialize());
}
}
return serialized;
}
/**
*
* @param {GameRoot} root
* @param {Array<any>} array
* @returns {string|void}
*/
deserializeEntityArray(root, array) {
for (let i = 0; i < array.length; ++i) {
this.deserializeEntity(root, array[i]);
}
}
/**
*
* @param {GameRoot} root
* @param {Entity} payload
*/
deserializeEntity(root, payload) {
const staticData = payload.components.StaticMapEntity;
assert(staticData, "entity has no static data");
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,
});
entity.uid = payload.uid;
this.deserializeComponents(root, entity, payload.components);
root.entityMgr.registerEntity(entity, payload.uid);
root.map.placeStaticEntity(entity);
}
/////// COMPONENTS ////
/**
* Deserializes components of an entity
* @param {GameRoot} root
* @param {Entity} entity
* @param {Object.<string, any>} data
* @returns {string|void}
*/
deserializeComponents(root, entity, data) {
for (const componentId in data) {
if (!entity.components[componentId]) {
logger.warn("Entity no longer has component:", componentId);
continue;
}
const errorStatus = entity.components[componentId].deserialize(data[componentId], root);
if (errorStatus) {
return errorStatus;
}
}
}
}
import { createLogger } from "../core/logging";
import { Vector } from "../core/vector";
import { getBuildingDataFromCode } from "../game/building_codes";
import { Entity } from "../game/entity";
import { GameRoot } from "../game/root";
const logger = createLogger("serializer_internal");
// Internal serializer methods
export class SerializerInternal {
/**
* Serializes an array of entities
* @param {Array<Entity>} array
*/
serializeEntityArray(array) {
const serialized = [];
for (let i = 0; i < array.length; ++i) {
const entity = array[i];
if (!entity.queuedForDestroy && !entity.destroyed) {
serialized.push(entity.serialize());
}
}
return serialized;
}
/**
*
* @param {GameRoot} root
* @param {Array<Entity>} array
* @returns {string|void}
*/
deserializeEntityArray(root, array) {
for (let i = 0; i < array.length; ++i) {
this.deserializeEntity(root, array[i]);
}
}
/**
*
* @param {GameRoot} root
* @param {Entity} payload
*/
deserializeEntity(root, payload) {
const staticData = payload.components.StaticMapEntity;
assert(staticData, "entity has no static data");
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,
});
entity.uid = payload.uid;
this.deserializeComponents(root, entity, payload.components);
root.entityMgr.registerEntity(entity, payload.uid);
root.map.placeStaticEntity(entity);
}
/////// COMPONENTS ////
/**
* Deserializes components of an entity
* @param {GameRoot} root
* @param {Entity} entity
* @param {Object.<string, any>} data
* @returns {string|void}
*/
deserializeComponents(root, entity, data) {
for (const componentId in data) {
if (!entity.components[componentId]) {
logger.warn("Entity no longer has component:", componentId);
continue;
}
const errorStatus = entity.components[componentId].deserialize(data[componentId], root);
if (errorStatus) {
return errorStatus;
}
}
}
}

Loading…
Cancel
Save