diff --git a/packages-user/data-common/src/replay/array.test.ts b/packages-user/data-common/src/replay/array.test.ts index 5f62e93..780e599 100644 --- a/packages-user/data-common/src/replay/array.test.ts +++ b/packages-user/data-common/src/replay/array.test.ts @@ -207,8 +207,8 @@ describe('ReplayArray single operations', () => { expect(array.get(1)).toEqual({ command: 3, params: [30], index: 1 }); }); - // 疑似 bug:delete 中间步骤后索引数组未按删除位置回退,导致后续步骤读到错误参数,详见 06-TEST-FINDINGS.md #06-04-3,修复后取消 skip - it.skip('deletes a middle step and shifts later param indexes', () => { + // 验证 delete 中间步骤后索引数组按删除位置回退,后续步骤仍读到正确参数 + it('deletes a middle step and shifts later param indexes', () => { const array = createArray(); array.add(1, [10]); array.add(2, [20]); @@ -567,8 +567,8 @@ describe('ReplayArray stream and buffer combination', () => { expect(stream.read()).toEqual({ command: 3, params: [30], index: 3 }); }); - // 疑似 bug:delete 中间步后索引数组未按删除位置回退,异质序列后续步骤读到错误参数,详见 06-TEST-FINDINGS.md #06-04-3,修复后取消 skip - it.skip('reads the new order after deleting a middle step from a heterogeneous route', () => { + // 验证异质序列删除中间步后索引按删除位置回退,读流按新次序精确读回 + it('reads the new order after deleting a middle step from a heterogeneous route', () => { const array = createHeterogeneousArray(); array.delete(1); diff --git a/packages-user/data-common/src/replay/array.ts b/packages-user/data-common/src/replay/array.ts index ce4947d..f604cb6 100644 --- a/packages-user/data-common/src/replay/array.ts +++ b/packages-user/data-common/src/replay/array.ts @@ -46,6 +46,13 @@ interface IDecodedCommand { readonly paramCount: number; } +interface IParamRange { + /** 命令参数在参数缓冲区中的起始字节 */ + readonly start: number; + /** 命令参数在参数缓冲区中的结束字节,不包含该字节 */ + readonly end: number; +} + export class ReplayArray implements IReplayArray { length: number = 0; commandWidth: ReplayCommandWidth = ReplayCommandWidth.Uint8; @@ -393,6 +400,20 @@ export class ReplayArray implements IReplayArray { }); } + /** + * 获取指定命令在参数缓冲区中的字节区间 + * @param index 命令索引 + */ + private getParamRange(index: number): IParamRange { + const start = this.indexArray[index]; + const end = + index + 1 < this.length + ? this.indexArray[index + 1] + : this.paramUsed; + + return { start, end }; + } + add(command: number, params: ReplayParamValue[]): void { if (this.disabled > 0) return; const normalized = this.normalizeParamList(params); @@ -447,8 +468,9 @@ export class ReplayArray implements IReplayArray { if (this.disabled > 0) return; const commandSize = this.getCommandSize(); const commandStart = index * commandSize; - const paramStart = this.indexArray[index]; - const nextParam = this.indexArray[index + 1]; + const range = this.getParamRange(index); + const paramStart = range.start; + const nextParam = range.end; const paramLength = nextParam - paramStart; // 直接进行位移 @@ -470,7 +492,7 @@ export class ReplayArray implements IReplayArray { } // 最后把后面的索引减少 paramLength - for (let i = paramStart; i < this.length; i++) { + for (let i = index; i < this.length; i++) { this.indexArray[i] -= paramLength; }