diff --git a/packages/core/src/ECS/Utils/BigIntCompatibility.ts b/packages/core/src/ECS/Utils/BigIntCompatibility.ts index ceef6818..441d5c31 100644 --- a/packages/core/src/ECS/Utils/BigIntCompatibility.ts +++ b/packages/core/src/ECS/Utils/BigIntCompatibility.ts @@ -1,15 +1,16 @@ /** - * 64位掩码兼容层 - */ - -/** - * 64位掩码数据结构,使用两个32位整数表示 + * 位掩码数据结构 + * 基础模式(64位):使用 lo + hi 存储 64 位,segments 为空 + * 扩展模式(128+位):lo + hi 作为第一段,segments 存储额外的 64 位段 + * segments[0] 对应 bit 64-127,segments[1] 对应 bit 128-191,以此类推 */ export interface BitMask64Data { - /** 低32位 */ + /** 低32位(bit 0-31) */ lo: number; - /** 高32位 */ + /** 高32位(bit 32-63) */ hi: number; + /** 扩展段数组,每个元素是一个 64 位段,用于超过 64 位的场景 */ + segments?: BitMask64Data[]; } export class BitMask64Utils { @@ -55,12 +56,44 @@ export class BitMask64Utils { /** * 检查掩码是否包含所有指定的位 + * 支持扩展模式,自动处理超过 64 位的掩码 * @param mask 要检查的掩码 * @param bits 指定的位模式 * @returns 如果掩码包含bits中的所有位则返回true */ public static hasAll(mask: BitMask64Data, bits: BitMask64Data): boolean { - return (mask.lo & bits.lo) === bits.lo && (mask.hi & bits.hi) === bits.hi; + // 检查第一个 64 位段 + if ((mask.lo & bits.lo) !== bits.lo || (mask.hi & bits.hi) !== bits.hi) { + return false; + } + + // 如果 bits 没有扩展段,检查完成 + if (!bits.segments || bits.segments.length === 0) { + return true; + } + + // 如果 bits 有扩展段但 mask 没有,返回 false + if (!mask.segments || mask.segments.length === 0) { + // 检查 bits 的扩展段是否全为 0 + return bits.segments.every(seg => BitMask64Utils.isZero(seg)); + } + + // 递归检查每个扩展段 + const minSegments = Math.min(mask.segments.length, bits.segments.length); + for (let i = 0; i < minSegments; i++) { + if (!BitMask64Utils.hasAll(mask.segments[i], bits.segments[i])) { + return false; + } + } + + // 如果 bits 有更多段,检查这些段是否为空 + for (let i = minSegments; i < bits.segments.length; i++) { + if (!BitMask64Utils.isZero(bits.segments[i])) { + return false; + } + } + + return true; } /** @@ -234,7 +267,98 @@ export class BitMask64Utils { hi &= hi - 1; count++; } - + return count; } + + /** + * 设置扩展位(支持超过 64 位的索引) + * @param mask 要修改的掩码(原地修改) + * @param bitIndex 位索引(可以超过 63) + */ + public static setBitExtended(mask: BitMask64Data, bitIndex: number): void { + if (bitIndex < 0) { + throw new Error('Bit index cannot be negative'); + } + + if (bitIndex < 64) { + BitMask64Utils.setBit(mask, bitIndex); + return; + } + + // 计算段索引和段内位索引 + const segmentIndex = Math.floor(bitIndex / 64) - 1; + const localBitIndex = bitIndex % 64; + + // 确保 segments 数组存在 + if (!mask.segments) { + mask.segments = []; + } + + // 扩展 segments 数组 + while (mask.segments.length <= segmentIndex) { + mask.segments.push(BitMask64Utils.clone(BitMask64Utils.ZERO)); + } + + // 设置对应段的位 + BitMask64Utils.setBit(mask.segments[segmentIndex], localBitIndex); + } + + /** + * 获取扩展位(支持超过 64 位的索引) + * @param mask 要检查的掩码 + * @param bitIndex 位索引(可以超过 63) + * @returns 如果位被设置则返回 true + */ + public static getBitExtended(mask: BitMask64Data, bitIndex: number): boolean { + if (bitIndex < 0) { + return false; + } + + if (bitIndex < 64) { + const testMask = BitMask64Utils.create(bitIndex); + return BitMask64Utils.hasAny(mask, testMask); + } + + if (!mask.segments) { + return false; + } + + const segmentIndex = Math.floor(bitIndex / 64) - 1; + if (segmentIndex >= mask.segments.length) { + return false; + } + + const localBitIndex = bitIndex % 64; + const testMask = BitMask64Utils.create(localBitIndex); + return BitMask64Utils.hasAny(mask.segments[segmentIndex], testMask); + } + + /** + * 清除扩展位(支持超过 64 位的索引) + * @param mask 要修改的掩码(原地修改) + * @param bitIndex 位索引(可以超过 63) + */ + public static clearBitExtended(mask: BitMask64Data, bitIndex: number): void { + if (bitIndex < 0) { + return; + } + + if (bitIndex < 64) { + BitMask64Utils.clearBit(mask, bitIndex); + return; + } + + if (!mask.segments) { + return; + } + + const segmentIndex = Math.floor(bitIndex / 64) - 1; + if (segmentIndex >= mask.segments.length) { + return; + } + + const localBitIndex = bitIndex % 64; + BitMask64Utils.clearBit(mask.segments[segmentIndex], localBitIndex); + } } \ No newline at end of file diff --git a/packages/core/src/ECS/Utils/Bits.ts b/packages/core/src/ECS/Utils/Bits.ts index a3a48d37..b725b740 100644 --- a/packages/core/src/ECS/Utils/Bits.ts +++ b/packages/core/src/ECS/Utils/Bits.ts @@ -1,11 +1,12 @@ import { BitMask64Data, BitMask64Utils } from './BigIntCompatibility'; /** - * 64位位集合类,用于高效的位操作 - * 支持最多64个位的设置、清除、查询和逻辑运算 + * 位集合类,用于高效的位操作 + * 自动扩展支持:默认 64 位,超过时自动扩展到 128/256 位 + * 扩展模式性能略有下降,但仍然比数组遍历快得多 */ export class Bits { - /** 存储位数据的64位掩码 */ + /** 存储位数据的掩码,支持扩展 */ private _value: BitMask64Data; /** @@ -27,36 +28,29 @@ export class Bits { /** * 设置指定位为1 - * @param index 位索引,范围 [0, 63] - * @throws 当位索引为负数或超过64位限制时抛出错误 + * 自动扩展:当索引超过 64 时,自动扩展到 128/256 位 + * @param index 位索引(0-based) + * @throws 当位索引为负数时抛出错误 */ public set(index: number): void { if (index < 0) { throw new Error('Bit index cannot be negative'); } - - if (index >= 64) { - throw new Error('Bit index exceeds 64-bit limit. ECS framework supports max 64 component types.'); - } - - BitMask64Utils.setBit(this._value, index); + + BitMask64Utils.setBitExtended(this._value, index); } /** * 清除指定位为0 - * @param index 位索引,范围 [0, 63] + * @param index 位索引 * @throws 当位索引为负数时抛出错误 */ public clear(index: number): void { if (index < 0) { throw new Error('Bit index cannot be negative'); } - - if (index >= 64) { - return; - } - - BitMask64Utils.clearBit(this._value, index); + + BitMask64Utils.clearBitExtended(this._value, index); } /** @@ -65,12 +59,7 @@ export class Bits { * @returns 如果位被设置为1则返回true,否则返回false */ public get(index: number): boolean { - if (index < 0 || index >= 64) { - return false; - } - - const mask = BitMask64Utils.create(index); - return BitMask64Utils.hasAny(this._value, mask); + return BitMask64Utils.getBitExtended(this._value, index); } /** diff --git a/packages/core/src/ECS/Utils/ComponentTypeManager.ts b/packages/core/src/ECS/Utils/ComponentTypeManager.ts index bc80cf63..3214e53b 100644 --- a/packages/core/src/ECS/Utils/ComponentTypeManager.ts +++ b/packages/core/src/ECS/Utils/ComponentTypeManager.ts @@ -5,6 +5,7 @@ import { ComponentType } from "../../Types"; /** * 组件类型管理器 * 负责管理组件类型的注册和ID分配 + * 支持无限数量的组件类型(通过自动扩展 BitMask) */ export class ComponentTypeManager { private static _instance: ComponentTypeManager; @@ -31,13 +32,13 @@ export class ComponentTypeManager { */ public getTypeId(componentType: ComponentType): number { let typeId = this._componentTypes.get(componentType); - + if (typeId === undefined) { typeId = this._nextTypeId++; this._componentTypes.set(componentType, typeId); this._typeNames.set(typeId, getComponentTypeName(componentType)); } - + return typeId; } diff --git a/packages/core/tests/ECS/Utils/Bits.test.ts b/packages/core/tests/ECS/Utils/Bits.test.ts index 09bece7a..4f3d9564 100644 --- a/packages/core/tests/ECS/Utils/Bits.test.ts +++ b/packages/core/tests/ECS/Utils/Bits.test.ts @@ -438,9 +438,15 @@ describe('Bits - 高性能位操作类测试', () => { expect(bits.cardinality()).toBe(1); }); - it('超过64位索引应该抛出错误', () => { - expect(() => bits.set(64)).toThrow('Bit index exceeds 64-bit limit'); - expect(() => bits.set(100)).toThrow('Bit index exceeds 64-bit limit'); + it('超过64位索引应该自动扩展', () => { + // 现在支持自动扩展到 128/256 位 + expect(() => bits.set(64)).not.toThrow(); + expect(() => bits.set(100)).not.toThrow(); + + // 验证扩展后的位可以正确读取 + expect(bits.get(64)).toBe(true); + expect(bits.get(100)).toBe(true); + expect(bits.get(65)).toBe(false); }); it('64位范围内的位运算应该正确', () => {