feat(core): 启用 TypeScript 最严格的类型检查 (#199)
* feat(core): 启用 TypeScript 最严格的类型检查 * ci: 配置 Codecov 以适应类型安全改进 * fix(core): 修复 CodeQL 安全警告 * fix(core): eslint.config.mjs
This commit is contained in:
@@ -141,7 +141,7 @@ export class ArchetypeSystem {
|
||||
}
|
||||
|
||||
if (componentTypes.length === 1) {
|
||||
const archetypes = this._componentToArchetypes.get(componentTypes[0]);
|
||||
const archetypes = this._componentToArchetypes.get(componentTypes[0]!);
|
||||
if (archetypes) {
|
||||
for (const archetype of archetypes) {
|
||||
matchingArchetypes.push(archetype);
|
||||
|
||||
@@ -9,7 +9,6 @@ export class ComponentPool<T extends Component> {
|
||||
private resetFn?: (component: T) => void;
|
||||
private maxSize: number;
|
||||
private minSize: number;
|
||||
private growthFactor: number;
|
||||
|
||||
private stats = {
|
||||
totalCreated: 0,
|
||||
@@ -21,14 +20,14 @@ export class ComponentPool<T extends Component> {
|
||||
createFn: () => T,
|
||||
resetFn?: (component: T) => void,
|
||||
maxSize: number = 1000,
|
||||
minSize: number = 10,
|
||||
growthFactor: number = 1.5
|
||||
minSize: number = 10
|
||||
) {
|
||||
this.createFn = createFn;
|
||||
this.resetFn = resetFn;
|
||||
if (resetFn) {
|
||||
this.resetFn = resetFn;
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
this.minSize = Math.max(1, minSize);
|
||||
this.growthFactor = Math.max(1.1, growthFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +143,7 @@ interface ComponentUsageTracker {
|
||||
*/
|
||||
export class ComponentPoolManager {
|
||||
private static instance: ComponentPoolManager;
|
||||
private pools = new Map<string, ComponentPool<any>>();
|
||||
private pools = new Map<string, ComponentPool<Component>>();
|
||||
private usageTracker = new Map<string, ComponentUsageTracker>();
|
||||
|
||||
private autoCleanupInterval = 60000;
|
||||
@@ -169,7 +168,7 @@ export class ComponentPoolManager {
|
||||
maxSize?: number,
|
||||
minSize?: number
|
||||
): void {
|
||||
this.pools.set(componentName, new ComponentPool(createFn, resetFn, maxSize, minSize));
|
||||
this.pools.set(componentName, new ComponentPool(createFn, resetFn, maxSize, minSize) as unknown as ComponentPool<Component>);
|
||||
|
||||
this.usageTracker.set(componentName, {
|
||||
createCount: 0,
|
||||
@@ -186,7 +185,7 @@ export class ComponentPoolManager {
|
||||
|
||||
this.trackUsage(componentName, 'create');
|
||||
|
||||
return pool ? pool.acquire() : null;
|
||||
return pool ? (pool.acquire() as T) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,8 +287,16 @@ export class ComponentPoolManager {
|
||||
/**
|
||||
* 获取全局统计信息
|
||||
*/
|
||||
getGlobalStats() {
|
||||
const stats: any[] = [];
|
||||
getGlobalStats(): Array<{
|
||||
componentName: string;
|
||||
poolStats: ReturnType<ComponentPool<Component>['getStats']>;
|
||||
usage: ComponentUsageTracker | undefined;
|
||||
}> {
|
||||
const stats: Array<{
|
||||
componentName: string;
|
||||
poolStats: ReturnType<ComponentPool<Component>['getStats']>;
|
||||
usage: ComponentUsageTracker | undefined;
|
||||
}> = [];
|
||||
|
||||
for (const [name, pool] of this.pools.entries()) {
|
||||
stats.push({
|
||||
|
||||
@@ -53,7 +53,7 @@ export class ComponentStorage<T extends Component> {
|
||||
*/
|
||||
public getComponent(entityId: number): T | null {
|
||||
const index = this.entityToIndex.get(entityId);
|
||||
return index !== undefined ? this.dense[index] : null;
|
||||
return index !== undefined ? this.dense[index]! : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,17 +76,17 @@ export class ComponentStorage<T extends Component> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const component = this.dense[index];
|
||||
const component = this.dense[index]!;
|
||||
const lastIndex = this.dense.length - 1;
|
||||
|
||||
if (index !== lastIndex) {
|
||||
// 将末尾元素交换到要删除的位置
|
||||
const lastComponent = this.dense[lastIndex];
|
||||
const lastEntityId = this.entityIds[lastIndex];
|
||||
|
||||
const lastComponent = this.dense[lastIndex]!;
|
||||
const lastEntityId = this.entityIds[lastIndex]!;
|
||||
|
||||
this.dense[index] = lastComponent;
|
||||
this.entityIds[index] = lastEntityId;
|
||||
|
||||
|
||||
// 更新被交换元素的映射
|
||||
this.entityToIndex.set(lastEntityId, index);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export class ComponentStorage<T extends Component> {
|
||||
*/
|
||||
public forEach(callback: (component: T, entityId: number, index: number) => void): void {
|
||||
for (let i = 0; i < this.dense.length; i++) {
|
||||
callback(this.dense[i], this.entityIds[i], i);
|
||||
callback(this.dense[i]!, this.entityIds[i]!, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ export class ComponentStorage<T extends Component> {
|
||||
*/
|
||||
export class ComponentStorageManager {
|
||||
private static readonly _logger = createLogger('ComponentStorage');
|
||||
private storages = new Map<Function, ComponentStorage<any> | SoAStorage<any>>();
|
||||
private storages = new Map<Function, ComponentStorage<Component> | SoAStorage<Component>>();
|
||||
|
||||
/**
|
||||
* 检查组件类型是否启用SoA存储
|
||||
@@ -262,11 +262,11 @@ export class ComponentStorageManager {
|
||||
*/
|
||||
public getStorage<T extends Component>(componentType: ComponentType<T>): ComponentStorage<T> | SoAStorage<T> {
|
||||
let storage = this.storages.get(componentType);
|
||||
|
||||
|
||||
if (!storage) {
|
||||
// 检查是否启用SoA优化
|
||||
const enableSoA = (componentType as any).__enableSoA;
|
||||
|
||||
const enableSoA = (componentType as unknown as { __enableSoA?: boolean }).__enableSoA;
|
||||
|
||||
if (enableSoA) {
|
||||
// 使用SoA优化存储
|
||||
storage = new SoAStorage(componentType);
|
||||
@@ -275,11 +275,11 @@ export class ComponentStorageManager {
|
||||
// 默认使用原始存储
|
||||
storage = new ComponentStorage(componentType);
|
||||
}
|
||||
|
||||
|
||||
this.storages.set(componentType, storage);
|
||||
}
|
||||
|
||||
return storage;
|
||||
|
||||
return storage as ComponentStorage<T> | SoAStorage<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +301,7 @@ export class ComponentStorageManager {
|
||||
*/
|
||||
public getComponent<T extends Component>(entityId: number, componentType: ComponentType<T>): T | null {
|
||||
const storage = this.storages.get(componentType);
|
||||
return storage ? storage.getComponent(entityId) : null;
|
||||
return storage ? (storage as ComponentStorage<T> | SoAStorage<T>).getComponent(entityId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,7 +323,7 @@ export class ComponentStorageManager {
|
||||
*/
|
||||
public removeComponent<T extends Component>(entityId: number, componentType: ComponentType<T>): T | null {
|
||||
const storage = this.storages.get(componentType);
|
||||
return storage ? storage.removeComponent(entityId) : null;
|
||||
return storage ? (storage as ComponentStorage<T> | SoAStorage<T>).removeComponent(entityId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,8 +358,8 @@ export class ComponentStorageManager {
|
||||
/**
|
||||
* 获取所有存储器的统计信息
|
||||
*/
|
||||
public getAllStats(): Map<string, any> {
|
||||
const stats = new Map<string, any>();
|
||||
public getAllStats(): Map<string, { totalSlots: number; usedSlots: number; freeSlots: number; fragmentation: number }> {
|
||||
const stats = new Map<string, { totalSlots: number; usedSlots: number; freeSlots: number; fragmentation: number }>();
|
||||
|
||||
for (const [componentType, storage] of this.storages.entries()) {
|
||||
const typeName = getComponentTypeName(componentType as ComponentType);
|
||||
|
||||
@@ -15,11 +15,10 @@ import {
|
||||
EventListenerConfig,
|
||||
EventStats
|
||||
} from './EventSystem';
|
||||
import {
|
||||
ECSEventType,
|
||||
EventPriority,
|
||||
EVENT_TYPES,
|
||||
EventTypeValidator
|
||||
import {
|
||||
ECSEventType,
|
||||
EventPriority,
|
||||
EventTypeValidator
|
||||
} from '../CoreEvents';
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,7 +77,7 @@ export class ECSFluentAPI {
|
||||
*/
|
||||
public findFirst(...componentTypes: ComponentType[]): Entity | null {
|
||||
const result = this.querySystem.queryAll(...componentTypes);
|
||||
return result.entities.length > 0 ? result.entities[0] : null;
|
||||
return result.entities.length > 0 ? result.entities[0]! : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import type { Entity } from '../../Entity';
|
||||
import type { ComponentConstructor, ComponentInstance, ComponentTypeMap } from '../../../Types/TypeHelpers';
|
||||
import type { ComponentConstructor } from '../../../Types/TypeHelpers';
|
||||
import { Matcher, type QueryCondition } from '../../Utils/Matcher';
|
||||
|
||||
/**
|
||||
@@ -179,8 +179,12 @@ export class TypedQueryBuilder<
|
||||
this._all = (all || []) as TAll;
|
||||
this._any = (any || []) as TAny;
|
||||
this._none = (none || []) as TNone;
|
||||
this._tag = tag;
|
||||
this._name = name;
|
||||
if (tag !== undefined) {
|
||||
this._tag = tag;
|
||||
}
|
||||
if (name !== undefined) {
|
||||
this._name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,8 +326,8 @@ export class TypedQueryBuilder<
|
||||
all: [...this._all] as ComponentConstructor[],
|
||||
any: [...this._any] as ComponentConstructor[],
|
||||
none: [...this._none] as ComponentConstructor[],
|
||||
tag: this._tag,
|
||||
name: this._name
|
||||
...(this._tag !== undefined && { tag: this._tag }),
|
||||
...(this._name !== undefined && { name: this._name })
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -66,9 +66,6 @@ export class QuerySystem {
|
||||
dirtyChecks: 0
|
||||
};
|
||||
|
||||
private resultArrayPool: Entity[][] = [];
|
||||
private poolMaxSize = 50;
|
||||
|
||||
constructor() {
|
||||
this.entityIndex = {
|
||||
byTag: new Map(),
|
||||
@@ -78,20 +75,6 @@ export class QuerySystem {
|
||||
this.archetypeSystem = new ArchetypeSystem();
|
||||
}
|
||||
|
||||
private acquireResultArray(): Entity[] {
|
||||
if (this.resultArrayPool.length > 0) {
|
||||
return this.resultArrayPool.pop()!;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private releaseResultArray(array: Entity[]): void {
|
||||
if (this.resultArrayPool.length < this.poolMaxSize) {
|
||||
array.length = 0;
|
||||
this.resultArrayPool.push(array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体列表并重建索引
|
||||
*
|
||||
@@ -378,30 +361,6 @@ export class QuerySystem {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 多组件查询算法
|
||||
*
|
||||
* 针对多组件查询场景的高效算法实现。
|
||||
* 通过选择最小的组件集合作为起点,减少需要检查的实体数量。
|
||||
*
|
||||
* @param componentTypes 组件类型列表
|
||||
* @returns 匹配的实体列表
|
||||
*/
|
||||
private queryMultipleComponents(componentTypes: ComponentType[]): Entity[] {
|
||||
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'AND');
|
||||
const result: Entity[] = [];
|
||||
|
||||
for (const archetype of archetypeResult.archetypes) {
|
||||
for (const entity of archetype.entities) {
|
||||
result.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 查询包含任意指定组件的实体
|
||||
*
|
||||
@@ -715,7 +674,7 @@ export class QuerySystem {
|
||||
private generateCacheKey(prefix: string, componentTypes: ComponentType[]): string {
|
||||
// 快速路径:单组件查询
|
||||
if (componentTypes.length === 1) {
|
||||
const name = getComponentTypeName(componentTypes[0]);
|
||||
const name = getComponentTypeName(componentTypes[0]!);
|
||||
return `${prefix}:${name}`;
|
||||
}
|
||||
|
||||
@@ -1258,7 +1217,7 @@ export class QueryBuilder {
|
||||
|
||||
// 简化实现:目前只支持单一条件
|
||||
if (this.conditions.length === 1) {
|
||||
const condition = this.conditions[0];
|
||||
const condition = this.conditions[0]!;
|
||||
switch (condition.type) {
|
||||
case QueryConditionType.ALL:
|
||||
return this.querySystem.queryAll(...condition.componentTypes);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Component } from '../Component';
|
||||
import type { Entity } from '../Entity';
|
||||
import type { IScene } from '../IScene';
|
||||
import { createLogger } from '../../Utils/Logger';
|
||||
|
||||
const logger = createLogger('ReferenceTracker');
|
||||
|
||||
/**
|
||||
* WeakRef 接口定义
|
||||
@@ -98,11 +95,6 @@ export class ReferenceTracker {
|
||||
*/
|
||||
private _references: Map<number, Set<EntityRefRecord>> = new Map();
|
||||
|
||||
/**
|
||||
* 当前Scene的引用
|
||||
*/
|
||||
private _scene: IWeakRef<IScene> | null = null;
|
||||
|
||||
/**
|
||||
* 注册Entity引用
|
||||
*
|
||||
@@ -272,15 +264,6 @@ export class ReferenceTracker {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Scene引用
|
||||
*
|
||||
* @param scene Scene实例
|
||||
*/
|
||||
public setScene(scene: IScene): void {
|
||||
this._scene = new WeakRefImpl(scene);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册Entity到Scene的映射
|
||||
*
|
||||
|
||||
@@ -463,7 +463,7 @@ export class SoAStorage<T extends Component> {
|
||||
}
|
||||
|
||||
private updateComponentAtIndex(index: number, component: T): void {
|
||||
const entityId = this.indexToEntity[index];
|
||||
const entityId = this.indexToEntity[index]!;
|
||||
const complexFieldMap = new Map<string, any>();
|
||||
const highPrecisionFields = (this.type as any).__highPrecisionFields || new Set();
|
||||
const serializeMapFields = (this.type as any).__serializeMapFields || new Set();
|
||||
@@ -802,8 +802,11 @@ export class SoAStorage<T extends Component> {
|
||||
const newIndexToEntity: number[] = [];
|
||||
|
||||
for (let newIndex = 0; newIndex < activeEntries.length; newIndex++) {
|
||||
const [entityId, oldIndex] = activeEntries[newIndex];
|
||||
|
||||
const entry = activeEntries[newIndex];
|
||||
if (!entry) continue;
|
||||
|
||||
const [entityId, oldIndex] = entry;
|
||||
|
||||
newEntityToIndex.set(entityId, newIndex);
|
||||
newIndexToEntity[newIndex] = entityId;
|
||||
|
||||
@@ -811,17 +814,26 @@ export class SoAStorage<T extends Component> {
|
||||
if (newIndex !== oldIndex) {
|
||||
// 移动数值字段
|
||||
for (const [, array] of this.fields.entries()) {
|
||||
array[newIndex] = array[oldIndex];
|
||||
const value = array[oldIndex];
|
||||
if (value !== undefined) {
|
||||
array[newIndex] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 移动字符串字段
|
||||
for (const [, stringArray] of this.stringFields.entries()) {
|
||||
stringArray[newIndex] = stringArray[oldIndex];
|
||||
const value = stringArray[oldIndex];
|
||||
if (value !== undefined) {
|
||||
stringArray[newIndex] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 移动序列化字段
|
||||
for (const [, serializedArray] of this.serializedFields.entries()) {
|
||||
serializedArray[newIndex] = serializedArray[oldIndex];
|
||||
const value = serializedArray[oldIndex];
|
||||
if (value !== undefined) {
|
||||
serializedArray[newIndex] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import { ComponentPoolManager } from './Core/ComponentPool';
|
||||
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
|
||||
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
|
||||
import { createInstance, isInjectable, injectProperties } from '../Core/DI';
|
||||
import { isUpdatable, getUpdatableMetadata } from '../Core/DI/Decorators';
|
||||
import { createLogger } from '../Utils/Logger';
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,11 +8,24 @@ import { Component } from '../Component';
|
||||
import { ComponentType } from '../Core/ComponentStorage';
|
||||
import { getComponentTypeName } from '../Decorators';
|
||||
import {
|
||||
getSerializationMetadata,
|
||||
isSerializable,
|
||||
SerializationMetadata
|
||||
getSerializationMetadata
|
||||
} from './SerializationDecorators';
|
||||
|
||||
/**
|
||||
* 可序列化的值类型
|
||||
*/
|
||||
export type SerializableValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| undefined
|
||||
| SerializableValue[]
|
||||
| { [key: string]: SerializableValue }
|
||||
| { __type: 'Date'; value: string }
|
||||
| { __type: 'Map'; value: Array<[SerializableValue, SerializableValue]> }
|
||||
| { __type: 'Set'; value: SerializableValue[] };
|
||||
|
||||
/**
|
||||
* 序列化后的组件数据
|
||||
*/
|
||||
@@ -30,7 +43,7 @@ export interface SerializedComponent {
|
||||
/**
|
||||
* 组件数据
|
||||
*/
|
||||
data: Record<string, any>;
|
||||
data: Record<string, SerializableValue>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,12 +66,12 @@ export class ComponentSerializer {
|
||||
|
||||
const componentType = component.constructor as ComponentType;
|
||||
const typeName = metadata.options.typeId || getComponentTypeName(componentType);
|
||||
const data: Record<string, any> = {};
|
||||
const data: Record<string, SerializableValue> = {};
|
||||
|
||||
// 序列化标记的字段
|
||||
for (const [fieldName, options] of metadata.fields) {
|
||||
const fieldKey = typeof fieldName === 'symbol' ? fieldName.toString() : fieldName;
|
||||
const value = (component as any)[fieldName];
|
||||
const value = (component as unknown as Record<string | symbol, SerializableValue>)[fieldName];
|
||||
|
||||
// 跳过忽略的字段
|
||||
if (metadata.ignoredFields.has(fieldName)) {
|
||||
@@ -125,7 +138,7 @@ export class ComponentSerializer {
|
||||
? options.deserializer(serializedValue)
|
||||
: this.deserializeValue(serializedValue);
|
||||
|
||||
(component as any)[fieldName] = value;
|
||||
(component as unknown as Record<string | symbol, SerializableValue>)[fieldName] = value;
|
||||
}
|
||||
|
||||
return component;
|
||||
@@ -178,7 +191,7 @@ export class ComponentSerializer {
|
||||
*
|
||||
* 处理基本类型、数组、对象等的序列化
|
||||
*/
|
||||
private static serializeValue(value: any): any {
|
||||
private static serializeValue(value: SerializableValue): SerializableValue {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
@@ -219,11 +232,12 @@ export class ComponentSerializer {
|
||||
}
|
||||
|
||||
// 普通对象
|
||||
if (type === 'object') {
|
||||
const result: Record<string, any> = {};
|
||||
for (const key in value) {
|
||||
if (value.hasOwnProperty(key)) {
|
||||
result[key] = this.serializeValue(value[key]);
|
||||
if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {
|
||||
const result: Record<string, SerializableValue> = {};
|
||||
const obj = value as Record<string, SerializableValue>;
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
result[key] = this.serializeValue(obj[key]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -236,7 +250,7 @@ export class ComponentSerializer {
|
||||
/**
|
||||
* 默认值反序列化
|
||||
*/
|
||||
private static deserializeValue(value: any): any {
|
||||
private static deserializeValue(value: SerializableValue): SerializableValue {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
@@ -248,14 +262,15 @@ export class ComponentSerializer {
|
||||
}
|
||||
|
||||
// 处理特殊类型标记
|
||||
if (type === 'object' && value.__type) {
|
||||
switch (value.__type) {
|
||||
if (type === 'object' && typeof value === 'object' && '__type' in value) {
|
||||
const typedValue = value as { __type: string; value: SerializableValue };
|
||||
switch (typedValue.__type) {
|
||||
case 'Date':
|
||||
return new Date(value.value);
|
||||
return { __type: 'Date', value: typeof typedValue.value === 'string' ? typedValue.value : String(typedValue.value) };
|
||||
case 'Map':
|
||||
return new Map(value.value);
|
||||
return { __type: 'Map', value: typedValue.value as Array<[SerializableValue, SerializableValue]> };
|
||||
case 'Set':
|
||||
return new Set(value.value);
|
||||
return { __type: 'Set', value: typedValue.value as SerializableValue[] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,11 +280,12 @@ export class ComponentSerializer {
|
||||
}
|
||||
|
||||
// 普通对象
|
||||
if (type === 'object') {
|
||||
const result: Record<string, any> = {};
|
||||
for (const key in value) {
|
||||
if (value.hasOwnProperty(key)) {
|
||||
result[key] = this.deserializeValue(value[key]);
|
||||
if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {
|
||||
const result: Record<string, SerializableValue> = {};
|
||||
const obj = value as Record<string, SerializableValue>;
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
result[key] = this.deserializeValue(obj[key]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import { Entity } from '../Entity';
|
||||
import { Component } from '../Component';
|
||||
import { ComponentType } from '../Core/ComponentStorage';
|
||||
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
||||
import { IScene } from '../IScene';
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import type { IScene } from '../IScene';
|
||||
import { Entity } from '../Entity';
|
||||
import { Component } from '../Component';
|
||||
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
||||
import { SerializedEntity } from './EntitySerializer';
|
||||
import { ComponentType } from '../Core/ComponentStorage';
|
||||
@@ -204,7 +203,7 @@ export class IncrementalSerializer {
|
||||
active: entity.active,
|
||||
enabled: entity.enabled,
|
||||
updateOrder: entity.updateOrder,
|
||||
parentId: entity.parent?.id
|
||||
...(entity.parent && { parentId: entity.parent.id })
|
||||
});
|
||||
|
||||
// 快照组件
|
||||
@@ -286,7 +285,7 @@ export class IncrementalSerializer {
|
||||
active: entity.active,
|
||||
enabled: entity.enabled,
|
||||
updateOrder: entity.updateOrder,
|
||||
parentId: entity.parent?.id,
|
||||
...(entity.parent && { parentId: entity.parent.id }),
|
||||
components: [],
|
||||
children: []
|
||||
}
|
||||
@@ -325,7 +324,7 @@ export class IncrementalSerializer {
|
||||
active: entity.active,
|
||||
enabled: entity.enabled,
|
||||
updateOrder: entity.updateOrder,
|
||||
parentId: entity.parent?.id
|
||||
...(entity.parent && { parentId: entity.parent.id })
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import type { IScene } from '../IScene';
|
||||
import { Entity } from '../Entity';
|
||||
import { Component } from '../Component';
|
||||
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
|
||||
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
|
||||
import { getComponentTypeName } from '../Decorators';
|
||||
@@ -514,7 +513,7 @@ export class SceneSerializer {
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
version: data.version,
|
||||
errors: errors.length > 0 ? errors : undefined
|
||||
...(errors.length > 0 && { errors })
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
@@ -543,7 +542,7 @@ export class SceneSerializer {
|
||||
return {
|
||||
name: data.name,
|
||||
version: data.version,
|
||||
timestamp: data.timestamp,
|
||||
...(data.timestamp !== undefined && { timestamp: data.timestamp }),
|
||||
entityCount: data.metadata?.entityCount || data.entities.length,
|
||||
componentTypeCount: data.componentTypeRegistry.length
|
||||
};
|
||||
|
||||
@@ -63,7 +63,7 @@ export class VersionMigrationManager {
|
||||
public static registerComponentMigration(
|
||||
componentType: string,
|
||||
fromVersion: number,
|
||||
toVersion: number,
|
||||
_toVersion: number,
|
||||
migration: ComponentMigrationFunction
|
||||
): void {
|
||||
if (!this.componentMigrations.has(componentType)) {
|
||||
@@ -98,7 +98,7 @@ export class VersionMigrationManager {
|
||||
*/
|
||||
public static registerSceneMigration(
|
||||
fromVersion: number,
|
||||
toVersion: number,
|
||||
_toVersion: number,
|
||||
migration: SceneMigrationFunction
|
||||
): void {
|
||||
this.sceneMigrations.set(fromVersion, migration);
|
||||
|
||||
@@ -65,7 +65,7 @@ interface EventListenerRecord {
|
||||
* ```
|
||||
*/
|
||||
export abstract class EntitySystem<
|
||||
TComponents extends readonly ComponentConstructor[] = []
|
||||
_TComponents extends readonly ComponentConstructor[] = []
|
||||
> implements ISystemBase, IService {
|
||||
private _updateOrder: number;
|
||||
private _enabled: boolean;
|
||||
@@ -83,7 +83,6 @@ export abstract class EntitySystem<
|
||||
*/
|
||||
private _entityIdMap: Map<number, Entity> | null;
|
||||
private _entityIdMapVersion: number;
|
||||
private _entityIdMapSize: number;
|
||||
|
||||
/**
|
||||
* 统一的实体缓存管理器
|
||||
@@ -158,7 +157,6 @@ export abstract class EntitySystem<
|
||||
|
||||
this._entityIdMap = null;
|
||||
this._entityIdMapVersion = -1;
|
||||
this._entityIdMapSize = 0;
|
||||
|
||||
// 初始化logger
|
||||
this.logger = createLogger(this.getLoggerName());
|
||||
@@ -281,7 +279,6 @@ export abstract class EntitySystem<
|
||||
// 清理实体ID映射缓存
|
||||
this._entityIdMap = null;
|
||||
this._entityIdMapVersion = -1;
|
||||
this._entityIdMapSize = 0;
|
||||
|
||||
// 清理所有事件监听器
|
||||
// 调用框架销毁方法
|
||||
@@ -425,7 +422,7 @@ export abstract class EntitySystem<
|
||||
const idSet = new Set<number>();
|
||||
|
||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||
idSet.add(entities[i].id | 0);
|
||||
idSet.add(entities[i]!.id | 0);
|
||||
}
|
||||
return idSet;
|
||||
}
|
||||
@@ -497,13 +494,12 @@ export abstract class EntitySystem<
|
||||
|
||||
const len = allEntities.length;
|
||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||
const entity = allEntities[i];
|
||||
const entity = allEntities[i]!;
|
||||
entityMap.set(entity.id | 0, entity);
|
||||
}
|
||||
|
||||
this._entityIdMap = entityMap;
|
||||
this._entityIdMapVersion = version;
|
||||
this._entityIdMapSize = len;
|
||||
|
||||
return entityMap;
|
||||
}
|
||||
@@ -608,7 +604,7 @@ export abstract class EntitySystem<
|
||||
*
|
||||
* @param entities 要处理的实体列表
|
||||
*/
|
||||
protected process(entities: readonly Entity[]): void {
|
||||
protected process(_entities: readonly Entity[]): void {
|
||||
// 子类必须实现此方法
|
||||
}
|
||||
|
||||
@@ -720,7 +716,7 @@ export abstract class EntitySystem<
|
||||
*
|
||||
* @param entity 被添加的实体
|
||||
*/
|
||||
protected onAdded(entity: Entity): void {
|
||||
protected onAdded(_entity: Entity): void {
|
||||
// 子类可以重写此方法
|
||||
}
|
||||
|
||||
@@ -731,7 +727,7 @@ export abstract class EntitySystem<
|
||||
*
|
||||
* @param entity 被移除的实体
|
||||
*/
|
||||
protected onRemoved(entity: Entity): void {
|
||||
protected onRemoved(_entity: Entity): void {
|
||||
// 子类可以重写此方法
|
||||
}
|
||||
|
||||
@@ -812,6 +808,7 @@ export abstract class EntitySystem<
|
||||
|
||||
if (listenerIndex >= 0) {
|
||||
const listener = this._eventListeners[listenerIndex];
|
||||
if (!listener) return;
|
||||
|
||||
// 从事件系统中移除
|
||||
listener.eventSystem.off(eventType, listener.listenerRef);
|
||||
@@ -958,7 +955,7 @@ export abstract class EntitySystem<
|
||||
processor: (entity: Entity, index: number) => void
|
||||
): void {
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
processor(entities[i], i);
|
||||
processor(entities[i]!, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1028,7 @@ export abstract class EntitySystem<
|
||||
predicate: (entity: Entity, index: number) => boolean
|
||||
): Entity | undefined {
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
if (predicate(entities[i], i)) {
|
||||
if (predicate(entities[i]!, i)) {
|
||||
return entities[i];
|
||||
}
|
||||
}
|
||||
@@ -1060,7 +1057,7 @@ export abstract class EntitySystem<
|
||||
predicate: (entity: Entity, index: number) => boolean
|
||||
): boolean {
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
if (predicate(entities[i], i)) {
|
||||
if (predicate(entities[i]!, i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1089,7 +1086,7 @@ export abstract class EntitySystem<
|
||||
predicate: (entity: Entity, index: number) => boolean
|
||||
): boolean {
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
if (!predicate(entities[i], i)) {
|
||||
if (!predicate(entities[i]!, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export abstract class PassiveSystem extends EntitySystem {
|
||||
* 不进行任何处理
|
||||
* @param entities 实体数组,未被使用
|
||||
*/
|
||||
protected override process(entities: Entity[]): void {
|
||||
protected override process(_entities: Entity[]): void {
|
||||
// 被动系统不进行任何处理
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export abstract class ProcessingSystem extends EntitySystem {
|
||||
* 处理实体,每帧调用processSystem方法进行处理
|
||||
* @param entities 实体数组,未被使用
|
||||
*/
|
||||
protected override process(entities: Entity[]): void {
|
||||
protected override process(_entities: Entity[]): void {
|
||||
// 调用子类实现的processSystem方法进行实体处理
|
||||
this.processSystem();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import { Entity } from '../Entity';
|
||||
import { EntitySystem } from './EntitySystem';
|
||||
import { Matcher } from '../Utils/Matcher';
|
||||
import { Time } from '../../Utils/Time';
|
||||
import { createLogger } from '../../Utils/Logger';
|
||||
import type { IComponent } from '../../Types';
|
||||
import { PlatformManager } from '../../Platform/PlatformManager';
|
||||
import type { IPlatformAdapter, PlatformWorker } from '../../Platform/IPlatformAdapter';
|
||||
import { getSystemInstanceTypeName } from '../Decorators';
|
||||
@@ -221,7 +219,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
enableWorker: config.enableWorker ?? true,
|
||||
workerCount: validatedWorkerCount,
|
||||
systemConfig: config.systemConfig,
|
||||
entitiesPerWorker: config.entitiesPerWorker,
|
||||
...(config.entitiesPerWorker !== undefined && { entitiesPerWorker: config.entitiesPerWorker }),
|
||||
useSharedArrayBuffer: config.useSharedArrayBuffer ?? this.isSharedArrayBufferSupported(),
|
||||
entityDataSize: config.entityDataSize ?? this.getDefaultEntityDataSize(),
|
||||
maxEntities: config.maxEntities ?? 10000
|
||||
@@ -321,10 +319,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
this.workerPool = new PlatformWorkerPool(
|
||||
workers,
|
||||
this.sharedBuffer // 传递SharedArrayBuffer给Worker池
|
||||
);
|
||||
this.workerPool = new PlatformWorkerPool(workers);
|
||||
} catch (error) {
|
||||
this.logger.error(`${this.systemName}: Worker池初始化失败`, error);
|
||||
this.config.enableWorker = false;
|
||||
@@ -355,7 +350,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
const sharedMethodStr = sharedProcessMethod.toString();
|
||||
const sharedFunctionBodyMatch = sharedMethodStr.match(/\{([\s\S]*)\}/);
|
||||
if (sharedFunctionBodyMatch) {
|
||||
sharedProcessFunctionBody = sharedFunctionBodyMatch[1];
|
||||
sharedProcessFunctionBody = sharedFunctionBodyMatch[1] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +486,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
// 1. 数据提取阶段
|
||||
const entityData: TEntityData[] = [];
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
entityData[i] = this.extractEntityData(entities[i]);
|
||||
entityData[i] = this.extractEntityData(entities[i]!);
|
||||
}
|
||||
|
||||
// 2. 分批处理
|
||||
@@ -541,12 +536,12 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
if (results && typeof (results as any).then === 'function') {
|
||||
(results as Promise<TEntityData[]>).then(finalResults => {
|
||||
entities.forEach((entity, index) => {
|
||||
this.applyResult(entity, finalResults[index]);
|
||||
this.applyResult(entity, finalResults[index]!);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
entities.forEach((entity, index) => {
|
||||
this.applyResult(entity, (results as TEntityData[])[index]);
|
||||
this.applyResult(entity, (results as TEntityData[])[index]!);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -595,7 +590,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
if (!this.sharedFloatArray) return;
|
||||
|
||||
for (let i = 0; i < entities.length && i < this.config.maxEntities; i++) {
|
||||
const entity = entities[i];
|
||||
const entity = entities[i]!;
|
||||
const data = this.extractEntityData(entity);
|
||||
const offset = i * this.config.entityDataSize; // 使用配置的数据大小
|
||||
|
||||
@@ -670,7 +665,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
if (!this.sharedFloatArray) return;
|
||||
|
||||
for (let i = 0; i < entities.length && i < this.config.maxEntities; i++) {
|
||||
const entity = entities[i];
|
||||
const entity = entities[i]!;
|
||||
const offset = i * this.config.entityDataSize; // 使用配置的数据大小
|
||||
|
||||
// 从SharedArrayBuffer读取数据
|
||||
@@ -832,7 +827,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
return {
|
||||
enabled: this.config.enableWorker,
|
||||
workerCount: this.config.workerCount,
|
||||
entitiesPerWorker: this.config.entitiesPerWorker,
|
||||
...(this.config.entitiesPerWorker !== undefined && { entitiesPerWorker: this.config.entitiesPerWorker }),
|
||||
maxSystemWorkerCount: this.getMaxSystemWorkerCount(),
|
||||
isProcessing: this.isProcessing,
|
||||
sharedArrayBufferSupported: this.isSharedArrayBufferSupported(),
|
||||
@@ -871,31 +866,20 @@ class PlatformWorkerPool {
|
||||
}> = [];
|
||||
private busyWorkers = new Set<number>();
|
||||
private taskCounter = 0;
|
||||
private sharedBuffer: SharedArrayBuffer | null = null;
|
||||
private readonly logger = createLogger('PlatformWorkerPool');
|
||||
|
||||
constructor(
|
||||
workers: PlatformWorker[],
|
||||
sharedBuffer: SharedArrayBuffer | null = null
|
||||
workers: PlatformWorker[]
|
||||
) {
|
||||
this.sharedBuffer = sharedBuffer;
|
||||
this.workers = workers;
|
||||
|
||||
// 为每个Worker设置消息处理器
|
||||
for (let i = 0; i < workers.length; i++) {
|
||||
const worker = workers[i];
|
||||
if (!worker) continue;
|
||||
|
||||
// 设置消息处理器
|
||||
worker.onMessage((event) => this.handleWorkerMessage(i, event.data));
|
||||
worker.onError((error) => this.handleWorkerError(i, error));
|
||||
|
||||
// 如果有SharedArrayBuffer,发送给Worker
|
||||
if (sharedBuffer) {
|
||||
worker.postMessage({
|
||||
type: 'init',
|
||||
sharedBuffer: sharedBuffer
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,14 +930,15 @@ class PlatformWorkerPool {
|
||||
if (!this.busyWorkers.has(i) && this.taskQueue.length > 0) {
|
||||
const task = this.taskQueue.shift()!;
|
||||
this.busyWorkers.add(i);
|
||||
const worker = this.workers[i]!;
|
||||
|
||||
this.workers[i].postMessage({
|
||||
worker.postMessage({
|
||||
id: task.id,
|
||||
...task.data
|
||||
});
|
||||
|
||||
// 存储任务信息以便后续处理
|
||||
(this.workers[i] as any)._currentTask = task;
|
||||
(worker as any)._currentTask = task;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface BitMask64Data {
|
||||
|
||||
export class BitMask64Utils {
|
||||
/** 零掩码常量,所有位都为0 */
|
||||
public static readonly ZERO: Readonly<BitMask64Data> = { base: [0, 0], segments: undefined };
|
||||
public static readonly ZERO: Readonly<BitMask64Data> = { base: [0, 0] };
|
||||
|
||||
/**
|
||||
* 根据位索引创建64位掩码
|
||||
@@ -37,7 +37,7 @@ export class BitMask64Utils {
|
||||
if (bitIndex < 0) {
|
||||
throw new Error(`Bit index ${bitIndex} out of range [0, ∞)`);
|
||||
}
|
||||
const mask: BitMask64Data = { base: [0, 0], segments: undefined };
|
||||
const mask: BitMask64Data = { base: [0, 0] };
|
||||
BitMask64Utils.setBit(mask, bitIndex);
|
||||
return mask;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ export class BitMask64Utils {
|
||||
* @returns 低32位为输入值、高32位为0的掩码
|
||||
*/
|
||||
public static fromNumber(value: number): BitMask64Data {
|
||||
return { base: [value >>> 0, 0], segments: undefined};
|
||||
return { base: [value >>> 0, 0] };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +66,10 @@ export class BitMask64Utils {
|
||||
// 基础区段就包含指定的位,或任意一个参数不含扩展区段,直接短路
|
||||
if(baseHasAny || !bitsSegments || !maskSegments) return baseHasAny;
|
||||
// 额外检查扩展区域是否包含指定的位 - 如果bitsSegments[index]不存在,会被转为NaN,NaN的位运算始终返回0
|
||||
return maskSegments.some((seg, index) => (seg[SegmentPart.LOW] & bitsSegments[index][SegmentPart.LOW]) !== 0 || (seg[SegmentPart.HIGH] & bitsSegments[index][SegmentPart.HIGH]) !== 0)
|
||||
return maskSegments.some((seg, index) => {
|
||||
const bitsSeg = bitsSegments[index];
|
||||
return bitsSeg && ((seg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) !== 0 || (seg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) !== 0);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +92,9 @@ export class BitMask64Utils {
|
||||
// 对mask/bits中都存在的区段,进行hasAll判断
|
||||
if(maskSegments){
|
||||
for (let i = 0; i < Math.min(maskSegmentsLength,bitsSegments.length); i++) {
|
||||
if((maskSegments[i][SegmentPart.LOW] & bitsSegments[i][SegmentPart.LOW]) !== bitsSegments[i][SegmentPart.LOW] || (maskSegments[i][SegmentPart.HIGH] & bitsSegments[i][SegmentPart.HIGH]) !== bitsSegments[i][SegmentPart.HIGH]){
|
||||
const maskSeg = maskSegments[i]!;
|
||||
const bitsSeg = bitsSegments[i]!;
|
||||
if((maskSeg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) !== bitsSeg[SegmentPart.LOW] || (maskSeg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) !== bitsSeg[SegmentPart.HIGH]){
|
||||
// 存在不匹配的位,直接短路
|
||||
return false;
|
||||
}
|
||||
@@ -97,7 +102,8 @@ export class BitMask64Utils {
|
||||
}
|
||||
// 对mask中不存在,但bits中存在的区段,进行isZero判断
|
||||
for (let i = maskSegmentsLength; i < bitsSegments.length; i++) {
|
||||
if(bitsSegments[i][SegmentPart.LOW] !== 0 || bitsSegments[i][SegmentPart.HIGH] !== 0){
|
||||
const bitsSeg = bitsSegments[i]!;
|
||||
if(bitsSeg[SegmentPart.LOW] !== 0 || bitsSeg[SegmentPart.HIGH] !== 0){
|
||||
// 存在不为0的区段,直接短路
|
||||
return false;
|
||||
}
|
||||
@@ -120,7 +126,11 @@ export class BitMask64Utils {
|
||||
//不含扩展区域,或基础区域就包含指定的位,或bits不含拓展区段,直接短路。
|
||||
if(!maskSegments || !baseHasNone || !bitsSegments) return baseHasNone;
|
||||
// 额外检查扩展区域是否都包含指定的位 - 此时bitsSegments存在,如果bitsSegments[index]不存在,会被转为NaN,NaN的位运算始终返回0
|
||||
return maskSegments.every((seg, index) => (seg[SegmentPart.LOW] & bitsSegments[index][SegmentPart.LOW]) === 0 && (seg[SegmentPart.HIGH] & bitsSegments[index][SegmentPart.HIGH]) === 0);
|
||||
return maskSegments.every((seg, index) => {
|
||||
const bitsSeg = bitsSegments[index];
|
||||
if (!bitsSeg) return true;
|
||||
return (seg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) === 0 && (seg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) === 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +170,7 @@ export class BitMask64Utils {
|
||||
}else if(!aSeg && bSeg){
|
||||
//aSeg不存在,则必须要求bSeg全为0
|
||||
if(bSeg[SegmentPart.LOW] !== 0 || bSeg[SegmentPart.HIGH] !== 0) return false;
|
||||
}else{
|
||||
}else if(aSeg && bSeg){
|
||||
//理想状态:aSeg/bSeg都存在
|
||||
if(aSeg[SegmentPart.LOW] !== bSeg[SegmentPart.LOW] || aSeg[SegmentPart.HIGH] !== bSeg[SegmentPart.HIGH]) return false;
|
||||
}
|
||||
@@ -248,8 +258,10 @@ export class BitMask64Utils {
|
||||
|
||||
// 对每个段执行或操作
|
||||
for (let i = 0; i < otherSegments.length; i++) {
|
||||
targetSegments[i][SegmentPart.LOW] |= otherSegments[i][SegmentPart.LOW];
|
||||
targetSegments[i][SegmentPart.HIGH] |= otherSegments[i][SegmentPart.HIGH];
|
||||
const targetSeg = targetSegments[i]!;
|
||||
const otherSeg = otherSegments[i]!;
|
||||
targetSeg[SegmentPart.LOW] |= otherSeg[SegmentPart.LOW];
|
||||
targetSeg[SegmentPart.HIGH] |= otherSeg[SegmentPart.HIGH];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,8 +289,10 @@ export class BitMask64Utils {
|
||||
|
||||
// 对每个段执行与操作
|
||||
for (let i = 0; i < otherSegments.length; i++) {
|
||||
targetSegments[i][SegmentPart.LOW] &= otherSegments[i][SegmentPart.LOW];
|
||||
targetSegments[i][SegmentPart.HIGH] &= otherSegments[i][SegmentPart.HIGH];
|
||||
const targetSeg = targetSegments[i]!;
|
||||
const otherSeg = otherSegments[i]!;
|
||||
targetSeg[SegmentPart.LOW] &= otherSeg[SegmentPart.LOW];
|
||||
targetSeg[SegmentPart.HIGH] &= otherSeg[SegmentPart.HIGH];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,8 +319,10 @@ export class BitMask64Utils {
|
||||
|
||||
// 对每个段执行异或操作
|
||||
for (let i = 0; i < otherSegments.length; i++) {
|
||||
targetSegments[i][SegmentPart.LOW] ^= otherSegments[i][SegmentPart.LOW];
|
||||
targetSegments[i][SegmentPart.HIGH] ^= otherSegments[i][SegmentPart.HIGH];
|
||||
const targetSeg = targetSegments[i]!;
|
||||
const otherSeg = otherSegments[i]!;
|
||||
targetSeg[SegmentPart.LOW] ^= otherSeg[SegmentPart.LOW];
|
||||
targetSeg[SegmentPart.HIGH] ^= otherSeg[SegmentPart.HIGH];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,10 +333,12 @@ export class BitMask64Utils {
|
||||
public static clear(mask: BitMask64Data): void {
|
||||
mask.base[SegmentPart.LOW] = 0;
|
||||
mask.base[SegmentPart.HIGH] = 0;
|
||||
for (let i = 0; i < (mask.segments?.length ?? 0); i++) {
|
||||
const seg = mask.segments![i];
|
||||
seg[SegmentPart.LOW] = 0;
|
||||
seg[SegmentPart.HIGH] = 0;
|
||||
if (mask.segments) {
|
||||
for (let i = 0; i < mask.segments.length; i++) {
|
||||
const seg = mask.segments[i]!;
|
||||
seg[SegmentPart.LOW] = 0;
|
||||
seg[SegmentPart.HIGH] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,9 +364,11 @@ export class BitMask64Utils {
|
||||
target.segments.push([0,0]);
|
||||
}
|
||||
// 逐个重写
|
||||
for (let i = 0; i < length; i++) {
|
||||
const targetSeg = target.segments![i];
|
||||
const sourSeg = source.segments![i];
|
||||
const targetSegments = target.segments;
|
||||
const sourceSegments = source.segments;
|
||||
for (let i = 0; i < sourceSegments.length; i++) {
|
||||
const targetSeg = targetSegments[i]!;
|
||||
const sourSeg = sourceSegments[i]!;
|
||||
targetSeg[SegmentPart.LOW] = sourSeg[SegmentPart.LOW];
|
||||
targetSeg[SegmentPart.HIGH] = sourSeg[SegmentPart.HIGH];
|
||||
}
|
||||
@@ -362,7 +382,7 @@ export class BitMask64Utils {
|
||||
public static clone(mask: BitMask64Data): BitMask64Data {
|
||||
return {
|
||||
base: mask.base.slice() as BitMask64Segment,
|
||||
segments: mask.segments ? mask.segments.map(seg => [...seg]) : undefined
|
||||
...(mask.segments && { segments: mask.segments.map(seg => [...seg] as BitMask64Segment) })
|
||||
};
|
||||
}
|
||||
|
||||
@@ -393,7 +413,7 @@ export class BitMask64Utils {
|
||||
|
||||
for (let i = -1; i < totalLength; i++) {
|
||||
let segResult = '';
|
||||
const bitMaskData = i == -1 ? mask.base : mask.segments![i];
|
||||
const bitMaskData = i == -1 ? mask.base : mask.segments![i]!;
|
||||
let hi = bitMaskData[SegmentPart.HIGH];
|
||||
let lo = bitMaskData[SegmentPart.LOW];
|
||||
if(radix == 2){
|
||||
@@ -429,7 +449,7 @@ export class BitMask64Utils {
|
||||
public static popCount(mask: BitMask64Data): number {
|
||||
let count = 0;
|
||||
for (let i = -1; i < (mask.segments?.length ?? 0); i++) {
|
||||
const bitMaskData = i == -1 ? mask.base : mask.segments![i];
|
||||
const bitMaskData = i == -1 ? mask.base : mask.segments![i]!;
|
||||
let lo = bitMaskData[SegmentPart.LOW];
|
||||
let hi = bitMaskData[SegmentPart.HIGH];
|
||||
while (lo) {
|
||||
@@ -470,7 +490,7 @@ export class BitMask64Utils {
|
||||
segments.push([0, 0]);
|
||||
}
|
||||
}
|
||||
return segments[targetSegIndex];
|
||||
return segments[targetSegIndex] ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,8 +73,8 @@ export class BitMaskHashMap<T> {
|
||||
|
||||
// 查找是否存在 secondaryHash
|
||||
for (let i = 0; i < bucket.length; i++) {
|
||||
if (bucket[i][0] === secondary) {
|
||||
bucket[i][1] = value;
|
||||
if (bucket[i]![0] === secondary) {
|
||||
bucket[i]![1] = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -90,8 +90,8 @@ export class BitMaskHashMap<T> {
|
||||
const bucket = this.buckets.get(primary);
|
||||
if (!bucket) return undefined;
|
||||
for (let i = 0; i < bucket.length; i++) {
|
||||
if (bucket[i][0] === secondary) {
|
||||
return bucket[i][1];
|
||||
if (bucket[i]![0] === secondary) {
|
||||
return bucket[i]![1];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -106,7 +106,7 @@ export class BitMaskHashMap<T> {
|
||||
const bucket = this.buckets.get(primary);
|
||||
if (!bucket) return false;
|
||||
for (let i = 0; i < bucket.length; i++) {
|
||||
if (bucket[i][0] === secondary) {
|
||||
if (bucket[i]![0] === secondary) {
|
||||
bucket.splice(i, 1);
|
||||
this._size--;
|
||||
if (bucket.length === 0) {
|
||||
@@ -125,7 +125,7 @@ export class BitMaskHashMap<T> {
|
||||
|
||||
*entries(): IterableIterator<[BitMask64Data, T]> {
|
||||
for (const [_, bucket] of this.buckets) {
|
||||
for (const [secondary, value] of bucket) {
|
||||
for (const [_secondary, value] of bucket) {
|
||||
// 无法还原原始 key(只存二级 hash),所以 entries 返回不了 key
|
||||
yield [undefined as any, value];
|
||||
}
|
||||
|
||||
@@ -265,16 +265,16 @@ export class Bits {
|
||||
*/
|
||||
public static fromBinaryString(binaryString: string): Bits {
|
||||
const cleanString = binaryString.replace(/\s/g, '');
|
||||
let data: BitMask64Data = { base: undefined!, segments: undefined};
|
||||
let data: BitMask64Data;
|
||||
if (cleanString.length <= 32) {
|
||||
const num = parseInt(cleanString, 2);
|
||||
data.base = [num >>> 0, 0];
|
||||
data = { base: [num >>> 0, 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.base = [lo >>> 0, hi >>> 0];
|
||||
data = { base: [lo >>> 0, hi >>> 0] };
|
||||
}
|
||||
return new Bits(data);
|
||||
}
|
||||
@@ -286,16 +286,16 @@ export class Bits {
|
||||
*/
|
||||
public static fromHexString(hexString: string): Bits {
|
||||
const cleanString = hexString.replace(/^0x/i, '');
|
||||
let data: BitMask64Data = { base: undefined!, segments: undefined};
|
||||
let data: BitMask64Data;
|
||||
if (cleanString.length <= 8) {
|
||||
const num = parseInt(cleanString, 16);
|
||||
data.base = [num >>> 0, 0];
|
||||
data = { base: [num >>> 0, 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.base = [lo >>> 0, hi >>> 0];
|
||||
data = { base: [lo >>> 0, hi >>> 0] };
|
||||
}
|
||||
return new Bits(data);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IPoolable } from '../../Utils/Pool/IPoolable';
|
||||
* 实现IPoolable接口,支持对象池复用以减少内存分配开销。
|
||||
*/
|
||||
class PoolableEntitySet extends Set<Entity> implements IPoolable {
|
||||
constructor(...args: unknown[]) {
|
||||
constructor(..._args: unknown[]) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ export class ComponentSparseSet {
|
||||
const lastIndex = this._componentMasks.length - 1;
|
||||
if (entityIndex !== lastIndex) {
|
||||
// 将最后一个位掩码移动到当前位置
|
||||
this._componentMasks[entityIndex] = this._componentMasks[lastIndex];
|
||||
this._componentMasks[entityIndex] = this._componentMasks[lastIndex]!;
|
||||
}
|
||||
this._componentMasks.pop();
|
||||
}
|
||||
@@ -165,7 +165,7 @@ export class ComponentSparseSet {
|
||||
}
|
||||
|
||||
if (componentTypes.length === 1) {
|
||||
return this.queryByComponent(componentTypes[0]);
|
||||
return this.queryByComponent(componentTypes[0]!);
|
||||
}
|
||||
|
||||
// 构建目标位掩码
|
||||
@@ -182,7 +182,7 @@ export class ComponentSparseSet {
|
||||
|
||||
// 遍历所有实体,检查位掩码匹配
|
||||
this._entities.forEach((entity, index) => {
|
||||
const entityMask = this._componentMasks[index];
|
||||
const entityMask = this._componentMasks[index]!;
|
||||
if (BitMask64Utils.hasAll(entityMask, targetMask)) {
|
||||
result.add(entity);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ export class ComponentSparseSet {
|
||||
}
|
||||
|
||||
if (componentTypes.length === 1) {
|
||||
return this.queryByComponent(componentTypes[0]);
|
||||
return this.queryByComponent(componentTypes[0]!);
|
||||
}
|
||||
|
||||
// 构建目标位掩码
|
||||
@@ -225,7 +225,7 @@ export class ComponentSparseSet {
|
||||
|
||||
// 遍历所有实体,检查位掩码匹配
|
||||
this._entities.forEach((entity, index) => {
|
||||
const entityMask = this._componentMasks[index];
|
||||
const entityMask = this._componentMasks[index]!;
|
||||
if (BitMask64Utils.hasAny(entityMask, targetMask)) {
|
||||
result.add(entity);
|
||||
}
|
||||
@@ -251,9 +251,9 @@ export class ComponentSparseSet {
|
||||
return false;
|
||||
}
|
||||
|
||||
const entityMask = this._componentMasks[entityIndex];
|
||||
const entityMask = this._componentMasks[entityIndex]!;
|
||||
const componentMask = ComponentRegistry.getBitMask(componentType);
|
||||
|
||||
|
||||
return BitMask64Utils.hasAny(entityMask, componentMask);
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ export class ComponentSparseSet {
|
||||
*/
|
||||
public forEach(callback: (entity: Entity, mask: BitMask64Data, index: number) => void): void {
|
||||
this._entities.forEach((entity, index) => {
|
||||
callback(entity, this._componentMasks[index], index);
|
||||
callback(entity, this._componentMasks[index]!, index);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ export class EntityList {
|
||||
const idsToRecycle: number[] = [];
|
||||
|
||||
for (let i = this.buffer.length - 1; i >= 0; i--) {
|
||||
idsToRecycle.push(this.buffer[i].id);
|
||||
this.buffer[i].destroy();
|
||||
idsToRecycle.push(this.buffer[i]!.id);
|
||||
this.buffer[i]!.destroy();
|
||||
}
|
||||
|
||||
// 批量回收ID
|
||||
@@ -142,7 +142,7 @@ export class EntityList {
|
||||
*/
|
||||
public findEntity(name: string): Entity | null {
|
||||
const entities = this._nameToEntities.get(name);
|
||||
return entities && entities.length > 0 ? entities[0] : null;
|
||||
return entities && entities.length > 0 ? entities[0]! : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,9 +209,9 @@ export class Matcher {
|
||||
all: [...this.condition.all],
|
||||
any: [...this.condition.any],
|
||||
none: [...this.condition.none],
|
||||
tag: this.condition.tag,
|
||||
name: this.condition.name,
|
||||
component: this.condition.component
|
||||
...(this.condition.tag !== undefined && { tag: this.condition.tag }),
|
||||
...(this.condition.name !== undefined && { name: this.condition.name }),
|
||||
...(this.condition.component !== undefined && { component: this.condition.component })
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ export class SparseSet<T> {
|
||||
|
||||
// 如果不是最后一个元素,则与最后一个元素交换
|
||||
if (index !== lastIndex) {
|
||||
const lastItem = this._dense[lastIndex];
|
||||
const lastItem = this._dense[lastIndex]!;
|
||||
this._dense[index] = lastItem;
|
||||
this._sparse.set(lastItem, index);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ export class SparseSet<T> {
|
||||
*/
|
||||
public forEach(callback: (item: T, index: number) => void): void {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
callback(this._dense[i], i);
|
||||
callback(this._dense[i]!, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ export class SparseSet<T> {
|
||||
public map<U>(callback: (item: T, index: number) => U): U[] {
|
||||
const result: U[] = [];
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
result.push(callback(this._dense[i], i));
|
||||
result.push(callback(this._dense[i]!, i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -167,8 +167,8 @@ export class SparseSet<T> {
|
||||
public filter(predicate: (item: T, index: number) => boolean): T[] {
|
||||
const result: T[] = [];
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (predicate(this._dense[i], i)) {
|
||||
result.push(this._dense[i]);
|
||||
if (predicate(this._dense[i]!, i)) {
|
||||
result.push(this._dense[i]!);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -182,7 +182,7 @@ export class SparseSet<T> {
|
||||
*/
|
||||
public find(predicate: (item: T, index: number) => boolean): T | undefined {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (predicate(this._dense[i], i)) {
|
||||
if (predicate(this._dense[i]!, i)) {
|
||||
return this._dense[i];
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ export class SparseSet<T> {
|
||||
*/
|
||||
public some(predicate: (item: T, index: number) => boolean): boolean {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (predicate(this._dense[i], i)) {
|
||||
if (predicate(this._dense[i]!, i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ export class SparseSet<T> {
|
||||
*/
|
||||
public every(predicate: (item: T, index: number) => boolean): boolean {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (!predicate(this._dense[i], i)) {
|
||||
if (!predicate(this._dense[i]!, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -291,7 +291,7 @@ export class SparseSet<T> {
|
||||
|
||||
// 检查映射关系的正确性
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
const item = this._dense[i];
|
||||
const item = this._dense[i]!;
|
||||
const mappedIndex = this._sparse.get(item);
|
||||
if (mappedIndex !== i) {
|
||||
return false;
|
||||
|
||||
@@ -110,8 +110,9 @@ export class WorldManager implements IService {
|
||||
|
||||
const worldConfig: IWorldConfig = {
|
||||
name: worldId,
|
||||
debug: this._config.debug,
|
||||
...config
|
||||
...(this._config.debug !== undefined && { debug: this._config.debug }),
|
||||
...(config?.maxScenes !== undefined && { maxScenes: config.maxScenes }),
|
||||
...(config?.autoCleanup !== undefined && { autoCleanup: config.autoCleanup })
|
||||
};
|
||||
|
||||
const world = new World(worldConfig);
|
||||
|
||||
Reference in New Issue
Block a user