mysticsymbolic.github.io/lib/pages/creature-page/serialization.ts

123 wiersze
3.4 KiB
TypeScript
Czysty Zwykły widok Historia

import * as avro from "avro-js";
import { CreatureDesign } from "./core";
import {
AvroAttachedCreatureSymbol,
AvroCreatureDesign,
AvroCreatureSymbol,
AvroNestedCreatureSymbol,
} from "./creature-design.avsc";
import { fromBase64, toBase64 } from "../../base64";
import CreatureAvsc from "./creature-design.avsc.json";
import { Packer, SvgCompositionContextPacker } from "../../serialization";
import {
AttachedCreatureSymbol,
CreatureSymbol,
NestedCreatureSymbol,
} from "../../creature-symbol";
import { SvgVocabulary } from "../../svg-vocabulary";
import { ATTACHMENT_POINT_TYPES } from "../../specs";
const LATEST_VERSION = "v2";
const avroCreatureDesign = avro.parse<AvroCreatureDesign>(CreatureAvsc);
const ATTACHMENT_POINT_MAPPING = new Map(
ATTACHMENT_POINT_TYPES.map((name, i) => {
return [name, i];
})
);
const NestedCreatureSymbolPacker: Packer<
NestedCreatureSymbol,
AvroNestedCreatureSymbol
> = {
pack: (value) => {
return {
base: CreatureSymbolPacker.pack(value),
indices: Buffer.from(value.indices),
};
},
unpack: (value) => {
return {
...CreatureSymbolPacker.unpack(value.base),
indices: Array.from(value.indices),
};
},
};
const AttachedCreatureSymbolPacker: Packer<
AttachedCreatureSymbol,
AvroAttachedCreatureSymbol
> = {
pack: (value) => {
const attachTo = ATTACHMENT_POINT_MAPPING.get(value.attachTo);
if (attachTo === undefined) {
throw new Error(`Invalid attachment type "${value.attachTo}"`);
}
return {
base: CreatureSymbolPacker.pack(value),
attachTo,
indices: Buffer.from(value.indices),
};
},
unpack: (value) => {
const attachTo = ATTACHMENT_POINT_TYPES[value.attachTo];
if (attachTo === undefined) {
throw new Error(`Invalid attachment type "${value.attachTo}"`);
}
return {
...CreatureSymbolPacker.unpack(value.base),
attachTo,
indices: Array.from(value.indices),
};
},
};
const CreatureSymbolPacker: Packer<CreatureSymbol, AvroCreatureSymbol> = {
pack: (value) => {
return {
...value,
symbol: value.data.name,
attachments: value.attachments.map(AttachedCreatureSymbolPacker.pack),
nests: value.nests.map(NestedCreatureSymbolPacker.pack),
};
},
unpack: (value) => {
return {
...value,
data: SvgVocabulary.get(value.symbol),
attachments: value.attachments.map(AttachedCreatureSymbolPacker.unpack),
nests: value.nests.map(NestedCreatureSymbolPacker.unpack),
};
},
};
const DesignConfigPacker: Packer<CreatureDesign, AvroCreatureDesign> = {
pack: (value) => {
return {
creature: CreatureSymbolPacker.pack(value.creature),
compCtx: SvgCompositionContextPacker.pack(value.compCtx),
};
},
unpack: (value) => {
return {
creature: CreatureSymbolPacker.unpack(value.creature),
compCtx: SvgCompositionContextPacker.unpack(value.compCtx),
};
},
};
export function serializeCreatureDesign(value: CreatureDesign): string {
const buf = avroCreatureDesign.toBuffer(DesignConfigPacker.pack(value));
return `${LATEST_VERSION}.${toBase64(buf)}`;
}
export function deserializeCreatureDesign(value: string): CreatureDesign {
const [version, serialized] = value.split(".", 2);
if (version === "v1") {
throw new Error(`Sorry, we no longer support loading v1 creatures!`);
}
const buf = fromBase64(serialized);
return DesignConfigPacker.unpack(avroCreatureDesign.fromBuffer(buf));
}