diff --git a/packages/core/src/ECS/Core/ComponentStorage/ComponentRegistry.ts b/packages/core/src/ECS/Core/ComponentStorage/ComponentRegistry.ts index 5352d459..c0635ec2 100644 --- a/packages/core/src/ECS/Core/ComponentStorage/ComponentRegistry.ts +++ b/packages/core/src/ECS/Core/ComponentStorage/ComponentRegistry.ts @@ -6,7 +6,7 @@ import { getComponentTypeName } from '../../Decorators'; /** * 组件类型定义 */ -export type ComponentType = new (...args: unknown[]) => T; +export type ComponentType = new (...args: any[]) => T; /** * 组件注册表 diff --git a/packages/core/src/ECS/Utils/BigIntCompatibility.ts b/packages/core/src/ECS/Utils/BigIntCompatibility.ts index a4a04a0b..ceef6818 100644 --- a/packages/core/src/ECS/Utils/BigIntCompatibility.ts +++ b/packages/core/src/ECS/Utils/BigIntCompatibility.ts @@ -3,77 +3,24 @@ */ /** - * 位掩码接口 - */ -export interface IBigIntLike { - valueOf(): number; - toString(radix?: number): string; - and(other: IBigIntLike): IBigIntLike; - or(other: IBigIntLike): IBigIntLike; - xor(other: IBigIntLike): IBigIntLike; - not(maxBits?: number): IBigIntLike; - shiftLeft(bits: number): IBigIntLike; - shiftRight(bits: number): IBigIntLike; - equals(other: IBigIntLike): boolean; - isZero(): boolean; - clone(): IBigIntLike; -} - - - -/** - * 掩码工厂类 - */ -export class BigIntFactory { - private static _cachedZero: IBigIntLike | null = null; - private static _cachedOne: IBigIntLike | null = null; - - public static create(value: number | string = 0): IBigIntLike { - return new BitMask64(value); - } - - public static zero(): IBigIntLike { - if (!this._cachedZero) { - this._cachedZero = new BitMask64(0); - } - return this._cachedZero.clone(); - } - - public static one(): IBigIntLike { - if (!this._cachedOne) { - this._cachedOne = new BitMask64(1); - } - return this._cachedOne.clone(); - } - - public static fromBinaryString(binary: string): IBigIntLike { - return new BitMask64('0b' + binary); - } - - public static fromHexString(hex: string): IBigIntLike { - return new BitMask64(hex); - } - -} - - -/** - * 64位掩码结构 + * 64位掩码数据结构,使用两个32位整数表示 */ export interface BitMask64Data { + /** 低32位 */ lo: number; + /** 高32位 */ hi: number; } -/** - * 64位掩码工具类 - */ export class BitMask64Utils { - /** 零掩码常量 */ + /** 零掩码常量,所有位都为0 */ public static readonly ZERO: BitMask64Data = { lo: 0, hi: 0 }; /** - * 创建掩码 + * 根据位索引创建64位掩码 + * @param bitIndex 位索引,范围 [0, 63] + * @returns 包含指定位设置为1的掩码 + * @throws 当位索引超出范围时抛出错误 */ public static create(bitIndex: number): BitMask64Data { if (bitIndex < 0 || bitIndex >= 64) { @@ -88,49 +35,68 @@ export class BitMask64Utils { } /** - * 从数值创建掩码 + * 从32位数字创建64位掩码 + * @param value 32位数字值 + * @returns 低32位为输入值、高32位为0的掩码 */ public static fromNumber(value: number): BitMask64Data { return { lo: value >>> 0, hi: 0 }; } /** - * 检查是否有任意位 + * 检查掩码是否包含任意指定的位 + * @param mask 要检查的掩码 + * @param bits 指定的位模式 + * @returns 如果掩码包含bits中的任意位则返回true */ public static hasAny(mask: BitMask64Data, bits: BitMask64Data): boolean { return (mask.lo & bits.lo) !== 0 || (mask.hi & bits.hi) !== 0; } /** - * 检查是否有所有位 + * 检查掩码是否包含所有指定的位 + * @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; } /** - * 检查是否没有任何位 + * 检查掩码是否不包含任何指定的位 + * @param mask 要检查的掩码 + * @param bits 指定的位模式 + * @returns 如果掩码不包含bits中的任何位则返回true */ public static hasNone(mask: BitMask64Data, bits: BitMask64Data): boolean { return (mask.lo & bits.lo) === 0 && (mask.hi & bits.hi) === 0; } /** - * 检查是否为零 + * 检查掩码是否为零 + * @param mask 要检查的掩码 + * @returns 如果掩码所有位都为0则返回true */ public static isZero(mask: BitMask64Data): boolean { return mask.lo === 0 && mask.hi === 0; } /** - * 检查是否相等 + * 检查两个掩码是否相等 + * @param a 第一个掩码 + * @param b 第二个掩码 + * @returns 如果两个掩码完全相等则返回true */ public static equals(a: BitMask64Data, b: BitMask64Data): boolean { return a.lo === b.lo && a.hi === b.hi; } /** - * 原地设置位(修改原掩码) + * 设置掩码中指定位为1 + * @param mask 要修改的掩码(原地修改) + * @param bitIndex 位索引,范围 [0, 63] + * @throws 当位索引超出范围时抛出错误 */ public static setBit(mask: BitMask64Data, bitIndex: number): void { if (bitIndex < 0 || bitIndex >= 64) { @@ -145,7 +111,10 @@ export class BitMask64Utils { } /** - * 原地清除位(修改原掩码) + * 清除掩码中指定位为0 + * @param mask 要修改的掩码(原地修改) + * @param bitIndex 位索引,范围 [0, 63] + * @throws 当位索引超出范围时抛出错误 */ public static clearBit(mask: BitMask64Data, bitIndex: number): void { if (bitIndex < 0 || bitIndex >= 64) { @@ -160,7 +129,9 @@ export class BitMask64Utils { } /** - * 原地或运算(修改原掩码) + * 对目标掩码执行按位或操作 + * @param target 目标掩码(原地修改) + * @param other 用于按位或的掩码 */ public static orInPlace(target: BitMask64Data, other: BitMask64Data): void { target.lo |= other.lo; @@ -168,7 +139,9 @@ export class BitMask64Utils { } /** - * 原地与运算(修改原掩码) + * 对目标掩码执行按位与操作 + * @param target 目标掩码(原地修改) + * @param other 用于按位与的掩码 */ public static andInPlace(target: BitMask64Data, other: BitMask64Data): void { target.lo &= other.lo; @@ -176,7 +149,9 @@ export class BitMask64Utils { } /** - * 原地异或运算(修改原掩码) + * 对目标掩码执行按位异或操作 + * @param target 目标掩码(原地修改) + * @param other 用于按位异或的掩码 */ public static xorInPlace(target: BitMask64Data, other: BitMask64Data): void { target.lo ^= other.lo; @@ -184,7 +159,8 @@ export class BitMask64Utils { } /** - * 原地清零 + * 清除掩码的所有位为0 + * @param mask 要清除的掩码(原地修改) */ public static clear(mask: BitMask64Data): void { mask.lo = 0; @@ -192,302 +168,73 @@ export class BitMask64Utils { } /** - * 复制掩码 + * 将源掩码的值复制到目标掩码 + * @param source 源掩码 + * @param target 目标掩码(原地修改) */ - public static copy(from: BitMask64Data, to: BitMask64Data): void { - to.lo = from.lo; - to.hi = from.hi; + public static copy(source: BitMask64Data, target: BitMask64Data): void { + target.lo = source.lo; + target.hi = source.hi; } /** - * 创建副本 + * 创建掩码的深拷贝 + * @param mask 要拷贝的掩码 + * @returns 新的掩码对象,内容与源掩码相同 */ public static clone(mask: BitMask64Data): BitMask64Data { return { lo: mask.lo, hi: mask.hi }; } /** - * 转换为字符串(调试用) + * 将掩码转换为字符串表示 + * @param mask 要转换的掩码 + * @param radix 进制,支持2(二进制)或16(十六进制),默认为2 + * @returns 掩码的字符串表示,二进制不带前缀,十六进制带0x前缀 + * @throws 当进制不支持时抛出错误 */ public static toString(mask: BitMask64Data, radix: number = 2): string { if (radix === 2) { - const hiBits = mask.hi.toString(2).padStart(32, '0'); - const loBits = mask.lo.toString(2).padStart(32, '0'); - return hiBits + loBits; + if (mask.hi === 0) { + return mask.lo.toString(2); + } else { + const hiBits = mask.hi.toString(2); + const loBits = mask.lo.toString(2).padStart(32, '0'); + return hiBits + loBits; + } } else if (radix === 16) { - const hiBits = mask.hi.toString(16).padStart(8, '0'); - const loBits = mask.lo.toString(16).padStart(8, '0'); - return '0x' + hiBits + loBits; + if (mask.hi === 0) { + return '0x' + mask.lo.toString(16).toUpperCase(); + } else { + const hiBits = mask.hi.toString(16).toUpperCase(); + const loBits = mask.lo.toString(16).toUpperCase().padStart(8, '0'); + return '0x' + hiBits + loBits; + } } else { throw new Error('Only radix 2 and 16 are supported'); } } /** - * 计算置位数量 + * 计算掩码中设置为1的位数 + * @param mask 要计算的掩码 + * @returns 掩码中1的位数 */ public static popCount(mask: BitMask64Data): number { - const popCount32 = (n: number) => { - n = n - ((n >>> 1) & 0x55555555); - n = (n & 0x33333333) + ((n >>> 2) & 0x33333333); - return (((n + (n >>> 4)) & 0x0f0f0f0f) * 0x01010101) >>> 24; - }; + let count = 0; + let lo = mask.lo; + let hi = mask.hi; - return popCount32(mask.lo) + popCount32(mask.hi); - } -} - -/** - * 64位掩码类 - */ -export class BitMask64 implements IBigIntLike { - private bits: BitMask64Data; - - constructor(value?: number | string | BitMask64Data) { - if (typeof value === 'number') { - this.bits = BitMask64Utils.fromNumber(value); - } else if (typeof value === 'string') { - this.bits = this.fromString(value); - } else if (value && typeof value === 'object' && 'lo' in value && 'hi' in value) { - this.bits = BitMask64Utils.clone(value); - } else { - this.bits = BitMask64Utils.clone(BitMask64Utils.ZERO); - } - } - - private fromString(value: string): BitMask64Data { - value = value.trim(); - - if (value.startsWith('0x') || value.startsWith('0X')) { - const hex = value.substring(2); - const num = parseInt(hex.length <= 8 ? hex : hex.substring(hex.length - 8), 16); - const hi = hex.length > 8 ? parseInt(hex.substring(0, hex.length - 8), 16) : 0; - return { lo: num >>> 0, hi: hi >>> 0 }; - } else if (value.startsWith('0b') || value.startsWith('0B')) { - const binary = value.substring(2); - const num = parseInt(binary.length <= 32 ? binary : binary.substring(binary.length - 32), 2); - const hi = binary.length > 32 ? parseInt(binary.substring(0, binary.length - 32), 2) : 0; - return { lo: num >>> 0, hi: hi >>> 0 }; - } else { - const num = parseInt(value, 10); - return BitMask64Utils.fromNumber(num); - } - } - - valueOf(): number { - return this.bits.lo; - } - - toString(radix: number = 10): string { - if (radix === 2 || radix === 16) { - return BitMask64Utils.toString(this.bits, radix); - } else if (radix === 10) { - if (this.bits.hi === 0) { - return this.bits.lo.toString(10); - } else { - return `${this.bits.hi * 4294967296 + this.bits.lo}`; - } - } else { - throw new Error('Only radix 2, 10, and 16 are supported'); - } - } - - and(other: BitMask64): BitMask64 { - const result = new BitMask64(); - result.bits.lo = this.bits.lo & other.bits.lo; - result.bits.hi = this.bits.hi & other.bits.hi; - return result; - } - - or(other: BitMask64): BitMask64 { - const result = new BitMask64(); - result.bits.lo = this.bits.lo | other.bits.lo; - result.bits.hi = this.bits.hi | other.bits.hi; - return result; - } - - xor(other: BitMask64): BitMask64 { - const result = new BitMask64(); - result.bits.lo = this.bits.lo ^ other.bits.lo; - result.bits.hi = this.bits.hi ^ other.bits.hi; - return result; - } - - not(maxBits: number = 64): BitMask64 { - const result = new BitMask64(); - - if (maxBits <= 32) { - const mask = (1 << maxBits) - 1; - result.bits.lo = (~this.bits.lo) & mask; - result.bits.hi = 0; - } else { - result.bits.lo = ~this.bits.lo; - if (maxBits < 64) { - const remainingBits = maxBits - 32; - const mask = (1 << remainingBits) - 1; - result.bits.hi = (~this.bits.hi) & mask; - } else { - result.bits.hi = ~this.bits.hi; - } + while (lo) { + lo &= lo - 1; + count++; } - return result; - } - - shiftLeft(bits: number): BitMask64 { - const result = new BitMask64(); - - if (bits === 0) { - BitMask64Utils.copy(this.bits, result.bits); - return result; + while (hi) { + hi &= hi - 1; + count++; } - if (bits >= 64) { - BitMask64Utils.clear(result.bits); - return result; - } - - if (bits >= 32) { - result.bits.hi = this.bits.lo << (bits - 32); - result.bits.lo = 0; - } else { - result.bits.hi = (this.bits.hi << bits) | (this.bits.lo >>> (32 - bits)); - result.bits.lo = this.bits.lo << bits; - } - - return result; - } - - shiftRight(bits: number): BitMask64 { - const result = new BitMask64(); - - if (bits === 0) { - BitMask64Utils.copy(this.bits, result.bits); - return result; - } - - if (bits >= 64) { - BitMask64Utils.clear(result.bits); - return result; - } - - if (bits >= 32) { - result.bits.lo = this.bits.hi >>> (bits - 32); - result.bits.hi = 0; - } else { - result.bits.lo = (this.bits.lo >>> bits) | (this.bits.hi << (32 - bits)); - result.bits.hi = this.bits.hi >>> bits; - } - - return result; - } - - equals(other: BitMask64): boolean { - return BitMask64Utils.equals(this.bits, other.bits); - } - - isZero(): boolean { - return BitMask64Utils.isZero(this.bits); - } - - clone(): BitMask64 { - return new BitMask64(this.bits); - } - - // 判定方法 - hasAny(other: BitMask64): boolean { - return BitMask64Utils.hasAny(this.bits, other.bits); - } - - hasAll(other: BitMask64): boolean { - return BitMask64Utils.hasAll(this.bits, other.bits); - } - - hasNone(other: BitMask64): boolean { - return BitMask64Utils.hasNone(this.bits, other.bits); - } - - // 原地修改方法 - orInPlace(other: BitMask64): this { - BitMask64Utils.orInPlace(this.bits, other.bits); - return this; - } - - andInPlace(other: BitMask64): this { - BitMask64Utils.andInPlace(this.bits, other.bits); - return this; - } - - xorInPlace(other: BitMask64): this { - BitMask64Utils.xorInPlace(this.bits, other.bits); - return this; - } - - setBitInPlace(bitIndex: number): this { - BitMask64Utils.setBit(this.bits, bitIndex); - return this; - } - - clearBitInPlace(bitIndex: number): this { - BitMask64Utils.clearBit(this.bits, bitIndex); - return this; - } - - clearInPlace(): this { - BitMask64Utils.clear(this.bits); - return this; - } - - copyFrom(other: BitMask64): this { - BitMask64Utils.copy(other.bits, this.bits); - return this; - } - - getRawMask(): BitMask64Data { - return this.bits; - } - - static create(bitIndex: number): BitMask64 { - const result = new BitMask64(); - result.bits = BitMask64Utils.create(bitIndex); - return result; - } - - static fromNumber(value: number): BitMask64 { - return new BitMask64(value); - } - - static zero(): BitMask64 { - return new BitMask64(); - } -} - -/** - * 掩码工厂类 - */ -export class BitMask64Factory { - private static _cachedZero: BitMask64 | null = null; - private static _cachedOne: BitMask64 | null = null; - - public static create(value: number | string = 0): BitMask64 { - return new BitMask64(value); - } - - public static zero(): BitMask64 { - if (!this._cachedZero) { - this._cachedZero = new BitMask64(0); - } - return this._cachedZero.clone(); - } - - public static one(): BitMask64 { - if (!this._cachedOne) { - this._cachedOne = new BitMask64(1); - } - return this._cachedOne.clone(); - } - - public static fromBitIndex(bitIndex: number): BitMask64 { - return BitMask64.create(bitIndex); + return count; } } \ 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 834039a8..a3a48d37 100644 --- a/packages/core/src/ECS/Utils/Bits.ts +++ b/packages/core/src/ECS/Utils/Bits.ts @@ -1,235 +1,256 @@ -import { IBigIntLike, BigIntFactory } from './BigIntCompatibility'; +import { BitMask64Data, BitMask64Utils } from './BigIntCompatibility'; /** - * 高性能位操作类 - * - * 基于BigInt实现,支持任意数量的位操作。 - * 自动适配运行环境,在不支持BigInt的环境中使用兼容实现。 - * - * @example - * ```typescript - * const bits = new Bits(); - * bits.set(0); - * bits.set(5); - * console.log(bits.get(0)); // true - * console.log(bits.get(1)); // false - * ``` + * 64位位集合类,用于高效的位操作 + * 支持最多64个位的设置、清除、查询和逻辑运算 */ export class Bits { - private _value: IBigIntLike; + /** 存储位数据的64位掩码 */ + private _value: BitMask64Data; /** - * 构造函数 - * @param initialValue 初始值,可以是IBigIntLike或数值 + * 构造函数,创建位集合 + * @param initialValue 初始值,可以是BitMask64Data对象、数字或字符串 */ - constructor(initialValue?: IBigIntLike | number | string) { + constructor(initialValue?: BitMask64Data | number | string) { if (initialValue && typeof initialValue === 'object') { - this._value = initialValue; + this._value = BitMask64Utils.clone(initialValue); + } else if (typeof initialValue === 'number') { + this._value = BitMask64Utils.fromNumber(initialValue); + } else if (typeof initialValue === 'string') { + const num = parseInt(initialValue, 10); + this._value = BitMask64Utils.fromNumber(num); } else { - this._value = BigIntFactory.create(initialValue || 0); + this._value = BitMask64Utils.clone(BitMask64Utils.ZERO); } } /** - * 设置指定位置的位为1 - * @param index 位索引(从0开始) - * @throws {Error} 当索引为负数时抛出错误 + * 设置指定位为1 + * @param index 位索引,范围 [0, 63] + * @throws 当位索引为负数或超过64位限制时抛出错误 */ public set(index: number): void { if (index < 0) { throw new Error('Bit index cannot be negative'); } - const mask = BigIntFactory.one().shiftLeft(index); - this._value = this._value.or(mask); + + if (index >= 64) { + throw new Error('Bit index exceeds 64-bit limit. ECS framework supports max 64 component types.'); + } + + BitMask64Utils.setBit(this._value, index); } /** - * 清除指定位置的位(设为0) - * @param index 位索引(从0开始) - * @throws {Error} 当索引为负数时抛出错误 + * 清除指定位为0 + * @param index 位索引,范围 [0, 63] + * @throws 当位索引为负数时抛出错误 */ public clear(index: number): void { if (index < 0) { throw new Error('Bit index cannot be negative'); } - const mask = BigIntFactory.one().shiftLeft(index).not(); - this._value = this._value.and(mask); + + if (index >= 64) { + return; + } + + BitMask64Utils.clearBit(this._value, index); } /** - * 获取指定位置的位值 - * @param index 位索引(从0开始) - * @returns 位值(true表示1,false表示0) + * 获取指定位的值 + * @param index 位索引 + * @returns 如果位被设置为1则返回true,否则返回false */ public get(index: number): boolean { - if (index < 0) { + if (index < 0 || index >= 64) { return false; } - const mask = BigIntFactory.one().shiftLeft(index); - return !this._value.and(mask).isZero(); + + const mask = BitMask64Utils.create(index); + return BitMask64Utils.hasAny(this._value, mask); } /** - * 检查是否包含所有指定的位 - * @param other 另一个Bits对象 - * @returns 是否包含所有指定的位 + * 检查是否包含另一个位集合的所有位 + * @param other 另一个位集合 + * @returns 如果包含other的所有设置位则返回true */ public containsAll(other: Bits): boolean { - const intersection = this._value.and(other._value); - return intersection.equals(other._value); + return BitMask64Utils.hasAll(this._value, other._value); } /** - * 检查是否包含任意一个指定的位 - * @param other 另一个Bits对象 - * @returns 是否包含任意一个指定的位 + * 检查是否与另一个位集合有交集 + * @param other 另一个位集合 + * @returns 如果有共同的设置位则返回true */ public intersects(other: Bits): boolean { - return !this._value.and(other._value).isZero(); + return BitMask64Utils.hasAny(this._value, other._value); } /** - * 检查是否不包含任何指定的位 - * @param other 另一个Bits对象 - * @returns 是否不包含任何指定的位 + * 检查是否与另一个位集合没有交集 + * @param other 另一个位集合 + * @returns 如果没有共同的设置位则返回true */ public excludes(other: Bits): boolean { - return !this.intersects(other); + return BitMask64Utils.hasNone(this._value, other._value); } /** - * 清空所有位 + * 清除所有位为0 */ public clearAll(): void { - this._value = BigIntFactory.zero(); + BitMask64Utils.clear(this._value); } /** - * 检查是否为空(没有设置任何位) - * @returns 是否为空 + * 检查位集合是否为空 + * @returns 如果所有位都为0则返回true */ public isEmpty(): boolean { - return this._value.isZero(); + return BitMask64Utils.isZero(this._value); } /** - * 获取设置的位数量 - * @returns 设置为1的位数量 + * 计算设置为1的位数 + * @returns 设置位的总数 */ public cardinality(): number { - let count = 0; - let value = this._value.clone(); - - while (!value.isZero()) { - const one = BigIntFactory.one(); - if (!value.and(one).isZero()) { - count++; - } - value = value.shiftRight(1); - } - - return count; + return BitMask64Utils.popCount(this._value); } /** - * 位运算:与 - * @param other 另一个Bits对象 - * @returns 新的Bits对象,包含与运算结果 + * 与另一个位集合执行按位与操作 + * @param other 另一个位集合 + * @returns 新的位集合,包含按位与的结果 */ public and(other: Bits): Bits { - return new Bits(this._value.and(other._value)); + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + BitMask64Utils.andInPlace(result._value, other._value); + return result; } /** - * 位运算:或 - * @param other 另一个Bits对象 - * @returns 新的Bits对象,包含或运算结果 + * 与另一个位集合执行按位或操作 + * @param other 另一个位集合 + * @returns 新的位集合,包含按位或的结果 */ public or(other: Bits): Bits { - return new Bits(this._value.or(other._value)); + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + BitMask64Utils.orInPlace(result._value, other._value); + return result; } /** - * 位运算:异或 - * @param other 另一个Bits对象 - * @returns 新的Bits对象,包含异或运算结果 + * 与另一个位集合执行按位异或操作 + * @param other 另一个位集合 + * @returns 新的位集合,包含按位异或的结果 */ public xor(other: Bits): Bits { - return new Bits(this._value.xor(other._value)); + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + BitMask64Utils.xorInPlace(result._value, other._value); + return result; } /** - * 位运算:非 - * @param maxBits 最大位数限制,默认64位 - * @returns 新的Bits对象,包含非运算结果 + * 执行按位取反操作 + * @param maxBits 最大位数,默认为64 + * @returns 新的位集合,包含按位取反的结果 */ public not(maxBits: number = 64): Bits { - return new Bits(this._value.not(maxBits)); + if (maxBits > 64) { + maxBits = 64; + } + + const result = new Bits(); + BitMask64Utils.copy(this._value, result._value); + + if (maxBits <= 32) { + const mask = (1 << maxBits) - 1; + result._value.lo = (~result._value.lo) & mask; + result._value.hi = 0; + } else { + result._value.lo = ~result._value.lo; + if (maxBits < 64) { + const remainingBits = maxBits - 32; + const mask = (1 << remainingBits) - 1; + result._value.hi = (~result._value.hi) & mask; + } else { + result._value.hi = ~result._value.hi; + } + } + + return result; } /** - * 复制另一个Bits对象 - * @param other 要复制的Bits对象 + * 从另一个位集合复制值 + * @param other 源位集合 */ public copyFrom(other: Bits): void { - this._value = other._value.clone(); + BitMask64Utils.copy(other._value, this._value); } /** - * 创建当前Bits的副本 - * @returns 新的Bits对象副本 + * 创建当前位集合的深拷贝 + * @returns 新的位集合,内容与当前位集合相同 */ public clone(): Bits { - return new Bits(this._value.clone()); + return new Bits(this._value); } /** - * 获取原始值 - * @returns 原始的IBigIntLike值 + * 获取内部的64位掩码数据 + * @returns 内部存储的BitMask64Data对象 */ - public getValue(): IBigIntLike { + public getValue(): BitMask64Data { return this._value; } /** - * 设置原始值 - * @param value 新的值,可以是IBigIntLike或数值 + * 设置位集合的值 + * @param value 新值,可以是BitMask64Data对象、数字或字符串 */ - public setValue(value: IBigIntLike | number | string): void { + public setValue(value: BitMask64Data | number | string): void { if (typeof value === 'object') { - this._value = value; + BitMask64Utils.copy(value, this._value); + } else if (typeof value === 'number') { + this._value = BitMask64Utils.fromNumber(value); } else { - this._value = BigIntFactory.create(value); + const num = parseInt(value, 10); + this._value = BitMask64Utils.fromNumber(num); } } /** - * 获取调试信息 - * @returns 返回显示设置位索引的字符串 + * 将位集合转换为可读字符串 + * @returns 格式为"Bits[index1, index2, ...]"的字符串 */ public toString(): string { const bits: string[] = []; - let index = 0; - let value = this._value.clone(); - - while (!value.isZero()) { - const one = BigIntFactory.one(); - if (!value.and(one).isZero()) { - bits.push(index.toString()); + for (let i = 0; i < 64; i++) { + if (this.get(i)) { + bits.push(i.toString()); } - value = value.shiftRight(1); - index++; } - return `Bits[${bits.join(', ')}]`; } /** - * 获取二进制表示 - * @param maxBits 最大位数,默认64位 - * @returns 二进制字符串表示 + * 将位集合转换为二进制字符串 + * @param maxBits 最大位数,默认为64 + * @returns 二进制字符串表示,每8位用空格分隔 */ public toBinaryString(maxBits: number = 64): string { + if (maxBits > 64) maxBits = 64; + let result = ''; for (let i = maxBits - 1; i >= 0; i--) { result += this.get(i) ? '1' : '0'; @@ -241,81 +262,111 @@ export class Bits { } /** - * 获取十六进制表示 - * @returns 十六进制字符串表示 + * 将位集合转换为十六进制字符串 + * @returns 十六进制字符串表示,带0x前缀 */ public toHexString(): string { - return '0x' + this._value.toString(16).toUpperCase(); + return BitMask64Utils.toString(this._value, 16); } /** - * 从二进制字符串创建Bits - * @param binaryString 二进制字符串 - * @returns 新的Bits对象 + * 从二进制字符串创建位集合 + * @param binaryString 二进制字符串,可以包含空格 + * @returns 新的位集合对象 */ public static fromBinaryString(binaryString: string): Bits { const cleanString = binaryString.replace(/\s/g, ''); - const value = BigIntFactory.fromBinaryString(cleanString); - return new Bits(value); + let data: BitMask64Data; + if (cleanString.length <= 32) { + const num = parseInt(cleanString, 2); + data = { lo: num >>> 0, hi: 0 }; + } else { + const loBits = cleanString.substring(cleanString.length - 32); + const hiBits = cleanString.substring(0, cleanString.length - 32); + const lo = parseInt(loBits, 2); + const hi = parseInt(hiBits, 2); + data = { lo: lo >>> 0, hi: hi >>> 0 }; + } + return new Bits(data); } /** - * 从十六进制字符串创建Bits - * @param hexString 十六进制字符串 - * @returns 新的Bits对象 + * 从十六进制字符串创建位集合 + * @param hexString 十六进制字符串,可以带或不带0x前缀 + * @returns 新的位集合对象 */ public static fromHexString(hexString: string): Bits { - const value = BigIntFactory.fromHexString(hexString); - return new Bits(value); + const cleanString = hexString.replace(/^0x/i, ''); + let data: BitMask64Data; + if (cleanString.length <= 8) { + const num = parseInt(cleanString, 16); + data = { lo: num >>> 0, hi: 0 }; + } else { + const loBits = cleanString.substring(cleanString.length - 8); + const hiBits = cleanString.substring(0, cleanString.length - 8); + const lo = parseInt(loBits, 16); + const hi = parseInt(hiBits, 16); + data = { lo: lo >>> 0, hi: hi >>> 0 }; + } + return new Bits(data); } /** - * 比较两个Bits对象是否相等 - * @param other 另一个Bits对象 - * @returns 是否相等 + * 检查是否与另一个位集合相等 + * @param other 另一个位集合 + * @returns 如果两个位集合完全相同则返回true */ public equals(other: Bits): boolean { - return this._value.equals(other._value); + return BitMask64Utils.equals(this._value, other._value); } /** - * 获取最高位的索引 - * @returns 最高位的索引,如果为空则返回-1 + * 获取最高位设置位的索引 + * @returns 最高位设置位的索引,如果位集合为空则返回-1 */ public getHighestBitIndex(): number { - if (this._value.isZero()) { + if (BitMask64Utils.isZero(this._value)) { return -1; } - let index = 0; - let value = this._value.clone(); - - while (!value.shiftRight(1).isZero()) { - value = value.shiftRight(1); - index++; + if (this._value.hi !== 0) { + for (let i = 31; i >= 0; i--) { + if ((this._value.hi & (1 << i)) !== 0) { + return i + 32; + } + } } - return index; + for (let i = 31; i >= 0; i--) { + if ((this._value.lo & (1 << i)) !== 0) { + return i; + } + } + + return -1; } /** - * 获取最低位的索引 - * @returns 最低位的索引,如果为空则返回-1 + * 获取最低位设置位的索引 + * @returns 最低位设置位的索引,如果位集合为空则返回-1 */ public getLowestBitIndex(): number { - if (this._value.isZero()) { + if (BitMask64Utils.isZero(this._value)) { return -1; } - let index = 0; - let value = this._value.clone(); - const one = BigIntFactory.one(); - - while (value.and(one).isZero()) { - value = value.shiftRight(1); - index++; + for (let i = 0; i < 32; i++) { + if ((this._value.lo & (1 << i)) !== 0) { + return i; + } } - return index; + for (let i = 0; i < 32; i++) { + if ((this._value.hi & (1 << i)) !== 0) { + return i + 32; + } + } + + return -1; } } \ No newline at end of file diff --git a/packages/core/src/ECS/Utils/index.ts b/packages/core/src/ECS/Utils/index.ts index 8987e70d..c063b73d 100644 --- a/packages/core/src/ECS/Utils/index.ts +++ b/packages/core/src/ECS/Utils/index.ts @@ -5,6 +5,6 @@ export { IdentifierPool } from './IdentifierPool'; export { Matcher } from './Matcher'; export { Bits } from './Bits'; export { ComponentTypeManager } from './ComponentTypeManager'; -export { BigIntFactory } from './BigIntCompatibility'; +export { BitMask64Utils, BitMask64Data } from './BigIntCompatibility'; export { SparseSet } from './SparseSet'; export { ComponentSparseSet } from './ComponentSparseSet'; \ No newline at end of file diff --git a/packages/core/tests/ECS/Core/ComponentStorage.test.ts b/packages/core/tests/ECS/Core/ComponentStorage.test.ts index 5e52b17d..dbf53ebd 100644 --- a/packages/core/tests/ECS/Core/ComponentStorage.test.ts +++ b/packages/core/tests/ECS/Core/ComponentStorage.test.ts @@ -5,7 +5,7 @@ import { ComponentType } from '../../../src/ECS/Core/ComponentStorage'; import { Component } from '../../../src/ECS/Component'; -import { BigIntFactory } from '../../../src/ECS/Utils/BigIntCompatibility'; +import { BitMask64Utils } from '../../../src/ECS/Utils/BigIntCompatibility'; // 测试组件类(默认使用原始存储) class TestComponent extends Component { @@ -116,8 +116,8 @@ describe('ComponentRegistry - 组件注册表测试', () => { const mask1 = ComponentRegistry.getBitMask(TestComponent); const mask2 = ComponentRegistry.getBitMask(PositionComponent); - expect(mask1.toString()).toBe('1'); // 2^0 - expect(mask2.toString()).toBe('2'); // 2^1 + expect(mask1.lo).toBe(1); // 2^0 + expect(mask2.lo).toBe(2); // 2^1 }); test('应该能够获取组件的位索引', () => { @@ -483,12 +483,12 @@ describe('ComponentStorageManager - 组件存储管理器测试', () => { const mask = manager.getComponentMask(1); // 应该包含TestComponent(位0)和PositionComponent(位1)的掩码 - expect(mask.toString()).toBe('3'); // 1 | 2 = 3 + expect(mask.lo).toBe(3); // 1 | 2 = 3 }); test('没有组件的实体应该有零掩码', () => { const mask = manager.getComponentMask(999); - expect(mask.isZero()).toBe(true); + expect(BitMask64Utils.equals(mask, BitMask64Utils.ZERO)).toBe(true); }); test('添加和移除组件应该更新掩码', () => { @@ -497,15 +497,15 @@ describe('ComponentStorageManager - 组件存储管理器测试', () => { manager.addComponent(1, new TestComponent(100)); let mask = manager.getComponentMask(1); - expect(mask.toString()).toBe('1'); + expect(mask.lo).toBe(1); manager.addComponent(1, new PositionComponent(10, 20)); mask = manager.getComponentMask(1); - expect(mask.toString()).toBe('3'); // 0b11 + expect(mask.lo).toBe(3); // 0b11 manager.removeComponent(1, TestComponent); mask = manager.getComponentMask(1); - expect(mask.toString()).toBe('2'); // 0b10 + expect(mask.lo).toBe(2); // 0b10 }); }); diff --git a/packages/core/tests/ECS/Utils/Bits.test.ts b/packages/core/tests/ECS/Utils/Bits.test.ts index b0c18d1b..ede80a02 100644 --- a/packages/core/tests/ECS/Utils/Bits.test.ts +++ b/packages/core/tests/ECS/Utils/Bits.test.ts @@ -430,13 +430,31 @@ describe('Bits - 高性能位操作类测试', () => { }); describe('大数值处理', () => { + const supportsBigInt = (() => { + try { + return typeof BigInt !== 'undefined' && BigInt(0) === 0n; + } catch { + return false; + } + })(); + it('应该能够处理超过64位的数值', () => { + if (!supportsBigInt) { + pending('BigInt not supported in this environment'); + return; + } + bits.set(100); expect(bits.get(100)).toBe(true); expect(bits.cardinality()).toBe(1); }); it('应该能够处理非常大的位索引', () => { + if (!supportsBigInt) { + pending('BigInt not supported in this environment'); + return; + } + bits.set(1000); bits.set(2000); expect(bits.get(1000)).toBe(true); @@ -445,6 +463,11 @@ describe('Bits - 高性能位操作类测试', () => { }); it('大数值的位运算应该正确', () => { + if (!supportsBigInt) { + pending('BigInt not supported in this environment'); + return; + } + const largeBits1 = new Bits(); const largeBits2 = new Bits();