The loader keeps no migrations any more: an asset of the old type autotile (before #131) is an unknown type and dropped, and a tilemap layer with the cell map of the first version (before #134) loads empty; every project is saved in the current format, and the two tests now pin that the old shapes are not read (#137)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bffa508ee7
commit
c91c18f495
4 files changed
+13
-47
No files matched your search
@@ -28,7 +28,7 @@ import type {
|
||||
TilemapLayer,
|
||||
} from '../model/Asset';
|
||||
import { parseCellKey } from '../model/tilemap';
|
||||
import { decodeCells, encodeCells, isStoredCells } from './tilemapCells';
|
||||
import { decodeCells, encodeCells } from './tilemapCells';
|
||||
import { isAssetType } from '../model/AssetTypes';
|
||||
import { isFontFile } from '../model/font';
|
||||
import { isSoundFile } from '../model/sound';
|
||||
@@ -80,7 +80,7 @@ import { SHADER_KEY, shaderParamDefs } from '../properties/shaders';
|
||||
*/
|
||||
export function deserializeProject(raw: unknown, fallbackId = ''): Project {
|
||||
const r = asRecord(raw);
|
||||
const rawAssets = (Array.isArray(r.assets) ? r.assets : []).map(asRecord).map(migrateAsset);
|
||||
const rawAssets = (Array.isArray(r.assets) ? r.assets : []).map(asRecord);
|
||||
|
||||
// Pass 1: asset ids and their effective schemas, needed to coerce overrides in pass 2.
|
||||
const schemas = new Map<string, PropertySchema>();
|
||||
@@ -524,8 +524,7 @@ function normalizeLayers(raw: unknown): TilemapLayer[] {
|
||||
for (const item of Array.isArray(raw) ? raw : []) {
|
||||
const l = asRecord(item);
|
||||
if (typeof l.id !== 'string' || !l.id || layers.some((o) => o.id === l.id)) continue;
|
||||
// Projects saved before #134 hold the map itself; it is taken over as it is.
|
||||
const stored = isStoredCells(l) ? decodeCells(l) : asRecord(l.cells);
|
||||
const stored = decodeCells(l);
|
||||
const cells: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(stored))
|
||||
if (parseCellKey(key) && typeof value === 'string' && value !== '') cells[key] = value;
|
||||
@@ -550,17 +549,6 @@ function normalizeBag(raw: unknown, schema: PropertySchema, sparse: boolean): Pr
|
||||
return bag;
|
||||
}
|
||||
|
||||
/**
|
||||
* A tile was called an autotile before it could be a plain one (#131). Such an asset had no kind
|
||||
* but the autotile blocks, and one written without a kind meant a floor – which it has to stay now
|
||||
* that a missing kind means a plain tile.
|
||||
*/
|
||||
function migrateAsset(a: Record<string, unknown>): Record<string, unknown> {
|
||||
if (a.type !== 'autotile') return a;
|
||||
const props = asRecord(a.props);
|
||||
return { ...a, type: 'tile', props: { ...props, kind: props.kind ?? 'floor' } };
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
return value && typeof value === 'object' ? (value as Record<string, unknown>) : {};
|
||||
}
|
||||
|
||||
@@ -113,8 +113,3 @@ export function decodeCells(raw: {
|
||||
});
|
||||
return cells;
|
||||
}
|
||||
|
||||
/** Whether a stored layer is in this format rather than the map of the first version (#128). */
|
||||
export function isStoredCells(raw: Record<string, unknown>): boolean {
|
||||
return Array.isArray(raw.rows);
|
||||
}
|
||||
+4
-16
@@ -417,29 +417,17 @@ describe('tile in the document', () => {
|
||||
expect(tilePlayback(read)).toBe('loop');
|
||||
});
|
||||
|
||||
/**
|
||||
* #131 renamed the asset and made a plain tile the default. A project saved before that holds
|
||||
* `autotile` assets, and one of them without a stored kind meant a floor block: it has to open as
|
||||
* the same floor, not turn into a plain tile.
|
||||
*/
|
||||
it('reads an autotile of an older project as the tile it was', () => {
|
||||
// No migration any more (#137): `autotile`, the name before #131, is an unknown type like any other.
|
||||
it('drops an asset of the old type autotile', () => {
|
||||
const raw = {
|
||||
id: 'p',
|
||||
assets: [
|
||||
{ id: 's', type: 'scene', name: 'Main', props: {}, objects: [] },
|
||||
{ id: 'a', type: 'autotile', name: 'Old grass', props: {}, pictures: ['x'] },
|
||||
{ id: 'b', type: 'autotile', name: 'Old wall', props: { kind: 'wall', fps: 2 }, pictures: [] },
|
||||
{ id: 'a', type: 'autotile', name: 'Old grass', props: { kind: 'floor' }, pictures: ['x'] },
|
||||
{ id: 'c', type: 'tile', name: 'New', props: {}, pictures: [] },
|
||||
],
|
||||
};
|
||||
const project = deserializeProject(raw);
|
||||
const byId = (id: string) => project.assets.find((a): a is TileAsset => a.id === id && a.type === 'tile');
|
||||
expect(byId('a')?.pictures).toEqual(['x']);
|
||||
expect(tileKind(byId('a')!)).toBe('floor');
|
||||
expect(tileKind(byId('b')!)).toBe('wall');
|
||||
expect(byId('b')?.props.fps).toBe(2);
|
||||
expect(tileKind(byId('c')!)).toBe('none');
|
||||
expect(project.assets.some((a) => (a.type as string) === 'autotile')).toBe(false);
|
||||
expect(deserializeProject(raw).assets.map((a) => a.id)).toEqual(['s', 'c']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -108,19 +108,14 @@ describe('the cells of a tilemap in the file', () => {
|
||||
expect((findAsset(project, id) as TilemapAsset).layers[0]!.cells).toEqual(cells);
|
||||
});
|
||||
|
||||
it('take a project saved before #134 over as it is, and write it in the new form', () => {
|
||||
// No migration any more (#137): the map of the first version (#128) is not read.
|
||||
it('read a layer holding the map itself as empty', () => {
|
||||
const { project, id } = projectWith({});
|
||||
const raw = serializeProject(project) as { assets: Record<string, unknown>[] };
|
||||
const old = raw.assets.find((a) => a.id === id)!;
|
||||
old.layers = [
|
||||
{ id: 'L1', name: 'Ground', cells: { '1,2': 'grass', '2,2': 'grass', nonsense: 'x', '3,3': '' } },
|
||||
];
|
||||
const loaded = deserializeProject(raw);
|
||||
expect((findAsset(loaded, id) as TilemapAsset).layers[0]!.cells).toEqual({
|
||||
'1,2': 'grass',
|
||||
'2,2': 'grass',
|
||||
});
|
||||
expect(storedLayer(serializeProject(loaded), id)).toMatchObject({ tiles: ['grass'], rows: ['1*2'] });
|
||||
raw.assets.find((a) => a.id === id)!.layers = [{ id: 'L1', name: 'Ground', cells: { '1,2': 'grass' } }];
|
||||
const layer = (findAsset(deserializeProject(raw), id) as TilemapAsset).layers[0]!;
|
||||
expect(layer).toMatchObject({ id: 'L1', name: 'Ground' });
|
||||
expect(layer.cells).toEqual({});
|
||||
});
|
||||
|
||||
it('shrink a full map of 100 × 100 with two layers to a small part of the old size', () => {
|
||||
|
||||
Reference in new issue
Block a user