mirror of
https://github.com/motajs/template.git
synced 2026-09-13 10:18:50 +08:00
feat(03-06): migrate TileStore to events map
- Store raw tile event mappings for getEvent lookups - Cover missing, replacement, index, and immutability behavior
This commit is contained in:
parent
846513b2a6
commit
89e53a6500
88
packages-user/data-common/src/store/tileStore.test.ts
Normal file
88
packages-user/data-common/src/store/tileStore.test.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { TileStore } from './tileStore';
|
||||
import { ITileRawData, TileType } from './types';
|
||||
|
||||
function createTile(
|
||||
num: number,
|
||||
id: string,
|
||||
events: Record<number, string> = {}
|
||||
): ITileRawData {
|
||||
return {
|
||||
num,
|
||||
id,
|
||||
events,
|
||||
type: TileType.Terrain,
|
||||
pass: { onlyEvents: false, inPass: 0b1111, outPass: 0b1111 },
|
||||
eventPass: true
|
||||
};
|
||||
}
|
||||
|
||||
describe('TileStore events-map contract', () => {
|
||||
// 验证图块注册时会保存并按优先级返回默认事件映射
|
||||
it('returns the default events map for a registered tile', () => {
|
||||
const store = new TileStore();
|
||||
store.addTile(createTile(1, 'floor', { 20: 'late', 10: 'early' }));
|
||||
|
||||
expect(store.getEvent(1)).toEqual(
|
||||
new Map([
|
||||
[20, 'late'],
|
||||
[10, 'early']
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
// 验证查询不存在的图块时返回安全的空事件映射
|
||||
it('returns an empty map for a missing tile', () => {
|
||||
const store = new TileStore();
|
||||
|
||||
expect(store.getEvent(99)).toEqual(new Map());
|
||||
expect(store.getEvent(99).size).toBe(0);
|
||||
});
|
||||
|
||||
// 验证图块 id、数字索引和完整数据查询保持一致
|
||||
it('keeps id and number indexes aligned with tile data', () => {
|
||||
const store = new TileStore();
|
||||
const tile = createTile(7, 'blue-wall', { 1: 'touch' });
|
||||
store.addTile(tile);
|
||||
|
||||
expect(store.getData(7)).toBe(tile);
|
||||
expect(store.idToNumber('blue-wall')).toBe(7);
|
||||
expect(store.numberToId(7)).toBe('blue-wall');
|
||||
expect(store.num('blue-wall')).toBe(7);
|
||||
expect(store.num(7)).toBe(7);
|
||||
expect(store.id(7)).toBe('blue-wall');
|
||||
expect(store.id('blue-wall')).toBe('blue-wall');
|
||||
});
|
||||
|
||||
// 验证按数字或 id 重复注册时旧图块及其事件映射都会被替换
|
||||
it('replaces tiles and event maps on number or id conflicts', () => {
|
||||
const store = new TileStore();
|
||||
store.addTile(createTile(1, 'first', { 1: 'first-event' }));
|
||||
store.addTile(createTile(1, 'second', { 2: 'second-event' }));
|
||||
|
||||
expect(store.getData(1)?.id).toBe('second');
|
||||
expect(store.idToNumber('first')).toBeUndefined();
|
||||
expect(store.getEvent(1)).toEqual(new Map([[2, 'second-event']]));
|
||||
|
||||
store.addTile(createTile(2, 'second', { 3: 'moved-event' }));
|
||||
|
||||
expect(store.getData(1)).toBeNull();
|
||||
expect(store.numberToId(1)).toBeUndefined();
|
||||
expect(store.getEvent(1)).toEqual(new Map());
|
||||
expect(store.getData(2)?.id).toBe('second');
|
||||
expect(store.getEvent(2)).toEqual(new Map([[3, 'moved-event']]));
|
||||
});
|
||||
|
||||
// 验证调用方修改返回映射不会写入 TileStore 的内部默认事件
|
||||
it('does not expose mutable internal event maps', () => {
|
||||
const store = new TileStore();
|
||||
store.addTile(createTile(3, 'safe-floor', { 4: 'original' }));
|
||||
|
||||
const events = store.getEvent(3);
|
||||
const mutableEvents = events as Map<number, string>;
|
||||
mutableEvents.set(5, 'external');
|
||||
|
||||
expect(store.getEvent(3)).toEqual(new Map([[4, 'original']]));
|
||||
expect(store.getEvent(3)).not.toBe(events);
|
||||
});
|
||||
});
|
||||
@ -17,6 +17,9 @@ export class TileStore<TLegacy = unknown> implements ITileStore<TLegacy> {
|
||||
/** 由图块数字反查图块 id 的映射表 */
|
||||
private readonly numMap: Map<number, string> = new Map();
|
||||
|
||||
/** 由图块数字保存的默认事件映射 */
|
||||
private readonly eventMap: Map<number, Map<number, string>> = new Map();
|
||||
|
||||
/** 当前挂载的旧样板图块转换器 */
|
||||
private legacyConverter: ITileLegacyConverter<TLegacy> | null = null;
|
||||
|
||||
@ -24,8 +27,9 @@ export class TileStore<TLegacy = unknown> implements ITileStore<TLegacy> {
|
||||
return this.dataMap.get(num) ?? null;
|
||||
}
|
||||
|
||||
getEvent(num: number): number {
|
||||
return this.dataMap.get(num)?.trigger ?? -1;
|
||||
getEvent(num: number): ReadonlyMap<number, string> {
|
||||
const events = this.eventMap.get(num);
|
||||
return events ? new Map(events) : new Map();
|
||||
}
|
||||
|
||||
getType(num: number): TileType {
|
||||
@ -50,6 +54,7 @@ export class TileStore<TLegacy = unknown> implements ITileStore<TLegacy> {
|
||||
}
|
||||
}
|
||||
this.dataMap.set(data.num, data);
|
||||
this.eventMap.set(data.num, this.createEventMap(data.events));
|
||||
this.idMap.set(data.id, data.num);
|
||||
this.numMap.set(data.num, data.id);
|
||||
}
|
||||
@ -96,7 +101,17 @@ export class TileStore<TLegacy = unknown> implements ITileStore<TLegacy> {
|
||||
/** 删除一组旧的图块定义及其双向索引 */
|
||||
private deleteBy(num: number, id: string): void {
|
||||
this.dataMap.delete(num);
|
||||
this.eventMap.delete(num);
|
||||
this.idMap.delete(id);
|
||||
this.numMap.delete(num);
|
||||
}
|
||||
|
||||
/** 将原始事件对象转换为运行时使用的数字键事件映射 */
|
||||
private createEventMap(events: Record<number, string>): Map<number, string> {
|
||||
const eventMap = new Map<number, string>();
|
||||
for (const [priority, event] of Object.entries(events)) {
|
||||
eventMap.set(Number(priority), event);
|
||||
}
|
||||
return eventMap;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user