使用Lerna 和 monorepo管理项目结构

This commit is contained in:
YHH
2025-08-07 13:29:12 +08:00
parent 4479f0fab0
commit ea8523be35
135 changed files with 7058 additions and 372 deletions

View File

@@ -0,0 +1,746 @@
/**
* BigInt兼容性抽象层
*
* 为不支持BigInt的环境提供兼容实现确保ECS框架在所有平台上都能正常运行。
* 自动检测运行时环境的BigInt支持情况并提供统一的接口。
*
* @example
* ```typescript
* // 创建兼容的BigInt值
* const value = BigIntFactory.create(123);
*
* // 位运算
* const result = value.or(BigIntFactory.create(456));
*
* // 检查兼容性
* console.log(BigIntFactory.isNativeSupported()); // true/false
* ```
*/
/**
* BigInt兼容接口
*
* 定义了BigInt的基本操作接口支持原生BigInt和兼容实现的统一调用。
*/
export interface IBigIntLike {
/**
* 获取数值表示
* @returns 数值
*/
valueOf(): number;
/**
* 转换为字符串
* @param radix 进制支持2、10、16
* @returns 字符串表示
*/
toString(radix?: number): string;
/**
* 位运算:与
* @param other 另一个BigInt值
* @returns 运算结果
*/
and(other: IBigIntLike): IBigIntLike;
/**
* 位运算:或
* @param other 另一个BigInt值
* @returns 运算结果
*/
or(other: IBigIntLike): IBigIntLike;
/**
* 位运算:异或
* @param other 另一个BigInt值
* @returns 运算结果
*/
xor(other: IBigIntLike): IBigIntLike;
/**
* 位运算:非
* @param maxBits 最大位数限制
* @returns 运算结果
*/
not(maxBits?: number): IBigIntLike;
/**
* 左移位运算
* @param bits 移位数
* @returns 运算结果
*/
shiftLeft(bits: number): IBigIntLike;
/**
* 右移位运算
* @param bits 移位数
* @returns 运算结果
*/
shiftRight(bits: number): IBigIntLike;
/**
* 相等比较
* @param other 另一个BigInt值
* @returns 是否相等
*/
equals(other: IBigIntLike): boolean;
/**
* 检查是否为零
* @returns 是否为零
*/
isZero(): boolean;
/**
* 创建副本
* @returns 新的实例
*/
clone(): IBigIntLike;
}
/**
* 原生BigInt包装器
*
* 为支持BigInt的环境提供统一接口包装。
*/
class NativeBigInt implements IBigIntLike {
constructor(private value: bigint) {}
valueOf(): number {
return Number(this.value);
}
toString(radix?: number): string {
if (radix !== undefined && radix !== 10 && radix !== 16 && radix !== 2) {
throw new Error('Only radix 2, 10, and 16 are supported');
}
const result = this.value.toString(radix);
if (radix === 16) {
return result.toUpperCase();
}
return result;
}
and(other: IBigIntLike): IBigIntLike {
const otherBigInt = other instanceof NativeBigInt ? other.value : BigInt(other.valueOf());
return new NativeBigInt(this.value & otherBigInt);
}
or(other: IBigIntLike): IBigIntLike {
const otherBigInt = other instanceof NativeBigInt ? other.value : BigInt(other.valueOf());
return new NativeBigInt(this.value | otherBigInt);
}
xor(other: IBigIntLike): IBigIntLike {
const otherBigInt = other instanceof NativeBigInt ? other.value : BigInt(other.valueOf());
return new NativeBigInt(this.value ^ otherBigInt);
}
not(maxBits: number = 64): IBigIntLike {
const mask = (BigInt(1) << BigInt(maxBits)) - BigInt(1);
return new NativeBigInt((~this.value) & mask);
}
shiftLeft(bits: number): IBigIntLike {
return new NativeBigInt(this.value << BigInt(bits));
}
shiftRight(bits: number): IBigIntLike {
return new NativeBigInt(this.value >> BigInt(bits));
}
equals(other: IBigIntLike): boolean {
const otherBigInt = other instanceof NativeBigInt ? other.value : BigInt(other.valueOf());
return this.value === otherBigInt;
}
isZero(): boolean {
return this.value === BigInt(0);
}
clone(): IBigIntLike {
return new NativeBigInt(this.value);
}
}
/**
* 数组模拟BigInt实现
*
* 为不支持BigInt的环境提供兼容实现使用32位数组模拟大整数运算。
* 性能略低于原生BigInt但保证功能一致性。
*/
class ArrayBigInt implements IBigIntLike {
private chunks: number[] = []; // 32位块数组
private static readonly CHUNK_SIZE = 32;
private static readonly CHUNK_MASK = 0xFFFFFFFF;
private static readonly CHUNK_MAX = 0x100000000; // 2^32
/**
* 构造函数
* @param value 初始值,可以是数值、字符串或数组
*/
constructor(value: number | string | number[] = 0) {
if (typeof value === 'number') {
this.fromNumber(value);
} else if (typeof value === 'string') {
this.fromString(value);
} else {
this.chunks = value.slice();
}
this.normalize();
}
/**
* 从数值初始化
* @param value 数值
*/
private fromNumber(value: number): void {
this.chunks = [];
// 处理负数(在位运算中通常不会遇到)
if (value < 0) {
value = Math.abs(value);
}
if (value === 0) {
this.chunks = [0];
return;
}
while (value > 0) {
this.chunks.push(value & ArrayBigInt.CHUNK_MASK);
value = Math.floor(value / ArrayBigInt.CHUNK_MAX);
}
}
/**
* 从字符串初始化
* @param value 字符串(支持十进制、十六进制、二进制)
*/
private fromString(value: string): void {
value = value.trim();
if (value.startsWith('0x') || value.startsWith('0X')) {
// 十六进制
this.fromHexString(value.substring(2));
} else if (value.startsWith('0b') || value.startsWith('0B')) {
// 二进制
this.fromBinaryString(value.substring(2));
} else {
// 十进制
this.fromDecimalString(value);
}
}
/**
* 从十六进制字符串初始化
* @param hex 十六进制字符串
*/
private fromHexString(hex: string): void {
this.chunks = [0];
for (let i = hex.length - 1; i >= 0; i -= 8) {
const start = Math.max(0, i - 7);
const chunk = parseInt(hex.substring(start, i + 1), 16);
this.chunks.push(chunk);
}
this.normalize();
}
/**
* 从二进制字符串初始化
* @param binary 二进制字符串
*/
private fromBinaryString(binary: string): void {
this.chunks = [0];
for (let i = binary.length - 1; i >= 0; i -= 32) {
const start = Math.max(0, i - 31);
const chunk = parseInt(binary.substring(start, i + 1), 2);
this.chunks.push(chunk);
}
this.normalize();
}
/**
* 从十进制字符串初始化
* @param decimal 十进制字符串
*/
private fromDecimalString(decimal: string): void {
// 简化实现直接转换为数值在ECS位运算场景中通常是小数值
const num = parseInt(decimal, 10);
this.fromNumber(num);
}
/**
* 规范化数组,移除前导零
*/
private normalize(): void {
while (this.chunks.length > 1 && this.chunks[this.chunks.length - 1] === 0) {
this.chunks.pop();
}
if (this.chunks.length === 0) {
this.chunks = [0];
}
}
valueOf(): number {
let result = 0;
let multiplier = 1;
for (const chunk of this.chunks) {
result += chunk * multiplier;
multiplier *= ArrayBigInt.CHUNK_MAX;
// 防止溢出
if (multiplier > Number.MAX_SAFE_INTEGER) {
break;
}
}
return result;
}
toString(radix: number = 10): string {
if (radix !== 10 && radix !== 16 && radix !== 2) {
throw new Error('Only radix 2, 10, and 16 are supported');
}
if (this.isZero()) {
return '0';
}
if (radix === 10) {
// 简化实现,转换为数值
return this.valueOf().toString(10);
} else if (radix === 16) {
let result = '';
for (let i = this.chunks.length - 1; i >= 0; i--) {
const hex = this.chunks[i].toString(16);
result += i === this.chunks.length - 1 ? hex : hex.padStart(8, '0');
}
return result.toUpperCase();
} else if (radix === 2) {
let result = '';
for (let i = this.chunks.length - 1; i >= 0; i--) {
const binary = this.chunks[i].toString(2);
result += i === this.chunks.length - 1 ? binary : binary.padStart(32, '0');
}
return result;
}
return this.valueOf().toString(radix);
}
and(other: IBigIntLike): IBigIntLike {
const otherArray = other as ArrayBigInt;
const maxLength = Math.max(this.chunks.length, otherArray.chunks.length);
const result: number[] = [];
for (let i = 0; i < maxLength; i++) {
const a = i < this.chunks.length ? this.chunks[i] : 0;
const b = i < otherArray.chunks.length ? otherArray.chunks[i] : 0;
result.push(a & b);
}
return new ArrayBigInt(result);
}
or(other: IBigIntLike): IBigIntLike {
const otherArray = other as ArrayBigInt;
const maxLength = Math.max(this.chunks.length, otherArray.chunks.length);
const result: number[] = [];
for (let i = 0; i < maxLength; i++) {
const a = i < this.chunks.length ? this.chunks[i] : 0;
const b = i < otherArray.chunks.length ? otherArray.chunks[i] : 0;
result.push(a | b);
}
return new ArrayBigInt(result);
}
xor(other: IBigIntLike): IBigIntLike {
const otherArray = other as ArrayBigInt;
const maxLength = Math.max(this.chunks.length, otherArray.chunks.length);
const result: number[] = [];
for (let i = 0; i < maxLength; i++) {
const a = i < this.chunks.length ? this.chunks[i] : 0;
const b = i < otherArray.chunks.length ? otherArray.chunks[i] : 0;
result.push(a ^ b);
}
return new ArrayBigInt(result);
}
not(maxBits: number = 64): IBigIntLike {
const maxChunks = Math.ceil(maxBits / ArrayBigInt.CHUNK_SIZE);
const result: number[] = [];
for (let i = 0; i < maxChunks; i++) {
const chunk = i < this.chunks.length ? this.chunks[i] : 0;
if (i === maxChunks - 1) {
// 最后一个块需要处理剩余位数
const remainingBits = maxBits % ArrayBigInt.CHUNK_SIZE;
if (remainingBits > 0) {
const mask = (1 << remainingBits) - 1;
result.push((~chunk) & mask);
} else {
result.push((~chunk) & ArrayBigInt.CHUNK_MASK);
}
} else {
result.push((~chunk) & ArrayBigInt.CHUNK_MASK);
}
}
return new ArrayBigInt(result);
}
shiftLeft(bits: number): IBigIntLike {
if (bits === 0) {
return this.clone();
}
if (bits < 0) {
return this.shiftRight(-bits);
}
const chunkShift = Math.floor(bits / ArrayBigInt.CHUNK_SIZE);
const bitShift = bits % ArrayBigInt.CHUNK_SIZE;
const result: number[] = new Array(chunkShift).fill(0);
if (bitShift === 0) {
// 整块移位
result.push(...this.chunks);
} else {
// 部分位移位
let carry = 0;
for (const chunk of this.chunks) {
const shifted = (chunk << bitShift) | carry;
result.push(shifted & ArrayBigInt.CHUNK_MASK);
carry = chunk >>> (ArrayBigInt.CHUNK_SIZE - bitShift);
}
if (carry > 0) {
result.push(carry);
}
}
return new ArrayBigInt(result);
}
shiftRight(bits: number): IBigIntLike {
if (bits === 0) {
return this.clone();
}
if (bits < 0) {
return this.shiftLeft(-bits);
}
const chunkShift = Math.floor(bits / ArrayBigInt.CHUNK_SIZE);
const bitShift = bits % ArrayBigInt.CHUNK_SIZE;
if (chunkShift >= this.chunks.length) {
return new ArrayBigInt(0);
}
const result: number[] = [];
if (bitShift === 0) {
// 整块移位
for (let i = chunkShift; i < this.chunks.length; i++) {
result.push(this.chunks[i]);
}
} else {
// 部分位移位
let carry = 0;
for (let i = this.chunks.length - 1; i >= chunkShift; i--) {
const chunk = this.chunks[i];
const shifted = (carry << (ArrayBigInt.CHUNK_SIZE - bitShift)) | (chunk >>> bitShift);
result.unshift(shifted);
carry = chunk & ((1 << bitShift) - 1);
}
}
return new ArrayBigInt(result.length > 0 ? result : [0]);
}
equals(other: IBigIntLike): boolean {
if (!(other instanceof ArrayBigInt)) {
return false;
}
if (this.chunks.length !== other.chunks.length) {
return false;
}
for (let i = 0; i < this.chunks.length; i++) {
if (this.chunks[i] !== other.chunks[i]) {
return false;
}
}
return true;
}
isZero(): boolean {
return this.chunks.length === 1 && this.chunks[0] === 0;
}
clone(): IBigIntLike {
return new ArrayBigInt(this.chunks.slice());
}
}
/**
* BigInt工厂类
*
* 自动检测运行时环境的BigInt支持情况并提供统一的创建接口。
* 在支持BigInt的环境中使用原生实现在不支持的环境中使用兼容实现。
*/
export class BigIntFactory {
private static _supportsBigInt: boolean | null = null;
private static _cachedZero: IBigIntLike | null = null;
private static _cachedOne: IBigIntLike | null = null;
// 缓存检测结果以避免重复检测
/**
* 检查是否支持原生BigInt
* @returns 是否支持原生BigInt
*/
public static isNativeSupported(): boolean {
if (this._supportsBigInt === null) {
this._supportsBigInt = this.detectBigIntSupport();
}
return this._supportsBigInt;
}
/**
* 检测BigInt支持情况
* @returns 是否支持BigInt
*/
private static detectBigIntSupport(): boolean {
try {
// 检查BigInt构造函数是否存在
if (typeof BigInt === 'undefined') {
return false;
}
// 检查基本BigInt操作
const test1 = BigInt(1);
const test2 = BigInt(2);
const result = test1 | test2;
// 检查字面量支持
const literal = eval('1n'); // 使用eval避免语法错误
// 检查类型
if (typeof result !== 'bigint' || typeof literal !== 'bigint') {
return false;
}
// 检查基本运算
const shifted = test1 << BigInt(1);
const compared = test1 === BigInt(1);
return typeof shifted === 'bigint' && compared === true;
} catch (error) {
// 任何异常都表示不支持
return false;
}
}
/**
* 创建BigInt兼容值
* @param value 初始值
* @returns IBigIntLike实例
*/
public static create(value: number | string | bigint = 0): IBigIntLike {
if (this.isNativeSupported()) {
let bigintValue: bigint;
if (typeof value === 'bigint') {
bigintValue = value;
} else if (typeof value === 'string') {
bigintValue = BigInt(value);
} else {
bigintValue = BigInt(value);
}
return new NativeBigInt(bigintValue);
} else {
// 转换bigint类型到兼容类型
let compatValue: number | string;
if (typeof value === 'bigint') {
compatValue = value.toString();
} else {
compatValue = value;
}
return new ArrayBigInt(compatValue);
}
}
/**
* 创建零值
* @returns 零值的IBigIntLike实例
*/
public static zero(): IBigIntLike {
if (!this._cachedZero) {
this._cachedZero = this.create(0);
}
return this._cachedZero;
}
/**
* 创建1值
* @returns 1值的IBigIntLike实例
*/
public static one(): IBigIntLike {
if (!this._cachedOne) {
this._cachedOne = this.create(1);
}
return this._cachedOne;
}
/**
* 从二进制字符串创建
* @param binary 二进制字符串
* @returns IBigIntLike实例
*/
public static fromBinaryString(binary: string): IBigIntLike {
if (this.isNativeSupported()) {
const value = BigInt('0b' + binary);
return new NativeBigInt(value);
} else {
return new ArrayBigInt('0b' + binary);
}
}
/**
* 从十六进制字符串创建
* @param hex 十六进制字符串
* @returns IBigIntLike实例
*/
public static fromHexString(hex: string): IBigIntLike {
if (this.isNativeSupported()) {
const cleanHex = hex.replace(/^0x/i, '');
const value = BigInt('0x' + cleanHex);
return new NativeBigInt(value);
} else {
return new ArrayBigInt(hex);
}
}
/**
* 获取环境信息
* @returns 环境信息对象
*/
public static getEnvironmentInfo(): EnvironmentInfo {
return {
supportsBigInt: this.isNativeSupported(),
environment: this.detectEnvironment(),
jsEngine: this.detectJSEngine()
};
}
/**
* 检测运行环境
* @returns 环境类型
*/
private static detectEnvironment(): string {
if (typeof window !== 'undefined') {
// 浏览器环境
if (typeof navigator !== 'undefined') {
const userAgent = navigator.userAgent;
if (userAgent.includes('Chrome')) {
const match = userAgent.match(/Chrome\/(\d+)/);
const version = match ? parseInt(match[1]) : 0;
return `Chrome ${version}`;
}
if (userAgent.includes('Firefox')) {
const match = userAgent.match(/Firefox\/(\d+)/);
const version = match ? parseInt(match[1]) : 0;
return `Firefox ${version}`;
}
if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) {
const match = userAgent.match(/Version\/(\d+)/);
const version = match ? parseInt(match[1]) : 0;
return `Safari ${version}`;
}
return 'Browser (Unknown)';
}
return 'Browser';
} else if (typeof global !== 'undefined') {
// Node.js环境
if (typeof process !== 'undefined' && process.version) {
return `Node.js ${process.version}`;
}
return 'Node.js';
} else if (typeof (globalThis as any).wx !== 'undefined') {
// 微信小程序
return 'WeChat MiniProgram';
} else if (typeof (globalThis as any).cc !== 'undefined') {
// Cocos Creator
return 'Cocos Creator';
} else if (typeof (globalThis as any).Laya !== 'undefined') {
// Laya引擎
return 'Laya Engine';
}
return 'Unknown';
}
/**
* 检测JavaScript引擎
* @returns JS引擎信息
*/
private static detectJSEngine(): string {
try {
// V8引擎特征检测
if (typeof process !== 'undefined' && process.versions && process.versions.v8) {
return `V8 ${process.versions.v8}`;
}
// SpiderMonkey特征检测
if (typeof (globalThis as any).Components !== 'undefined') {
return 'SpiderMonkey';
}
// JavaScriptCore特征检测
if (typeof window !== 'undefined' && typeof (window as any).safari !== 'undefined') {
return 'JavaScriptCore';
}
return 'Unknown';
} catch {
return 'Unknown';
}
}
}
/**
* 环境信息接口
*/
export interface EnvironmentInfo {
/** 是否支持BigInt */
supportsBigInt: boolean;
/** 运行环境 */
environment: string;
/** JavaScript引擎 */
jsEngine: string;
}

View File

@@ -0,0 +1,321 @@
import { IBigIntLike, BigIntFactory } 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
* ```
*/
export class Bits {
private _value: IBigIntLike;
/**
* 构造函数
* @param initialValue 初始值可以是IBigIntLike或数值
*/
constructor(initialValue?: IBigIntLike | number | string) {
if (initialValue && typeof initialValue === 'object') {
this._value = initialValue;
} else {
this._value = BigIntFactory.create(initialValue || 0);
}
}
/**
* 设置指定位置的位为1
* @param index 位索引从0开始
* @throws {Error} 当索引为负数时抛出错误
*/
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);
}
/**
* 清除指定位置的位设为0
* @param index 位索引从0开始
* @throws {Error} 当索引为负数时抛出错误
*/
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);
}
/**
* 获取指定位置的位值
* @param index 位索引从0开始
* @returns 位值true表示1false表示0
*/
public get(index: number): boolean {
if (index < 0) {
return false;
}
const mask = BigIntFactory.one().shiftLeft(index);
return !this._value.and(mask).isZero();
}
/**
* 检查是否包含所有指定的位
* @param other 另一个Bits对象
* @returns 是否包含所有指定的位
*/
public containsAll(other: Bits): boolean {
const intersection = this._value.and(other._value);
return intersection.equals(other._value);
}
/**
* 检查是否包含任意一个指定的位
* @param other 另一个Bits对象
* @returns 是否包含任意一个指定的位
*/
public intersects(other: Bits): boolean {
return !this._value.and(other._value).isZero();
}
/**
* 检查是否不包含任何指定的位
* @param other 另一个Bits对象
* @returns 是否不包含任何指定的位
*/
public excludes(other: Bits): boolean {
return !this.intersects(other);
}
/**
* 清空所有位
*/
public clearAll(): void {
this._value = BigIntFactory.zero();
}
/**
* 检查是否为空(没有设置任何位)
* @returns 是否为空
*/
public isEmpty(): boolean {
return this._value.isZero();
}
/**
* 获取设置的位数量
* @returns 设置为1的位数量
*/
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;
}
/**
* 位运算:与
* @param other 另一个Bits对象
* @returns 新的Bits对象包含与运算结果
*/
public and(other: Bits): Bits {
return new Bits(this._value.and(other._value));
}
/**
* 位运算:或
* @param other 另一个Bits对象
* @returns 新的Bits对象包含或运算结果
*/
public or(other: Bits): Bits {
return new Bits(this._value.or(other._value));
}
/**
* 位运算:异或
* @param other 另一个Bits对象
* @returns 新的Bits对象包含异或运算结果
*/
public xor(other: Bits): Bits {
return new Bits(this._value.xor(other._value));
}
/**
* 位运算:非
* @param maxBits 最大位数限制默认64位
* @returns 新的Bits对象包含非运算结果
*/
public not(maxBits: number = 64): Bits {
return new Bits(this._value.not(maxBits));
}
/**
* 复制另一个Bits对象
* @param other 要复制的Bits对象
*/
public copyFrom(other: Bits): void {
this._value = other._value.clone();
}
/**
* 创建当前Bits的副本
* @returns 新的Bits对象副本
*/
public clone(): Bits {
return new Bits(this._value.clone());
}
/**
* 获取原始值
* @returns 原始的IBigIntLike值
*/
public getValue(): IBigIntLike {
return this._value;
}
/**
* 设置原始值
* @param value 新的值可以是IBigIntLike或数值
*/
public setValue(value: IBigIntLike | number | string): void {
if (typeof value === 'object') {
this._value = value;
} else {
this._value = BigIntFactory.create(value);
}
}
/**
* 获取调试信息
* @returns 返回显示设置位索引的字符串
*/
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());
}
value = value.shiftRight(1);
index++;
}
return `Bits[${bits.join(', ')}]`;
}
/**
* 获取二进制表示
* @param maxBits 最大位数默认64位
* @returns 二进制字符串表示
*/
public toBinaryString(maxBits: number = 64): string {
let result = '';
for (let i = maxBits - 1; i >= 0; i--) {
result += this.get(i) ? '1' : '0';
if (i % 8 === 0 && i > 0) {
result += ' ';
}
}
return result;
}
/**
* 获取十六进制表示
* @returns 十六进制字符串表示
*/
public toHexString(): string {
return '0x' + this._value.toString(16).toUpperCase();
}
/**
* 从二进制字符串创建Bits
* @param binaryString 二进制字符串
* @returns 新的Bits对象
*/
public static fromBinaryString(binaryString: string): Bits {
const cleanString = binaryString.replace(/\s/g, '');
const value = BigIntFactory.fromBinaryString(cleanString);
return new Bits(value);
}
/**
* 从十六进制字符串创建Bits
* @param hexString 十六进制字符串
* @returns 新的Bits对象
*/
public static fromHexString(hexString: string): Bits {
const value = BigIntFactory.fromHexString(hexString);
return new Bits(value);
}
/**
* 比较两个Bits对象是否相等
* @param other 另一个Bits对象
* @returns 是否相等
*/
public equals(other: Bits): boolean {
return this._value.equals(other._value);
}
/**
* 获取最高位的索引
* @returns 最高位的索引,如果为空则返回-1
*/
public getHighestBitIndex(): number {
if (this._value.isZero()) {
return -1;
}
let index = 0;
let value = this._value.clone();
while (!value.shiftRight(1).isZero()) {
value = value.shiftRight(1);
index++;
}
return index;
}
/**
* 获取最低位的索引
* @returns 最低位的索引,如果为空则返回-1
*/
public getLowestBitIndex(): number {
if (this._value.isZero()) {
return -1;
}
let index = 0;
let value = this._value.clone();
const one = BigIntFactory.one();
while (value.and(one).isZero()) {
value = value.shiftRight(1);
index++;
}
return index;
}
}

View File

@@ -0,0 +1,99 @@
import { Component } from '../Component';
import { Bits } from './Bits';
/**
* 组件类型管理器
* 负责管理组件类型的注册和ID分配
*/
export class ComponentTypeManager {
private static _instance: ComponentTypeManager;
private _componentTypes = new Map<Function, number>();
private _typeNames = new Map<number, string>();
private _nextTypeId = 0;
/**
* 获取单例实例
*/
public static get instance(): ComponentTypeManager {
if (!ComponentTypeManager._instance) {
ComponentTypeManager._instance = new ComponentTypeManager();
}
return ComponentTypeManager._instance;
}
private constructor() {}
/**
* 获取组件类型的ID
* @param componentType 组件类型构造函数
* @returns 组件类型ID
*/
public getTypeId<T extends Component>(componentType: new (...args: unknown[]) => T): number {
let typeId = this._componentTypes.get(componentType);
if (typeId === undefined) {
typeId = this._nextTypeId++;
this._componentTypes.set(componentType, typeId);
this._typeNames.set(typeId, componentType.name);
}
return typeId;
}
/**
* 获取组件类型名称
* @param typeId 组件类型ID
* @returns 组件类型名称
*/
public getTypeName(typeId: number): string {
return this._typeNames.get(typeId) || 'Unknown';
}
/**
* 创建包含指定组件类型的Bits对象
* @param componentTypes 组件类型构造函数数组
* @returns Bits对象
*/
public createBits(...componentTypes: (new (...args: unknown[]) => Component)[]): Bits {
const bits = new Bits();
for (const componentType of componentTypes) {
const typeId = this.getTypeId(componentType);
bits.set(typeId);
}
return bits;
}
/**
* 获取实体的组件位掩码
* @param components 组件数组
* @returns Bits对象
*/
public getEntityBits(components: Component[]): Bits {
const bits = new Bits();
for (const component of components) {
const typeId = this.getTypeId(component.constructor as new (...args: unknown[]) => Component);
bits.set(typeId);
}
return bits;
}
/**
* 重置管理器(主要用于测试)
*/
public reset(): void {
this._componentTypes.clear();
this._typeNames.clear();
this._nextTypeId = 0;
}
/**
* 获取已注册的组件类型数量
*/
public get registeredTypeCount(): number {
return this._componentTypes.size;
}
}

View File

@@ -0,0 +1,304 @@
import { Entity } from '../Entity';
import { Component } from '../Component';
/**
* 高性能实体列表管理器
* 管理场景中的所有实体,支持快速查找和批量操作
*/
export class EntityList {
public buffer: Entity[] = [];
private _scene: any; // 临时使用any避免循环依赖
// 索引映射,提升查找性能
private _idToEntity = new Map<number, Entity>();
private _nameToEntities = new Map<string, Entity[]>();
// 延迟操作队列
private _entitiesToAdd: Entity[] = [];
private _entitiesToRemove: Entity[] = [];
private _isUpdating = false;
public get count(): number {
return this.buffer.length;
}
constructor(scene: any) {
this._scene = scene;
}
/**
* 添加实体(立即添加或延迟添加)
* @param entity 要添加的实体
*/
public add(entity: Entity): void {
if (this._isUpdating) {
// 如果正在更新中,延迟添加
this._entitiesToAdd.push(entity);
} else {
this.addImmediate(entity);
}
}
/**
* 立即添加实体
* @param entity 要添加的实体
*/
private addImmediate(entity: Entity): void {
// 检查是否已存在
if (this._idToEntity.has(entity.id)) {
return;
}
this.buffer.push(entity);
this._idToEntity.set(entity.id, entity);
// 更新名称索引
this.updateNameIndex(entity, true);
}
/**
* 移除实体(立即移除或延迟移除)
* @param entity 要移除的实体
*/
public remove(entity: Entity): void {
if (this._isUpdating) {
// 如果正在更新中,延迟移除
this._entitiesToRemove.push(entity);
} else {
this.removeImmediate(entity);
}
}
/**
* 立即移除实体
* @param entity 要移除的实体
*/
private removeImmediate(entity: Entity): void {
const index = this.buffer.indexOf(entity);
if (index !== -1) {
this.buffer.splice(index, 1);
this._idToEntity.delete(entity.id);
// 更新名称索引
this.updateNameIndex(entity, false);
// 回收实体ID到ID池
if (this._scene && this._scene.identifierPool) {
this._scene.identifierPool.checkIn(entity.id);
}
}
}
/**
* 移除所有实体
*/
public removeAllEntities(): void {
// 收集所有实体ID用于回收
const idsToRecycle: number[] = [];
for (let i = this.buffer.length - 1; i >= 0; i--) {
idsToRecycle.push(this.buffer[i].id);
this.buffer[i].destroy();
}
// 批量回收ID
if (this._scene && this._scene.identifierPool) {
for (const id of idsToRecycle) {
this._scene.identifierPool.checkIn(id);
}
}
this.buffer.length = 0;
this._idToEntity.clear();
this._nameToEntities.clear();
this._entitiesToAdd.length = 0;
this._entitiesToRemove.length = 0;
}
/**
* 更新实体列表,处理延迟操作
*/
public updateLists(): void {
// 处理延迟添加的实体
if (this._entitiesToAdd.length > 0) {
for (const entity of this._entitiesToAdd) {
this.addImmediate(entity);
}
this._entitiesToAdd.length = 0;
}
// 处理延迟移除的实体
if (this._entitiesToRemove.length > 0) {
for (const entity of this._entitiesToRemove) {
this.removeImmediate(entity);
}
this._entitiesToRemove.length = 0;
}
}
/**
* 更新所有实体
*/
public update(): void {
this._isUpdating = true;
try {
for (let i = 0; i < this.buffer.length; i++) {
const entity = this.buffer[i];
if (entity.enabled && !entity.isDestroyed) {
entity.update();
}
}
} finally {
this._isUpdating = false;
}
// 处理延迟操作
this.updateLists();
}
/**
* 根据名称查找实体使用索引O(1)复杂度)
* @param name 实体名称
* @returns 找到的第一个实体或null
*/
public findEntity(name: string): Entity | null {
const entities = this._nameToEntities.get(name);
return entities && entities.length > 0 ? entities[0] : null;
}
/**
* 根据名称查找所有实体
* @param name 实体名称
* @returns 找到的所有实体数组
*/
public findEntitiesByName(name: string): Entity[] {
return this._nameToEntities.get(name) || [];
}
/**
* 根据ID查找实体使用索引O(1)复杂度)
* @param id 实体ID
* @returns 找到的实体或null
*/
public findEntityById(id: number): Entity | null {
return this._idToEntity.get(id) || null;
}
/**
* 根据标签查找实体
* @param tag 标签
* @returns 找到的所有实体数组
*/
public findEntitiesByTag(tag: number): Entity[] {
const result: Entity[] = [];
for (const entity of this.buffer) {
if (entity.tag === tag) {
result.push(entity);
}
}
return result;
}
/**
* 根据组件类型查找实体
* @param componentType 组件类型
* @returns 找到的所有实体数组
*/
public findEntitiesWithComponent<T extends Component>(componentType: new (...args: unknown[]) => T): Entity[] {
const result: Entity[] = [];
for (const entity of this.buffer) {
if (entity.hasComponent(componentType)) {
result.push(entity);
}
}
return result;
}
/**
* 批量操作:对所有实体执行指定操作
* @param action 要执行的操作
*/
public forEach(action: (entity: Entity) => void): void {
for (const entity of this.buffer) {
action(entity);
}
}
/**
* 批量操作:对符合条件的实体执行指定操作
* @param predicate 筛选条件
* @param action 要执行的操作
*/
public forEachWhere(predicate: (entity: Entity) => boolean, action: (entity: Entity) => void): void {
for (const entity of this.buffer) {
if (predicate(entity)) {
action(entity);
}
}
}
/**
* 更新名称索引
* @param entity 实体
* @param isAdd 是否为添加操作
*/
private updateNameIndex(entity: Entity, isAdd: boolean): void {
if (!entity.name) {
return;
}
if (isAdd) {
let entities = this._nameToEntities.get(entity.name);
if (!entities) {
entities = [];
this._nameToEntities.set(entity.name, entities);
}
entities.push(entity);
} else {
const entities = this._nameToEntities.get(entity.name);
if (entities) {
const index = entities.indexOf(entity);
if (index !== -1) {
entities.splice(index, 1);
// 如果数组为空,删除映射
if (entities.length === 0) {
this._nameToEntities.delete(entity.name);
}
}
}
}
}
/**
* 获取实体列表的统计信息
* @returns 统计信息
*/
public getStats(): {
totalEntities: number;
activeEntities: number;
pendingAdd: number;
pendingRemove: number;
nameIndexSize: number;
} {
let activeCount = 0;
for (const entity of this.buffer) {
if (entity.enabled && !entity.isDestroyed) {
activeCount++;
}
}
return {
totalEntities: this.buffer.length,
activeEntities: activeCount,
pendingAdd: this._entitiesToAdd.length,
pendingRemove: this._entitiesToRemove.length,
nameIndexSize: this._nameToEntities.size
};
}
}

View File

@@ -0,0 +1,111 @@
import { EntitySystem } from '../Systems/EntitySystem';
/**
* 实体处理器列表管理器
* 管理场景中的所有实体系统
*/
export class EntityProcessorList {
private _processors: EntitySystem[] = [];
private _isDirty = false;
/**
* 设置为脏状态,需要重新排序
*/
public setDirty(): void {
this._isDirty = true;
}
/**
* 添加实体处理器
* @param processor 要添加的处理器
*/
public add(processor: EntitySystem): void {
this._processors.push(processor);
this.setDirty();
}
/**
* 移除实体处理器
* @param processor 要移除的处理器
*/
public remove(processor: EntitySystem): void {
const index = this._processors.indexOf(processor);
if (index !== -1) {
this._processors.splice(index, 1);
}
}
/**
* 获取指定类型的处理器
* @param type 处理器类型
*/
public getProcessor<T extends EntitySystem>(type: new (...args: unknown[]) => T): T | null {
for (const processor of this._processors) {
if (processor instanceof type) {
return processor as T;
}
}
return null;
}
/**
* 开始处理
*
* 对所有处理器进行排序以确保正确的执行顺序。
*/
public begin(): void {
this.sortProcessors();
}
/**
* 结束处理
*/
public end(): void {
// 清理处理器
}
/**
* 更新所有处理器
*/
public update(): void {
this.sortProcessors();
for (const processor of this._processors) {
try {
processor.update();
} catch (error) {
console.error(`Error in processor ${processor.constructor.name}:`, error);
}
}
}
/**
* 后期更新所有处理器
*/
public lateUpdate(): void {
for (const processor of this._processors) {
processor.lateUpdate();
}
}
/**
* 排序处理器
*/
private sortProcessors(): void {
if (this._isDirty) {
this._processors.sort((a, b) => a.updateOrder - b.updateOrder);
this._isDirty = false;
}
}
/** 获取处理器列表 */
public get processors() {
return this._processors;
}
/** 获取处理器数量 */
public get count() {
return this._processors.length;
}
}

View File

@@ -0,0 +1,405 @@
/**
* 世代式ID池管理器
*
* 用于管理实体ID的分配和回收支持世代版本控制以防止悬空引用问题。
* 世代式ID由索引和版本组成当ID被回收时版本会递增确保旧引用失效。
*
* 支持动态扩展理论上可以支持到65535个索引16位每个索引65535个版本16位
* 总计可以处理超过42亿个独特的ID组合完全满足ECS大规模实体需求。
*
* @example
* ```typescript
* const pool = new IdentifierPool();
*
* // 分配ID
* const id = pool.checkOut(); // 例如: 65536 (版本1索引0)
*
* // 回收ID
* pool.checkIn(id);
*
* // 验证ID是否有效
* const isValid = pool.isValid(id); // false因为版本已递增
* ```
*/
export class IdentifierPool {
/**
* 下一个可用的索引
*/
private _nextAvailableIndex = 0;
/**
* 空闲的索引列表
*/
private _freeIndices: number[] = [];
/**
* 每个索引对应的世代版本
* 动态扩展的Map按需分配内存
*/
private _generations = new Map<number, number>();
/**
* 延迟回收队列
* 防止在同一帧内立即重用ID避免时序问题
*/
private _pendingRecycle: Array<{
index: number;
generation: number;
timestamp: number;
}> = [];
/**
* 延迟回收时间(毫秒)
*/
private _recycleDelay: number = 100;
/**
* 最大索引限制16位
* 这是框架设计选择16位索引 + 16位版本 = 32位ID确保高效位操作
* 不是硬件限制,而是性能和内存效率的权衡
*/
private static readonly MAX_INDEX = 0xFFFF; // 65535
/**
* 最大世代限制16位
*/
private static readonly MAX_GENERATION = 0xFFFF; // 65535
/**
* 内存扩展块大小
* 当需要更多内存时,一次性预分配的索引数量
*/
private _expansionBlockSize: number;
/**
* 统计信息
*/
private _stats = {
totalAllocated: 0,
totalRecycled: 0,
currentActive: 0,
memoryExpansions: 0
};
/**
* 构造函数
*
* @param recycleDelay 延迟回收时间毫秒默认为100ms
* @param expansionBlockSize 内存扩展块大小默认为1024
*/
constructor(recycleDelay: number = 100, expansionBlockSize: number = 1024) {
this._recycleDelay = recycleDelay;
this._expansionBlockSize = expansionBlockSize;
// 预分配第一个块的世代信息
this._preAllocateGenerations(0, this._expansionBlockSize);
}
/**
* 获取一个可用的ID
*
* 返回一个32位ID高16位为世代版本低16位为索引。
*
* @returns 新分配的实体ID
* @throws {Error} 当达到索引限制时抛出错误
*/
public checkOut(): number {
// 处理延迟回收队列
this._processDelayedRecycle();
let index: number;
if (this._freeIndices.length > 0) {
// 重用回收的索引
index = this._freeIndices.pop()!;
} else {
// 分配新索引
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
throw new Error(
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
`这意味着您已经分配了超过65535个不同的实体索引。` +
`这是16位索引设计的限制考虑优化实体回收策略或升级到64位ID设计。`
);
}
index = this._nextAvailableIndex++;
// 按需扩展世代存储
this._ensureGenerationCapacity(index);
}
const generation = this._generations.get(index) || 1;
this._stats.totalAllocated++;
this._stats.currentActive++;
return this._packId(index, generation);
}
/**
* 回收一个ID
*
* 验证ID的有效性后将其加入延迟回收队列。
* ID不会立即可重用而是在延迟时间后才真正回收。
*
* @param id 要回收的实体ID
* @returns 是否成功回收ID是否有效且未被重复回收
*/
public checkIn(id: number): boolean {
const index = this._unpackIndex(id);
const generation = this._unpackGeneration(id);
// 验证ID有效性
if (!this._isValidId(index, generation)) {
return false;
}
// 检查是否已经在待回收队列中
const alreadyPending = this._pendingRecycle.some(
item => item.index === index && item.generation === generation
);
if (alreadyPending) {
return false; // 已经在回收队列中,拒绝重复回收
}
// 加入延迟回收队列
this._pendingRecycle.push({
index,
generation,
timestamp: Date.now()
});
this._stats.currentActive--;
this._stats.totalRecycled++;
return true;
}
/**
* 验证ID是否有效
*
* 检查ID的索引和世代版本是否匹配当前状态。
*
* @param id 要验证的实体ID
* @returns ID是否有效
*/
public isValid(id: number): boolean {
const index = this._unpackIndex(id);
const generation = this._unpackGeneration(id);
return this._isValidId(index, generation);
}
/**
* 获取统计信息
*
* @returns 池的当前状态统计
*/
public getStats(): {
/** 已分配的总索引数 */
totalAllocated: number;
/** 总计回收次数 */
totalRecycled: number;
/** 当前活跃实体数 */
currentActive: number;
/** 当前空闲的索引数 */
currentlyFree: number;
/** 等待回收的ID数 */
pendingRecycle: number;
/** 理论最大实体数(设计限制) */
maxPossibleEntities: number;
/** 当前使用的最大索引 */
maxUsedIndex: number;
/** 内存使用(字节) */
memoryUsage: number;
/** 内存扩展次数 */
memoryExpansions: number;
/** 平均世代版本 */
averageGeneration: number;
/** 世代存储大小 */
generationStorageSize: number;
} {
// 计算平均世代版本
let totalGeneration = 0;
let generationCount = 0;
for (const [index, generation] of this._generations) {
if (index < this._nextAvailableIndex) {
totalGeneration += generation;
generationCount++;
}
}
const averageGeneration = generationCount > 0
? totalGeneration / generationCount
: 1;
return {
totalAllocated: this._stats.totalAllocated,
totalRecycled: this._stats.totalRecycled,
currentActive: this._stats.currentActive,
currentlyFree: this._freeIndices.length,
pendingRecycle: this._pendingRecycle.length,
maxPossibleEntities: IdentifierPool.MAX_INDEX + 1,
maxUsedIndex: this._nextAvailableIndex - 1,
memoryUsage: this._calculateMemoryUsage(),
memoryExpansions: this._stats.memoryExpansions,
averageGeneration: Math.round(averageGeneration * 100) / 100,
generationStorageSize: this._generations.size
};
}
/**
* 强制执行延迟回收处理
*
* 在某些情况下可能需要立即处理延迟回收队列,
* 比如内存压力大或者需要精确的统计信息时。
*/
public forceProcessDelayedRecycle(): void {
this._processDelayedRecycle(true);
}
/**
* 清理过期的延迟回收项
*
* 将超过延迟时间的回收项真正回收到空闲列表中。
*
* @param forceAll 是否强制处理所有延迟回收项
* @private
*/
private _processDelayedRecycle(forceAll: boolean = false): void {
if (this._pendingRecycle.length === 0) return;
const now = Date.now();
const readyToRecycle: typeof this._pendingRecycle = [];
const stillPending: typeof this._pendingRecycle = [];
// 分离已到期和未到期的项
for (const item of this._pendingRecycle) {
if (forceAll || now - item.timestamp >= this._recycleDelay) {
readyToRecycle.push(item);
} else {
stillPending.push(item);
}
}
// 处理到期的回收项
for (const item of readyToRecycle) {
// 再次验证ID有效性防止重复回收
if (this._isValidId(item.index, item.generation)) {
// 递增世代版本
let newGeneration = item.generation + 1;
// 防止世代版本溢出
if (newGeneration > IdentifierPool.MAX_GENERATION) {
newGeneration = 1; // 重置为1而不是0
}
this._generations.set(item.index, newGeneration);
// 添加到空闲列表
this._freeIndices.push(item.index);
}
}
// 更新待回收队列
this._pendingRecycle = stillPending;
}
/**
* 预分配世代信息
*
* @param startIndex 起始索引
* @param count 分配数量
* @private
*/
private _preAllocateGenerations(startIndex: number, count: number): void {
for (let i = 0; i < count; i++) {
const index = startIndex + i;
if (index <= IdentifierPool.MAX_INDEX) {
this._generations.set(index, 1);
}
}
this._stats.memoryExpansions++;
}
/**
* 确保指定索引的世代信息存在
*
* @param index 索引
* @private
*/
private _ensureGenerationCapacity(index: number): void {
if (!this._generations.has(index)) {
// 计算需要扩展的起始位置
const expansionStart = Math.floor(index / this._expansionBlockSize) * this._expansionBlockSize;
// 预分配一个块
this._preAllocateGenerations(expansionStart, this._expansionBlockSize);
}
}
/**
* 计算内存使用量
*
* @returns 内存使用字节数
* @private
*/
private _calculateMemoryUsage(): number {
const generationMapSize = this._generations.size * 16; // Map overhead + number pair
const freeIndicesSize = this._freeIndices.length * 8;
const pendingRecycleSize = this._pendingRecycle.length * 32;
return generationMapSize + freeIndicesSize + pendingRecycleSize;
}
/**
* 打包索引和世代为32位ID
*
* @param index 索引16位
* @param generation 世代版本16位
* @returns 打包后的32位ID
* @private
*/
private _packId(index: number, generation: number): number {
return (generation << 16) | index;
}
/**
* 从ID中解包索引
*
* @param id 32位ID
* @returns 索引部分16位
* @private
*/
private _unpackIndex(id: number): number {
return id & 0xFFFF;
}
/**
* 从ID中解包世代版本
*
* @param id 32位ID
* @returns 世代版本部分16位
* @private
*/
private _unpackGeneration(id: number): number {
return (id >>> 16) & 0xFFFF;
}
/**
* 内部ID有效性检查
*
* @param index 索引
* @param generation 世代版本
* @returns 是否有效
* @private
*/
private _isValidId(index: number, generation: number): boolean {
if (index < 0 || index >= this._nextAvailableIndex) {
return false;
}
const currentGeneration = this._generations.get(index);
return currentGeneration !== undefined && currentGeneration === generation;
}
}

View File

@@ -0,0 +1,295 @@
import { ComponentType } from '../Core/ComponentStorage';
/**
* 查询条件类型
*/
interface QueryCondition {
all: ComponentType[];
any: ComponentType[];
none: ComponentType[];
tag?: number; // 按标签查询
name?: string; // 按名称查询
component?: ComponentType; // 单组件查询
}
/**
* 实体匹配条件描述符
*
* 用于描述实体查询条件,不执行实际查询
*
* @example
* ```typescript
* const matcher = Matcher.all(Position, Velocity)
* .any(Health, Shield)
* .none(Dead);
*
* // 获取查询条件
* const condition = matcher.getCondition();
* ```
*/
export class Matcher {
private readonly condition: QueryCondition = {
all: [],
any: [],
none: []
};
private constructor() {
// 私有构造函数,只能通过静态方法创建
}
/**
* 创建匹配器,要求所有指定的组件
* @param types 组件类型
*/
public static all(...types: ComponentType[]): Matcher {
const matcher = new Matcher();
return matcher.all(...types);
}
/**
* 创建匹配器,要求至少一个指定的组件
* @param types 组件类型
*/
public static any(...types: ComponentType[]): Matcher {
const matcher = new Matcher();
return matcher.any(...types);
}
/**
* 创建匹配器,排除指定的组件
* @param types 组件类型
*/
public static none(...types: ComponentType[]): Matcher {
const matcher = new Matcher();
return matcher.none(...types);
}
/**
* 创建按标签查询的匙配器
* @param tag 标签值
*/
public static byTag(tag: number): Matcher {
const matcher = new Matcher();
return matcher.withTag(tag);
}
/**
* 创建按名称查询的匙配器
* @param name 实体名称
*/
public static byName(name: string): Matcher {
const matcher = new Matcher();
return matcher.withName(name);
}
/**
* 创建单组件查询的匙配器
* @param componentType 组件类型
*/
public static byComponent(componentType: ComponentType): Matcher {
const matcher = new Matcher();
return matcher.withComponent(componentType);
}
/**
* 创建复杂查询构建器
*/
public static complex(): Matcher {
return new Matcher();
}
/**
* 创建空匙配器(向后兼容)
*/
public static empty(): Matcher {
return new Matcher();
}
/**
* 必须包含所有指定组件
* @param types 组件类型
*/
public all(...types: ComponentType[]): Matcher {
this.condition.all.push(...types);
return this;
}
/**
* 必须包含至少一个指定组件
* @param types 组件类型
*/
public any(...types: ComponentType[]): Matcher {
this.condition.any.push(...types);
return this;
}
/**
* 不能包含任何指定组件
* @param types 组件类型
*/
public none(...types: ComponentType[]): Matcher {
this.condition.none.push(...types);
return this;
}
/**
* 排除指定组件(别名方法)
* @param types 组件类型
*/
public exclude(...types: ComponentType[]): Matcher {
return this.none(...types);
}
/**
* 至少包含其中之一(别名方法)
* @param types 组件类型
*/
public one(...types: ComponentType[]): Matcher {
return this.any(...types);
}
/**
* 按标签查询
* @param tag 标签值
*/
public withTag(tag: number): Matcher {
this.condition.tag = tag;
return this;
}
/**
* 按名称查询
* @param name 实体名称
*/
public withName(name: string): Matcher {
this.condition.name = name;
return this;
}
/**
* 单组件查询
* @param componentType 组件类型
*/
public withComponent(componentType: ComponentType): Matcher {
this.condition.component = componentType;
return this;
}
/**
* 移除标签条件
*/
public withoutTag(): Matcher {
delete this.condition.tag;
return this;
}
/**
* 移除名称条件
*/
public withoutName(): Matcher {
delete this.condition.name;
return this;
}
/**
* 移除单组件条件
*/
public withoutComponent(): Matcher {
delete this.condition.component;
return this;
}
/**
* 获取查询条件(只读)
*/
public getCondition(): Readonly<QueryCondition> {
return {
all: [...this.condition.all],
any: [...this.condition.any],
none: [...this.condition.none],
tag: this.condition.tag,
name: this.condition.name,
component: this.condition.component
};
}
/**
* 检查是否为空条件
*/
public isEmpty(): boolean {
return this.condition.all.length === 0 &&
this.condition.any.length === 0 &&
this.condition.none.length === 0 &&
this.condition.tag === undefined &&
this.condition.name === undefined &&
this.condition.component === undefined;
}
/**
* 重置所有条件
*/
public reset(): Matcher {
this.condition.all.length = 0;
this.condition.any.length = 0;
this.condition.none.length = 0;
delete this.condition.tag;
delete this.condition.name;
delete this.condition.component;
return this;
}
/**
* 克隆匹配器
*/
public clone(): Matcher {
const cloned = new Matcher();
cloned.condition.all.push(...this.condition.all);
cloned.condition.any.push(...this.condition.any);
cloned.condition.none.push(...this.condition.none);
if (this.condition.tag !== undefined) {
cloned.condition.tag = this.condition.tag;
}
if (this.condition.name !== undefined) {
cloned.condition.name = this.condition.name;
}
if (this.condition.component !== undefined) {
cloned.condition.component = this.condition.component;
}
return cloned;
}
/**
* 字符串表示
*/
public toString(): string {
const parts: string[] = [];
if (this.condition.all.length > 0) {
parts.push(`all(${this.condition.all.map(t => t.name).join(', ')})`);
}
if (this.condition.any.length > 0) {
parts.push(`any(${this.condition.any.map(t => t.name).join(', ')})`);
}
if (this.condition.none.length > 0) {
parts.push(`none(${this.condition.none.map(t => t.name).join(', ')})`);
}
if (this.condition.tag !== undefined) {
parts.push(`tag(${this.condition.tag})`);
}
if (this.condition.name !== undefined) {
parts.push(`name(${this.condition.name})`);
}
if (this.condition.component !== undefined) {
parts.push(`component(${this.condition.component.name})`);
}
return `Matcher[${parts.join(' & ')}]`;
}
}

View File

@@ -0,0 +1,8 @@
// ECS工具类导出
export { EntityList } from './EntityList';
export { EntityProcessorList } from './EntityProcessorList';
export { IdentifierPool } from './IdentifierPool';
export { Matcher } from './Matcher';
export { Bits } from './Bits';
export { ComponentTypeManager } from './ComponentTypeManager';
export { BigIntFactory } from './BigIntCompatibility';