diff --git a/src/js/game/building_codes.js b/src/js/game/building_codes.js index 78240c31..5e2b717b 100644 --- a/src/js/game/building_codes.js +++ b/src/js/game/building_codes.js @@ -19,7 +19,7 @@ import { Vector } from "../core/vector"; /** * Stores a lookup table for all building variants (for better performance) - * @type {Object} + * @type {Object} */ export const gBuildingVariants = { // Set later @@ -27,13 +27,13 @@ export const gBuildingVariants = { /** * Mapping from 'metaBuildingId/variant/rotationVariant' to building code - * @type {Map} + * @type {Map} */ const variantsCache = new Map(); /** * Registers a new variant - * @param {number} code + * @param {number|string} code * @param {typeof MetaBuilding} meta * @param {string} variant * @param {number} rotationVariant @@ -54,9 +54,20 @@ export function registerBuildingVariant( }; } +/** + * Hashes the combination of buildng, variant and rotation variant + * @param {string} buildingId + * @param {string} variant + * @param {number} rotationVariant + * @returns + */ +function generateBuildingHash(buildingId, variant, rotationVariant) { + return buildingId + "/" + variant + "/" + rotationVariant; +} + /** * - * @param {number} code + * @param {string|number} code * @returns {BuildingVariantIdentifier} */ export function getBuildingDataFromCode(code) { @@ -70,8 +81,8 @@ export function getBuildingDataFromCode(code) { export function buildBuildingCodeCache() { for (const code in gBuildingVariants) { const data = gBuildingVariants[code]; - const hash = data.metaInstance.getId() + "/" + data.variant + "/" + data.rotationVariant; - variantsCache.set(hash, +code); + const hash = generateBuildingHash(data.metaInstance.getId(), data.variant, data.rotationVariant); + variantsCache.set(hash, isNaN(+code) ? code : +code); } } @@ -80,10 +91,10 @@ export function buildBuildingCodeCache() { * @param {MetaBuilding} metaBuilding * @param {string} variant * @param {number} rotationVariant - * @returns {number} + * @returns {number|string} */ export function getCodeFromBuildingData(metaBuilding, variant, rotationVariant) { - const hash = metaBuilding.getId() + "/" + variant + "/" + rotationVariant; + const hash = generateBuildingHash(metaBuilding.getId(), variant, rotationVariant); const result = variantsCache.get(hash); if (G_IS_DEV) { if (!result) { diff --git a/src/js/game/components/static_map_entity.js b/src/js/game/components/static_map_entity.js index c76a298e..a3d6a8ca 100644 --- a/src/js/game/components/static_map_entity.js +++ b/src/js/game/components/static_map_entity.js @@ -19,7 +19,7 @@ export class StaticMapEntityComponent extends Component { originalRotation: types.float, // See building_codes.js - code: types.uint, + code: types.uintOrString, }; } @@ -99,7 +99,7 @@ export class StaticMapEntityComponent extends Component { * @param {Vector=} param0.tileSize Size of the entity in tiles * @param {number=} param0.rotation Rotation in degrees. Must be multiple of 90 * @param {number=} param0.originalRotation Original Rotation in degrees. Must be multiple of 90 - * @param {number=} param0.code Building code + * @param {number|string=} param0.code Building code */ constructor({ origin = new Vector(), diff --git a/src/js/savegame/serialization.js b/src/js/savegame/serialization.js index 78642ceb..9a0ce3a5 100644 --- a/src/js/savegame/serialization.js +++ b/src/js/savegame/serialization.js @@ -22,6 +22,7 @@ import { TypeString, TypeStructuredObject, TypeVector, + TypePositiveIntegerOrString, } from "./serialization_data_types"; const logger = createLogger("serialization"); @@ -38,6 +39,7 @@ export const types = { vector: new TypeVector(), tileVector: new TypeVector(), bool: new TypeBoolean(), + uintOrString: new TypePositiveIntegerOrString(), /** * @param {BaseDataType} wrapped diff --git a/src/js/savegame/serialization_data_types.js b/src/js/savegame/serialization_data_types.js index 9d3b689f..df352e78 100644 --- a/src/js/savegame/serialization_data_types.js +++ b/src/js/savegame/serialization_data_types.js @@ -213,6 +213,53 @@ export class TypePositiveInteger extends BaseDataType { } } +export class TypePositiveIntegerOrString extends BaseDataType { + serialize(value) { + if (Number.isInteger(value)) { + assert(value >= 0, "type integer got negative value: " + value); + } else if (typeof value === "string") { + // all good + } else { + assertAlways(false, "Type integer|string got non integer or string for serialize: " + value); + } + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + oneOf: [{ type: "integer", minimum: 0 }, { type: "string" }], + }; + } + + verifySerializedValue(value) { + if (Number.isInteger(value)) { + if (value < 0) { + return "Negative value for positive integer"; + } + } else if (typeof value === "string") { + // all good + } else { + return "Not a valid number or string: " + value; + } + } + + getCacheKey() { + return "uint_str"; + } +} + export class TypeBoolean extends BaseDataType { serialize(value) { assert(value === true || value === false, "Type bool got non bool for serialize: " + value);