mirror of
https://github.com/motajs/template.git
synced 2026-10-17 03:10:17 +08:00
fix(07-13): clear existing dynamic tiles before loading
- add private clearDynamics() that snapshots the managed dynamic tiles and drops each via the deleteDynamic semantics (syncStaticEvent + removeTile + onDeleteDynamic), without awaiting the hook - call it as the first line of loadState so all three compression tiers and the missing-dynamicBlocks case start from a clean slate (#06-17-8) - add regressions: mapLayer hook/instance witness and the three-tier repeated-load non-accumulation case
This commit is contained in:
parent
c1df1e0116
commit
13234b762a
@ -9,6 +9,7 @@ import {
|
||||
FaceGroup,
|
||||
FaceManager,
|
||||
RoleFaceBinder,
|
||||
SaveCompression,
|
||||
TileStore,
|
||||
TileType
|
||||
} from '@user/data-common';
|
||||
@ -590,6 +591,30 @@ describe('MapLayer dynamic conversion', () => {
|
||||
expect(result.info.map(info => info.code)).toContain(130);
|
||||
await result.ret;
|
||||
});
|
||||
|
||||
// 验证 loadState 先清空既有动态块并触发删除钩子(#06-17-8 读档不累积)
|
||||
it('clears existing dynamic tiles before loading', () => {
|
||||
const { layer } = createFixture([0, 0, 0, 0]);
|
||||
const deleted: IDynamicTile[] = [];
|
||||
layer
|
||||
.addHook({
|
||||
onDeleteDynamic: async tile => {
|
||||
deleted.push(tile);
|
||||
}
|
||||
})
|
||||
.load();
|
||||
const first = layer.createDynamic(1, 0, 0);
|
||||
const second = layer.createDynamic(1, 1, 0);
|
||||
const saved = layer.saveState(SaveCompression.NoCompression);
|
||||
const extra = layer.createDynamic(1, 0, 1);
|
||||
|
||||
layer.loadState(saved, SaveCompression.NoCompression);
|
||||
|
||||
expect([...layer.iterateDynamicTiles()]).toHaveLength(2);
|
||||
expect([...layer.getDynamicTilesAt(0, 1)]).toHaveLength(0);
|
||||
expect(deleted).toEqual([first, second, extra]);
|
||||
expect([...layer.iterateDynamicTiles()]).not.toContain(first);
|
||||
});
|
||||
});
|
||||
|
||||
describe('MapLayer dirty state and doors', () => {
|
||||
|
||||
@ -848,6 +848,19 @@ export class MapLayer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空本图层全部既有动态图块,使读档后的动态块与存档点一致
|
||||
* 逐块复用删除语义,会触发 `onDeleteDynamic` 钩子,但读档为同步流程,不等待钩子完成
|
||||
*/
|
||||
private clearDynamics(): void {
|
||||
const tiles = [...this.iterateDynamicTiles()];
|
||||
for (const tile of tiles) {
|
||||
this.syncStaticEvent(tile, false);
|
||||
this.removeTile(tile);
|
||||
this.forEachHook(hook => hook.onDeleteDynamic?.(tile));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以无压缩方式读取当前图层
|
||||
* @param save 图层存档
|
||||
@ -920,6 +933,7 @@ export class MapLayer
|
||||
}
|
||||
|
||||
loadState(save: IMapLayerSave, compression: SaveCompression): void {
|
||||
this.clearDynamics();
|
||||
if (compression === SaveCompression.HighCompression) {
|
||||
this.loadHighCompression(save);
|
||||
} else if (compression === SaveCompression.LowCompression) {
|
||||
|
||||
@ -215,6 +215,24 @@ describe('MapLayer save and load round trips', () => {
|
||||
expect(lowResult.info.map(info => info.code)).toContain(124);
|
||||
expect(highResult.info.map(info => info.code)).toContain(124);
|
||||
});
|
||||
|
||||
// 验证动态块多于存档时读档后等于存档,且重复读档不累积(#06-17-8)
|
||||
it('does not accumulate dynamic tiles when loading fewer than present', () => {
|
||||
for (const compression of SAVE_COMPRESSIONS) {
|
||||
const { layer } = createMapFixture();
|
||||
setLayerReference(layer);
|
||||
layer.createDynamic(1, 0, 0);
|
||||
const saved = layer.saveState(compression);
|
||||
layer.createDynamic(1, 1, 0);
|
||||
layer.createDynamic(1, 1, 0);
|
||||
|
||||
layer.loadState(saved, compression);
|
||||
expect([...layer.iterateDynamicTiles()]).toHaveLength(1);
|
||||
|
||||
layer.loadState(saved, compression);
|
||||
expect([...layer.iterateDynamicTiles()]).toHaveLength(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('GameMap save and load round trips', () => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user