Compare commits
3 Commits
master
...
style/code
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c7c3c98af | ||
|
|
be7b3afb4a | ||
|
|
3e037f4ae0 |
@@ -31,9 +31,32 @@
|
|||||||
"@typescript-eslint/no-unsafe-call": "warn",
|
"@typescript-eslint/no-unsafe-call": "warn",
|
||||||
"@typescript-eslint/no-unsafe-return": "warn",
|
"@typescript-eslint/no-unsafe-return": "warn",
|
||||||
"@typescript-eslint/no-unsafe-argument": "warn",
|
"@typescript-eslint/no-unsafe-argument": "warn",
|
||||||
|
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
||||||
"@typescript-eslint/no-non-null-assertion": "off"
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
|
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||||
|
"@typescript-eslint/naming-convention": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"selector": "memberLike",
|
||||||
|
"modifiers": ["private"],
|
||||||
|
"format": ["camelCase"],
|
||||||
|
"leadingUnderscore": "require"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector": "memberLike",
|
||||||
|
"modifiers": ["public"],
|
||||||
|
"format": ["camelCase"],
|
||||||
|
"leadingUnderscore": "forbid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector": "memberLike",
|
||||||
|
"modifiers": ["protected"],
|
||||||
|
"format": ["camelCase"],
|
||||||
|
"leadingUnderscore": "require"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"ignorePatterns": [
|
"ignorePatterns": [
|
||||||
"node_modules/",
|
"node_modules/",
|
||||||
|
|||||||
@@ -329,8 +329,8 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static setScene<T extends IScene>(scene: T): T {
|
public static setScene<T extends IScene>(scene: T): T {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||||
throw new Error("Core实例未创建");
|
throw new Error('Core实例未创建');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._instance._sceneManager.setScene(scene);
|
return this._instance._sceneManager.setScene(scene);
|
||||||
@@ -387,7 +387,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static loadScene<T extends IScene>(scene: T): void {
|
public static loadScene<T extends IScene>(scene: T): void {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static update(deltaTime: number): void {
|
public static update(deltaTime: number): void {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static enableDebug(config: IECSDebugConfig): void {
|
public static enableDebug(config: IECSDebugConfig): void {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ export interface UpdatableMetadata {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function Injectable(): ClassDecorator {
|
export function Injectable(): ClassDecorator {
|
||||||
return function (target: Function): void {
|
return function (target: Constructor): void {
|
||||||
const existing = injectableMetadata.get(target as Constructor);
|
const existing = injectableMetadata.get(target);
|
||||||
|
|
||||||
injectableMetadata.set(target as Constructor, {
|
injectableMetadata.set(target as Constructor, {
|
||||||
injectable: true,
|
injectable: true,
|
||||||
@@ -117,13 +117,13 @@ export function Injectable(): ClassDecorator {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function Updatable(priority: number = 0): ClassDecorator {
|
export function Updatable(priority: number = 0): ClassDecorator {
|
||||||
return function (target: Function): void {
|
return function (target: Constructor): void {
|
||||||
// 验证类原型上是否有update方法
|
// 验证类原型上是否有update方法
|
||||||
const prototype = (target as Constructor & { prototype: { update?: unknown } }).prototype;
|
const prototype = (target as Constructor & { prototype: { update?: unknown } }).prototype;
|
||||||
if (!prototype || typeof prototype.update !== 'function') {
|
if (!prototype || typeof prototype.update !== 'function') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`@Updatable() decorator requires class ${target.name} to implement IUpdatable interface with update() method. ` +
|
`@Updatable() decorator requires class ${target.name} to implement IUpdatable interface with update() method. ` +
|
||||||
`Please add 'implements IUpdatable' and define update(deltaTime?: number): void method.`
|
"Please add 'implements IUpdatable' and define update(deltaTime?: number): void method."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +228,7 @@ export function getInjectMetadata(target: Constructor): Map<number, ServiceType<
|
|||||||
* const instance = createInstance(MySystem, container);
|
* const instance = createInstance(MySystem, container);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function createInstance<T>(
|
export function createInstance<T>(
|
||||||
constructor: new (...args: any[]) => T,
|
constructor: new (...args: any[]) => T,
|
||||||
container: ServiceContainer
|
container: ServiceContainer
|
||||||
@@ -249,7 +250,7 @@ export function createInstance<T>(
|
|||||||
if (typeof serviceType === 'string' || typeof serviceType === 'symbol') {
|
if (typeof serviceType === 'string' || typeof serviceType === 'symbol') {
|
||||||
// 字符串或Symbol类型的服务标识
|
// 字符串或Symbol类型的服务标识
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`String and Symbol service identifiers are not yet supported in constructor injection. ` +
|
'String and Symbol service identifiers are not yet supported in constructor injection. ' +
|
||||||
`Please use class types for ${constructor.name} parameter ${i}`
|
`Please use class types for ${constructor.name} parameter ${i}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -338,7 +339,7 @@ export function registerInjectable<T extends IService>(
|
|||||||
if (!isInjectable(serviceType)) {
|
if (!isInjectable(serviceType)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${serviceType.name} is not marked as @Injectable(). ` +
|
`${serviceType.name} is not marked as @Injectable(). ` +
|
||||||
`Please add @Injectable() decorator to the class.`
|
'Please add @Injectable() decorator to the class.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ export interface IService {
|
|||||||
* 服务类型
|
* 服务类型
|
||||||
*
|
*
|
||||||
* 支持任意构造函数签名,以便与依赖注入装饰器配合使用
|
* 支持任意构造函数签名,以便与依赖注入装饰器配合使用
|
||||||
* 使用 any[] 以允许任意参数类型的构造函数
|
* 使用 any[] 以允许任意参数类型的构造函数,这是类型系统的必要妥协
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export type ServiceType<T extends IService> = new (...args: any[]) => T;
|
export type ServiceType<T extends IService> = new (...args: any[]) => T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,7 +241,7 @@ export class ServiceContainer {
|
|||||||
|
|
||||||
// 检测循环依赖
|
// 检测循环依赖
|
||||||
if (this._resolving.has(type as ServiceType<IService>)) {
|
if (this._resolving.has(type as ServiceType<IService>)) {
|
||||||
const chain = Array.from(this._resolving).map(t => t.name).join(' -> ');
|
const chain = Array.from(this._resolving).map((t) => t.name).join(' -> ');
|
||||||
throw new Error(`Circular dependency detected: ${chain} -> ${type.name}`);
|
throw new Error(`Circular dependency detected: ${chain} -> ${type.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +338,7 @@ export class ServiceContainer {
|
|||||||
// 如果有单例实例,调用 dispose
|
// 如果有单例实例,调用 dispose
|
||||||
if (registration.instance) {
|
if (registration.instance) {
|
||||||
// 从可更新列表中移除
|
// 从可更新列表中移除
|
||||||
const index = this._updatableServices.findIndex(item => item.instance === registration.instance);
|
const index = this._updatableServices.findIndex((item) => item.instance === registration.instance);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this._updatableServices.splice(index, 1);
|
this._updatableServices.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,16 @@ export abstract class Component implements IComponent {
|
|||||||
*
|
*
|
||||||
* 用于为每个组件分配唯一的ID。
|
* 用于为每个组件分配唯一的ID。
|
||||||
*/
|
*/
|
||||||
public static _idGenerator: number = 0;
|
private static _nextId: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一个组件ID(只读)
|
||||||
|
*
|
||||||
|
* @returns 下一个将要分配的组件ID
|
||||||
|
*/
|
||||||
|
public static get nextComponentId(): number {
|
||||||
|
return Component._nextId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件唯一标识符
|
* 组件唯一标识符
|
||||||
@@ -58,7 +67,7 @@ export abstract class Component implements IComponent {
|
|||||||
* 自动分配唯一ID给组件。
|
* 自动分配唯一ID给组件。
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.id = Component._idGenerator++;
|
this.id = Component._nextId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Entity } from '../Entity';
|
import { Entity } from '../Entity';
|
||||||
import { ComponentType, ComponentRegistry } from './ComponentStorage';
|
import { ComponentType, ComponentRegistry } from './ComponentStorage';
|
||||||
import { BitMask64Data, BitMask64Utils } from "../Utils";
|
import { BitMask64Data, BitMask64Utils } from '../Utils';
|
||||||
import { BitMaskHashMap } from "../Utils/BitMaskHashMap";
|
import { BitMaskHashMap } from '../Utils/BitMaskHashMap';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 原型标识符
|
* 原型标识符
|
||||||
@@ -247,7 +247,7 @@ export class ArchetypeSystem {
|
|||||||
*/
|
*/
|
||||||
private updateAllArchetypeArrays(): void {
|
private updateAllArchetypeArrays(): void {
|
||||||
this._allArchetypes = [];
|
this._allArchetypes = [];
|
||||||
for (let archetype of this._archetypes.values()) {
|
for (const archetype of this._archetypes.values()) {
|
||||||
this._allArchetypes.push(archetype);
|
this._allArchetypes.push(archetype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ export class ArchetypeSystem {
|
|||||||
private getEntityComponentTypes(entity: Entity): ComponentType[] {
|
private getEntityComponentTypes(entity: Entity): ComponentType[] {
|
||||||
let componentTypes = this._entityComponentTypesCache.get(entity);
|
let componentTypes = this._entityComponentTypesCache.get(entity);
|
||||||
if (!componentTypes) {
|
if (!componentTypes) {
|
||||||
componentTypes = entity.components.map(component => component.constructor as ComponentType);
|
componentTypes = entity.components.map((component) => component.constructor as ComponentType);
|
||||||
this._entityComponentTypesCache.set(entity, componentTypes);
|
this._entityComponentTypesCache.set(entity, componentTypes);
|
||||||
}
|
}
|
||||||
return componentTypes;
|
return componentTypes;
|
||||||
@@ -269,7 +269,7 @@ export class ArchetypeSystem {
|
|||||||
* 使用ComponentRegistry确保与Entity.componentMask使用相同的bitIndex
|
* 使用ComponentRegistry确保与Entity.componentMask使用相同的bitIndex
|
||||||
*/
|
*/
|
||||||
private generateArchetypeId(componentTypes: ComponentType[]): ArchetypeId {
|
private generateArchetypeId(componentTypes: ComponentType[]): ArchetypeId {
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
if (!ComponentRegistry.isRegistered(type)) {
|
if (!ComponentRegistry.isRegistered(type)) {
|
||||||
ComponentRegistry.register(type);
|
ComponentRegistry.register(type);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { ComponentRegistry, ComponentType } from './ComponentStorage/ComponentRe
|
|||||||
export { ComponentRegistry, ComponentType };
|
export { ComponentRegistry, ComponentType };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高性能组件存储器
|
* 高性能组件存储器
|
||||||
*/
|
*/
|
||||||
@@ -152,7 +151,7 @@ export class ComponentStorage<T extends Component> {
|
|||||||
usedSlots: number;
|
usedSlots: number;
|
||||||
freeSlots: number;
|
freeSlots: number;
|
||||||
fragmentation: number;
|
fragmentation: number;
|
||||||
} {
|
} {
|
||||||
const totalSlots = this.dense.length;
|
const totalSlots = this.dense.length;
|
||||||
const usedSlots = this.dense.length;
|
const usedSlots = this.dense.length;
|
||||||
const freeSlots = 0; // 永远无空洞
|
const freeSlots = 0; // 永远无空洞
|
||||||
@@ -173,7 +172,7 @@ export class ComponentStorage<T extends Component> {
|
|||||||
*/
|
*/
|
||||||
export class ComponentStorageManager {
|
export class ComponentStorageManager {
|
||||||
private static readonly _logger = createLogger('ComponentStorage');
|
private static readonly _logger = createLogger('ComponentStorage');
|
||||||
private storages = new Map<Function, ComponentStorage<Component> | SoAStorage<Component>>();
|
private storages = new Map<ComponentType, ComponentStorage<Component> | SoAStorage<Component>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查组件类型是否启用SoA存储
|
* 检查组件类型是否启用SoA存储
|
||||||
@@ -342,7 +341,7 @@ export class ComponentStorageManager {
|
|||||||
* @returns 组件位掩码
|
* @returns 组件位掩码
|
||||||
*/
|
*/
|
||||||
public getComponentMask(entityId: number): BitMask64Data {
|
public getComponentMask(entityId: number): BitMask64Data {
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
|
|
||||||
for (const [componentType, storage] of this.storages.entries()) {
|
for (const [componentType, storage] of this.storages.entries()) {
|
||||||
if (storage.hasComponent(entityId)) {
|
if (storage.hasComponent(entityId)) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { getComponentTypeName } from '../../Decorators';
|
|||||||
/**
|
/**
|
||||||
* 组件类型定义
|
* 组件类型定义
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export type ComponentType<T extends Component = Component> = new (...args: any[]) => T;
|
export type ComponentType<T extends Component = Component> = new (...args: any[]) => T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,9 +15,9 @@ export type ComponentType<T extends Component = Component> = new (...args: any[]
|
|||||||
*/
|
*/
|
||||||
export class ComponentRegistry {
|
export class ComponentRegistry {
|
||||||
protected static readonly _logger = createLogger('ComponentStorage');
|
protected static readonly _logger = createLogger('ComponentStorage');
|
||||||
private static componentTypes = new Map<Function, number>();
|
private static componentTypes = new Map<ComponentType, number>();
|
||||||
private static bitIndexToType = new Map<number, Function>();
|
private static bitIndexToType = new Map<number, ComponentType>();
|
||||||
private static componentNameToType = new Map<string, Function>();
|
private static componentNameToType = new Map<string, ComponentType>();
|
||||||
private static componentNameToId = new Map<string, number>();
|
private static componentNameToId = new Map<string, number>();
|
||||||
private static maskCache = new Map<string, BitMask64Data>();
|
private static maskCache = new Map<string, BitMask64Data>();
|
||||||
private static nextBitIndex = 0;
|
private static nextBitIndex = 0;
|
||||||
@@ -102,7 +103,7 @@ export class ComponentRegistry {
|
|||||||
* @param componentName 组件名称
|
* @param componentName 组件名称
|
||||||
* @returns 组件类型构造函数
|
* @returns 组件类型构造函数
|
||||||
*/
|
*/
|
||||||
public static getComponentType(componentName: string): Function | null {
|
public static getComponentType(componentName: string): ComponentType | null {
|
||||||
return this.componentNameToType.get(componentName) || null;
|
return this.componentNameToType.get(componentName) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ export class ComponentRegistry {
|
|||||||
* 获取所有已注册的组件类型
|
* 获取所有已注册的组件类型
|
||||||
* @returns 组件类型映射
|
* @returns 组件类型映射
|
||||||
*/
|
*/
|
||||||
public static getAllRegisteredTypes(): Map<Function, number> {
|
public static getAllRegisteredTypes(): Map<ComponentType, number> {
|
||||||
return new Map(this.componentTypes);
|
return new Map(this.componentTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ export class ComponentRegistry {
|
|||||||
* 获取所有组件名称到类型的映射
|
* 获取所有组件名称到类型的映射
|
||||||
* @returns 名称到类型的映射
|
* @returns 名称到类型的映射
|
||||||
*/
|
*/
|
||||||
public static getAllComponentNames(): Map<string, Function> {
|
public static getAllComponentNames(): Map<string, ComponentType> {
|
||||||
return new Map(this.componentNameToType);
|
return new Map(this.componentNameToType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +182,7 @@ export class ComponentRegistry {
|
|||||||
return this.maskCache.get(cacheKey)!;
|
return this.maskCache.get(cacheKey)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const name of componentNames) {
|
for (const name of componentNames) {
|
||||||
const componentId = this.getComponentId(name);
|
const componentId = this.getComponentId(name);
|
||||||
if (componentId !== undefined) {
|
if (componentId !== undefined) {
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export class EventBus implements IEventBus {
|
|||||||
handler: (data: T) => Promise<void>,
|
handler: (data: T) => Promise<void>,
|
||||||
config: IEventListenerConfig = {}
|
config: IEventListenerConfig = {}
|
||||||
): string {
|
): string {
|
||||||
return this.on(eventType, handler as any, { ...config, async: true });
|
return this.on(eventType, handler as (data: T) => void, { ...config, async: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -466,4 +466,3 @@ export class GlobalEventBus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3,12 +3,12 @@ import { createLogger } from '../../Utils/Logger';
|
|||||||
/**
|
/**
|
||||||
* 事件处理器函数类型
|
* 事件处理器函数类型
|
||||||
*/
|
*/
|
||||||
export type EventHandler<T = any> = (event: T) => void;
|
export type EventHandler<T = unknown> = (event: T) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步事件处理器函数类型
|
* 异步事件处理器函数类型
|
||||||
*/
|
*/
|
||||||
export type AsyncEventHandler<T = any> = (event: T) => Promise<void>;
|
export type AsyncEventHandler<T = unknown> = (event: T) => Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件监听器配置
|
* 事件监听器配置
|
||||||
@@ -21,13 +21,13 @@ export interface EventListenerConfig {
|
|||||||
/** 是否异步执行 */
|
/** 是否异步执行 */
|
||||||
async?: boolean;
|
async?: boolean;
|
||||||
/** 执行上下文 */
|
/** 执行上下文 */
|
||||||
context?: any;
|
context?: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内部事件监听器
|
* 内部事件监听器
|
||||||
*/
|
*/
|
||||||
interface InternalEventListener<T = any> {
|
interface InternalEventListener<T = unknown> {
|
||||||
handler: EventHandler<T> | AsyncEventHandler<T>;
|
handler: EventHandler<T> | AsyncEventHandler<T>;
|
||||||
config: EventListenerConfig;
|
config: EventListenerConfig;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -71,8 +71,8 @@ export class TypeSafeEventSystem {
|
|||||||
private static readonly _logger = createLogger('EventSystem');
|
private static readonly _logger = createLogger('EventSystem');
|
||||||
private listeners = new Map<string, InternalEventListener[]>();
|
private listeners = new Map<string, InternalEventListener[]>();
|
||||||
private stats = new Map<string, EventStats>();
|
private stats = new Map<string, EventStats>();
|
||||||
private batchQueue = new Map<string, any[]>();
|
private batchQueue = new Map<string, unknown[]>();
|
||||||
private batchTimers = new Map<string, number>();
|
private batchTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
||||||
private batchConfigs = new Map<string, EventBatchConfig>();
|
private batchConfigs = new Map<string, EventBatchConfig>();
|
||||||
private nextListenerId = 0;
|
private nextListenerId = 0;
|
||||||
private isEnabled = true;
|
private isEnabled = true;
|
||||||
@@ -133,7 +133,7 @@ export class TypeSafeEventSystem {
|
|||||||
const listeners = this.listeners.get(eventType);
|
const listeners = this.listeners.get(eventType);
|
||||||
if (!listeners) return false;
|
if (!listeners) return false;
|
||||||
|
|
||||||
const index = listeners.findIndex(l => l.id === listenerId);
|
const index = listeners.findIndex((l) => l.id === listenerId);
|
||||||
if (index === -1) return false;
|
if (index === -1) return false;
|
||||||
|
|
||||||
listeners.splice(index, 1);
|
listeners.splice(index, 1);
|
||||||
@@ -353,7 +353,7 @@ export class TypeSafeEventSystem {
|
|||||||
id: listenerId
|
id: listenerId
|
||||||
};
|
};
|
||||||
|
|
||||||
listeners.push(listener);
|
listeners.push(listener as InternalEventListener);
|
||||||
|
|
||||||
// 初始化统计信息
|
// 初始化统计信息
|
||||||
if (!this.stats.has(eventType)) {
|
if (!this.stats.has(eventType)) {
|
||||||
@@ -379,8 +379,8 @@ export class TypeSafeEventSystem {
|
|||||||
const sortedListeners = this.sortListenersByPriority(listeners);
|
const sortedListeners = this.sortListenersByPriority(listeners);
|
||||||
|
|
||||||
// 分离同步和异步监听器
|
// 分离同步和异步监听器
|
||||||
const syncListeners = sortedListeners.filter(l => !l.config.async);
|
const syncListeners = sortedListeners.filter((l) => !l.config.async);
|
||||||
const asyncListeners = sortedListeners.filter(l => l.config.async);
|
const asyncListeners = sortedListeners.filter((l) => l.config.async);
|
||||||
|
|
||||||
// 执行同步监听器
|
// 执行同步监听器
|
||||||
for (const listener of syncListeners) {
|
for (const listener of syncListeners) {
|
||||||
@@ -447,7 +447,7 @@ export class TypeSafeEventSystem {
|
|||||||
if (!listeners) return;
|
if (!listeners) return;
|
||||||
|
|
||||||
for (const id of listenerIds) {
|
for (const id of listenerIds) {
|
||||||
const index = listeners.findIndex(l => l.id === id);
|
const index = listeners.findIndex((l) => l.id === id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
listeners.splice(index, 1);
|
listeners.splice(index, 1);
|
||||||
}
|
}
|
||||||
@@ -488,7 +488,7 @@ export class TypeSafeEventSystem {
|
|||||||
this.flushBatch(eventType);
|
this.flushBatch(eventType);
|
||||||
}, config.delay);
|
}, config.delay);
|
||||||
|
|
||||||
this.batchTimers.set(eventType, timer as any);
|
this.batchTimers.set(eventType, timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,4 +578,3 @@ export class TypeSafeEventSystem {
|
|||||||
*/
|
*/
|
||||||
export const GlobalEventSystem = new TypeSafeEventSystem();
|
export const GlobalEventSystem = new TypeSafeEventSystem();
|
||||||
|
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ export class ECSFluentAPI {
|
|||||||
componentStats: Map<string, unknown>;
|
componentStats: Map<string, unknown>;
|
||||||
queryStats: unknown;
|
queryStats: unknown;
|
||||||
eventStats: Map<string, unknown>;
|
eventStats: Map<string, unknown>;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
entityCount: this.scene.entities.count,
|
entityCount: this.scene.entities.count,
|
||||||
systemCount: this.scene.systems.length,
|
systemCount: this.scene.systems.length,
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ export class EntityBuilder {
|
|||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.storageManager = storageManager;
|
this.storageManager = storageManager;
|
||||||
const id = scene.identifierPool.checkOut();
|
const id = scene.identifierPool.checkOut();
|
||||||
this.entity = new Entity("", id);
|
this.entity = new Entity('', id);
|
||||||
this.entity.scene = this.scene as any;
|
this.entity.scene = this.scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
export { QuerySystem } from '../QuerySystem';
|
export { QuerySystem } from '../QuerySystem';
|
||||||
export { ECSFluentAPI, createECSAPI } from '../FluentAPI';
|
export { ECSFluentAPI, createECSAPI } from '../FluentAPI';
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ export class QuerySystem {
|
|||||||
if (entities.length === 0) return;
|
if (entities.length === 0) return;
|
||||||
|
|
||||||
// 使用Set来快速检查重复
|
// 使用Set来快速检查重复
|
||||||
const existingIds = new Set(this.entities.map(e => e.id));
|
const existingIds = new Set(this.entities.map((e) => e.id));
|
||||||
let addedCount = 0;
|
let addedCount = 0;
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
@@ -679,7 +679,7 @@ export class QuerySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 多组件查询:使用排序后的类型名称创建键
|
// 多组件查询:使用排序后的类型名称创建键
|
||||||
const sortKey = componentTypes.map(t => {
|
const sortKey = componentTypes.map((t) => {
|
||||||
const name = getComponentTypeName(t);
|
const name = getComponentTypeName(t);
|
||||||
return name;
|
return name;
|
||||||
}).sort().join(',');
|
}).sort().join(',');
|
||||||
@@ -810,7 +810,7 @@ export class QuerySystem {
|
|||||||
*/
|
*/
|
||||||
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
||||||
// 生成缓存键
|
// 生成缓存键
|
||||||
const cacheKey = componentTypes.map(t => {
|
const cacheKey = componentTypes.map((t) => {
|
||||||
return getComponentTypeName(t);
|
return getComponentTypeName(t);
|
||||||
}).sort().join(',');
|
}).sort().join(',');
|
||||||
|
|
||||||
@@ -821,7 +821,7 @@ export class QuerySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致
|
// 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
// 确保组件已注册
|
// 确保组件已注册
|
||||||
if (!ComponentRegistry.isRegistered(type)) {
|
if (!ComponentRegistry.isRegistered(type)) {
|
||||||
@@ -843,11 +843,31 @@ export class QuerySystem {
|
|||||||
return this._version;
|
return this._version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有实体
|
||||||
|
*
|
||||||
|
* 返回场景中的所有实体,不进行任何过滤。
|
||||||
|
*
|
||||||
|
* @returns 所有实体的只读数组
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const allEntities = scene.querySystem.queryAllEntities();
|
||||||
|
* console.log(`场景中共有 ${allEntities.length} 个实体`);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
public queryAllEntities(): readonly Entity[] {
|
||||||
|
return this.entities;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有实体
|
* 获取所有实体
|
||||||
|
*
|
||||||
|
* @deprecated 使用 queryAllEntities() 代替,以保持命名一致性
|
||||||
|
* @see {@link queryAllEntities}
|
||||||
*/
|
*/
|
||||||
public getAllEntities(): readonly Entity[] {
|
public getAllEntities(): readonly Entity[] {
|
||||||
return this.entities;
|
return this.queryAllEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -875,13 +895,17 @@ export class QuerySystem {
|
|||||||
cacheHitRate: string;
|
cacheHitRate: string;
|
||||||
};
|
};
|
||||||
optimizationStats: {
|
optimizationStats: {
|
||||||
archetypeSystem: any;
|
archetypeSystem: Array<{
|
||||||
|
id: BitMask64Data;
|
||||||
|
componentTypes: string[];
|
||||||
|
entityCount: number;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
cacheStats: {
|
cacheStats: {
|
||||||
size: number;
|
size: number;
|
||||||
hitRate: string;
|
hitRate: string;
|
||||||
};
|
};
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
entityCount: this.entities.length,
|
entityCount: this.entities.length,
|
||||||
indexStats: {
|
indexStats: {
|
||||||
@@ -895,9 +919,9 @@ export class QuerySystem {
|
|||||||
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
|
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
|
||||||
},
|
},
|
||||||
optimizationStats: {
|
optimizationStats: {
|
||||||
archetypeSystem: this.archetypeSystem.getAllArchetypes().map(a => ({
|
archetypeSystem: this.archetypeSystem.getAllArchetypes().map((a) => ({
|
||||||
id: a.id,
|
id: a.id,
|
||||||
componentTypes: a.componentTypes.map(t => getComponentTypeName(t)),
|
componentTypes: a.componentTypes.map((t) => getComponentTypeName(t)),
|
||||||
entityCount: a.entities.size
|
entityCount: a.entities.size
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
@@ -1023,7 +1047,7 @@ export class QuerySystem {
|
|||||||
}
|
}
|
||||||
case QueryConditionType.NONE: {
|
case QueryConditionType.NONE: {
|
||||||
const mask = this.createComponentMask(componentTypes);
|
const mask = this.createComponentMask(componentTypes);
|
||||||
return this.entities.filter(entity =>
|
return this.entities.filter((entity) =>
|
||||||
BitMask64Utils.hasNone(entity.componentMask, mask)
|
BitMask64Utils.hasNone(entity.componentMask, mask)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1241,7 +1265,7 @@ export class QueryBuilder {
|
|||||||
* 创建组件掩码
|
* 创建组件掩码
|
||||||
*/
|
*/
|
||||||
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
try {
|
try {
|
||||||
const bitMask = ComponentRegistry.getBitMask(type);
|
const bitMask = ComponentRegistry.getBitMask(type);
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export class ReactiveQuery {
|
|||||||
private generateQueryId(): string {
|
private generateQueryId(): string {
|
||||||
const typeStr = this._condition.type;
|
const typeStr = this._condition.type;
|
||||||
const componentsStr = this._condition.componentTypes
|
const componentsStr = this._condition.componentTypes
|
||||||
.map(t => t.name)
|
.map((t) => t.name)
|
||||||
.sort()
|
.sort()
|
||||||
.join(',');
|
.join(',');
|
||||||
return `${typeStr}:${componentsStr}`;
|
return `${typeStr}:${componentsStr}`;
|
||||||
|
|||||||
@@ -39,15 +39,22 @@ interface IWeakRefConstructor {
|
|||||||
new <T extends object>(target: T): IWeakRef<T>;
|
new <T extends object>(target: T): IWeakRef<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包含 WeakRef 的全局对象类型
|
||||||
|
*/
|
||||||
|
interface GlobalWithWeakRef {
|
||||||
|
WeakRef?: IWeakRefConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WeakRef 实现
|
* WeakRef 实现
|
||||||
*
|
*
|
||||||
* 优先使用原生 WeakRef,不支持时降级到 Polyfill
|
* 优先使用原生 WeakRef,不支持时降级到 Polyfill
|
||||||
*/
|
*/
|
||||||
const WeakRefImpl: IWeakRefConstructor = (
|
const WeakRefImpl: IWeakRefConstructor = (
|
||||||
(typeof globalThis !== 'undefined' && (globalThis as any).WeakRef) ||
|
(typeof globalThis !== 'undefined' && (globalThis as GlobalWithWeakRef).WeakRef) ||
|
||||||
(typeof global !== 'undefined' && (global as any).WeakRef) ||
|
(typeof global !== 'undefined' && (global as unknown as GlobalWithWeakRef).WeakRef) ||
|
||||||
(typeof window !== 'undefined' && (window as any).WeakRef) ||
|
(typeof window !== 'undefined' && (window as unknown as GlobalWithWeakRef).WeakRef) ||
|
||||||
WeakRefPolyfill
|
WeakRefPolyfill
|
||||||
) as IWeakRefConstructor;
|
) as IWeakRefConstructor;
|
||||||
|
|
||||||
@@ -174,6 +181,8 @@ export class ReferenceTracker {
|
|||||||
for (const record of validRecords) {
|
for (const record of validRecords) {
|
||||||
const component = record.component.deref();
|
const component = record.component.deref();
|
||||||
if (component) {
|
if (component) {
|
||||||
|
// 使用 any 进行动态属性访问,因为无法静态验证所有可能的组件属性
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(component as any)[record.propertyKey] = null;
|
(component as any)[record.propertyKey] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,7 +296,7 @@ export class ReferenceTracker {
|
|||||||
* 获取调试信息
|
* 获取调试信息
|
||||||
*/
|
*/
|
||||||
public getDebugInfo(): object {
|
public getDebugInfo(): object {
|
||||||
const info: Record<string, any> = {};
|
const info: Record<string, unknown> = {};
|
||||||
|
|
||||||
for (const [entityId, records] of this._references.entries()) {
|
for (const [entityId, records] of this._references.entries()) {
|
||||||
const validRecords = [];
|
const validRecords = [];
|
||||||
|
|||||||
@@ -2,12 +2,42 @@ import { Component } from '../Component';
|
|||||||
import { ComponentType } from './ComponentStorage';
|
import { ComponentType } from './ComponentStorage';
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import { createLogger } from '../../Utils/Logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 装饰器目标类型,用于存储元数据
|
||||||
|
*/
|
||||||
|
interface DecoratorTarget {
|
||||||
|
constructor: ComponentTypeWithMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带有元数据的组件类型
|
||||||
|
*/
|
||||||
|
interface ComponentTypeWithMetadata {
|
||||||
|
__enableSoA?: boolean;
|
||||||
|
__highPrecisionFields?: Set<string>;
|
||||||
|
__float64Fields?: Set<string>;
|
||||||
|
__float32Fields?: Set<string>;
|
||||||
|
__int32Fields?: Set<string>;
|
||||||
|
__uint32Fields?: Set<string>;
|
||||||
|
__int16Fields?: Set<string>;
|
||||||
|
__uint16Fields?: Set<string>;
|
||||||
|
__int8Fields?: Set<string>;
|
||||||
|
__uint8Fields?: Set<string>;
|
||||||
|
__uint8ClampedFields?: Set<string>;
|
||||||
|
__serializeMapFields?: Set<string>;
|
||||||
|
__serializeSetFields?: Set<string>;
|
||||||
|
__serializeArrayFields?: Set<string>;
|
||||||
|
__deepCopyFields?: Set<string>;
|
||||||
|
__autoTypedFields?: Map<string, Record<string, unknown>>;
|
||||||
|
__bigIntFields?: Set<string>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启用SoA优化装饰器
|
* 启用SoA优化装饰器
|
||||||
* 默认关闭SoA,只有在大规模批量操作场景下才建议开启
|
* 默认关闭SoA,只有在大规模批量操作场景下才建议开启
|
||||||
*/
|
*/
|
||||||
export function EnableSoA<T extends ComponentType>(target: T): T {
|
export function EnableSoA<T extends ComponentType>(target: T): T {
|
||||||
(target as any).__enableSoA = true;
|
(target as unknown as { __enableSoA: boolean }).__enableSoA = true;
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,7 +46,7 @@ export function EnableSoA<T extends ComponentType>(target: T): T {
|
|||||||
* 高精度数值装饰器
|
* 高精度数值装饰器
|
||||||
* 标记字段需要保持完整精度,存储为复杂对象而非TypedArray
|
* 标记字段需要保持完整精度,存储为复杂对象而非TypedArray
|
||||||
*/
|
*/
|
||||||
export function HighPrecision(target: any, propertyKey: string | symbol): void {
|
export function HighPrecision(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__highPrecisionFields) {
|
if (!target.constructor.__highPrecisionFields) {
|
||||||
target.constructor.__highPrecisionFields = new Set();
|
target.constructor.__highPrecisionFields = new Set();
|
||||||
@@ -28,7 +58,7 @@ export function HighPrecision(target: any, propertyKey: string | symbol): void {
|
|||||||
* 64位浮点数装饰器
|
* 64位浮点数装饰器
|
||||||
* 标记字段使用Float64Array存储(更高精度但更多内存)
|
* 标记字段使用Float64Array存储(更高精度但更多内存)
|
||||||
*/
|
*/
|
||||||
export function Float64(target: any, propertyKey: string | symbol): void {
|
export function Float64(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__float64Fields) {
|
if (!target.constructor.__float64Fields) {
|
||||||
target.constructor.__float64Fields = new Set();
|
target.constructor.__float64Fields = new Set();
|
||||||
@@ -40,7 +70,7 @@ export function Float64(target: any, propertyKey: string | symbol): void {
|
|||||||
* 32位浮点数装饰器
|
* 32位浮点数装饰器
|
||||||
* 标记字段使用Float32Array存储(默认类型,平衡性能和精度)
|
* 标记字段使用Float32Array存储(默认类型,平衡性能和精度)
|
||||||
*/
|
*/
|
||||||
export function Float32(target: any, propertyKey: string | symbol): void {
|
export function Float32(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__float32Fields) {
|
if (!target.constructor.__float32Fields) {
|
||||||
target.constructor.__float32Fields = new Set();
|
target.constructor.__float32Fields = new Set();
|
||||||
@@ -52,7 +82,7 @@ export function Float32(target: any, propertyKey: string | symbol): void {
|
|||||||
* 32位整数装饰器
|
* 32位整数装饰器
|
||||||
* 标记字段使用Int32Array存储(适用于整数值)
|
* 标记字段使用Int32Array存储(适用于整数值)
|
||||||
*/
|
*/
|
||||||
export function Int32(target: any, propertyKey: string | symbol): void {
|
export function Int32(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__int32Fields) {
|
if (!target.constructor.__int32Fields) {
|
||||||
target.constructor.__int32Fields = new Set();
|
target.constructor.__int32Fields = new Set();
|
||||||
@@ -64,7 +94,7 @@ export function Int32(target: any, propertyKey: string | symbol): void {
|
|||||||
* 32位无符号整数装饰器
|
* 32位无符号整数装饰器
|
||||||
* 标记字段使用Uint32Array存储(适用于无符号整数,如ID、标志位等)
|
* 标记字段使用Uint32Array存储(适用于无符号整数,如ID、标志位等)
|
||||||
*/
|
*/
|
||||||
export function Uint32(target: any, propertyKey: string | symbol): void {
|
export function Uint32(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__uint32Fields) {
|
if (!target.constructor.__uint32Fields) {
|
||||||
target.constructor.__uint32Fields = new Set();
|
target.constructor.__uint32Fields = new Set();
|
||||||
@@ -76,7 +106,7 @@ export function Uint32(target: any, propertyKey: string | symbol): void {
|
|||||||
* 16位整数装饰器
|
* 16位整数装饰器
|
||||||
* 标记字段使用Int16Array存储(适用于小范围整数)
|
* 标记字段使用Int16Array存储(适用于小范围整数)
|
||||||
*/
|
*/
|
||||||
export function Int16(target: any, propertyKey: string | symbol): void {
|
export function Int16(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__int16Fields) {
|
if (!target.constructor.__int16Fields) {
|
||||||
target.constructor.__int16Fields = new Set();
|
target.constructor.__int16Fields = new Set();
|
||||||
@@ -88,7 +118,7 @@ export function Int16(target: any, propertyKey: string | symbol): void {
|
|||||||
* 16位无符号整数装饰器
|
* 16位无符号整数装饰器
|
||||||
* 标记字段使用Uint16Array存储(适用于小范围无符号整数)
|
* 标记字段使用Uint16Array存储(适用于小范围无符号整数)
|
||||||
*/
|
*/
|
||||||
export function Uint16(target: any, propertyKey: string | symbol): void {
|
export function Uint16(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__uint16Fields) {
|
if (!target.constructor.__uint16Fields) {
|
||||||
target.constructor.__uint16Fields = new Set();
|
target.constructor.__uint16Fields = new Set();
|
||||||
@@ -100,7 +130,7 @@ export function Uint16(target: any, propertyKey: string | symbol): void {
|
|||||||
* 8位整数装饰器
|
* 8位整数装饰器
|
||||||
* 标记字段使用Int8Array存储(适用于很小的整数值)
|
* 标记字段使用Int8Array存储(适用于很小的整数值)
|
||||||
*/
|
*/
|
||||||
export function Int8(target: any, propertyKey: string | symbol): void {
|
export function Int8(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__int8Fields) {
|
if (!target.constructor.__int8Fields) {
|
||||||
target.constructor.__int8Fields = new Set();
|
target.constructor.__int8Fields = new Set();
|
||||||
@@ -112,7 +142,7 @@ export function Int8(target: any, propertyKey: string | symbol): void {
|
|||||||
* 8位无符号整数装饰器
|
* 8位无符号整数装饰器
|
||||||
* 标记字段使用Uint8Array存储(适用于字节值、布尔标志等)
|
* 标记字段使用Uint8Array存储(适用于字节值、布尔标志等)
|
||||||
*/
|
*/
|
||||||
export function Uint8(target: any, propertyKey: string | symbol): void {
|
export function Uint8(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__uint8Fields) {
|
if (!target.constructor.__uint8Fields) {
|
||||||
target.constructor.__uint8Fields = new Set();
|
target.constructor.__uint8Fields = new Set();
|
||||||
@@ -124,7 +154,7 @@ export function Uint8(target: any, propertyKey: string | symbol): void {
|
|||||||
* 8位夹紧整数装饰器
|
* 8位夹紧整数装饰器
|
||||||
* 标记字段使用Uint8ClampedArray存储(适用于颜色值等需要夹紧的数据)
|
* 标记字段使用Uint8ClampedArray存储(适用于颜色值等需要夹紧的数据)
|
||||||
*/
|
*/
|
||||||
export function Uint8Clamped(target: any, propertyKey: string | symbol): void {
|
export function Uint8Clamped(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__uint8ClampedFields) {
|
if (!target.constructor.__uint8ClampedFields) {
|
||||||
target.constructor.__uint8ClampedFields = new Set();
|
target.constructor.__uint8ClampedFields = new Set();
|
||||||
@@ -137,7 +167,7 @@ export function Uint8Clamped(target: any, propertyKey: string | symbol): void {
|
|||||||
* 序列化Map装饰器
|
* 序列化Map装饰器
|
||||||
* 标记Map字段需要序列化/反序列化存储
|
* 标记Map字段需要序列化/反序列化存储
|
||||||
*/
|
*/
|
||||||
export function SerializeMap(target: any, propertyKey: string | symbol): void {
|
export function SerializeMap(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__serializeMapFields) {
|
if (!target.constructor.__serializeMapFields) {
|
||||||
target.constructor.__serializeMapFields = new Set();
|
target.constructor.__serializeMapFields = new Set();
|
||||||
@@ -149,7 +179,7 @@ export function SerializeMap(target: any, propertyKey: string | symbol): void {
|
|||||||
* 序列化Set装饰器
|
* 序列化Set装饰器
|
||||||
* 标记Set字段需要序列化/反序列化存储
|
* 标记Set字段需要序列化/反序列化存储
|
||||||
*/
|
*/
|
||||||
export function SerializeSet(target: any, propertyKey: string | symbol): void {
|
export function SerializeSet(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__serializeSetFields) {
|
if (!target.constructor.__serializeSetFields) {
|
||||||
target.constructor.__serializeSetFields = new Set();
|
target.constructor.__serializeSetFields = new Set();
|
||||||
@@ -161,7 +191,7 @@ export function SerializeSet(target: any, propertyKey: string | symbol): void {
|
|||||||
* 序列化Array装饰器
|
* 序列化Array装饰器
|
||||||
* 标记Array字段需要序列化/反序列化存储
|
* 标记Array字段需要序列化/反序列化存储
|
||||||
*/
|
*/
|
||||||
export function SerializeArray(target: any, propertyKey: string | symbol): void {
|
export function SerializeArray(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__serializeArrayFields) {
|
if (!target.constructor.__serializeArrayFields) {
|
||||||
target.constructor.__serializeArrayFields = new Set();
|
target.constructor.__serializeArrayFields = new Set();
|
||||||
@@ -173,7 +203,7 @@ export function SerializeArray(target: any, propertyKey: string | symbol): void
|
|||||||
* 深拷贝装饰器
|
* 深拷贝装饰器
|
||||||
* 标记字段需要深拷贝处理(适用于嵌套对象)
|
* 标记字段需要深拷贝处理(适用于嵌套对象)
|
||||||
*/
|
*/
|
||||||
export function DeepCopy(target: any, propertyKey: string | symbol): void {
|
export function DeepCopy(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__deepCopyFields) {
|
if (!target.constructor.__deepCopyFields) {
|
||||||
target.constructor.__deepCopyFields = new Set();
|
target.constructor.__deepCopyFields = new Set();
|
||||||
@@ -197,7 +227,7 @@ export function AutoTyped(options?: {
|
|||||||
precision?: boolean;
|
precision?: boolean;
|
||||||
signed?: boolean;
|
signed?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return function (target: any, propertyKey: string | symbol): void {
|
return function (target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||||
const key = String(propertyKey);
|
const key = String(propertyKey);
|
||||||
if (!target.constructor.__autoTypedFields) {
|
if (!target.constructor.__autoTypedFields) {
|
||||||
target.constructor.__autoTypedFields = new Map();
|
target.constructor.__autoTypedFields = new Map();
|
||||||
@@ -214,6 +244,7 @@ export class TypeInference {
|
|||||||
/**
|
/**
|
||||||
* 根据数值范围推断最优的TypedArray类型
|
* 根据数值范围推断最优的TypedArray类型
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
public static inferOptimalType(value: any, options: {
|
public static inferOptimalType(value: any, options: {
|
||||||
minValue?: number;
|
minValue?: number;
|
||||||
maxValue?: number;
|
maxValue?: number;
|
||||||
@@ -338,7 +369,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
private fields = new Map<string, SupportedTypedArray>();
|
private fields = new Map<string, SupportedTypedArray>();
|
||||||
private stringFields = new Map<string, string[]>(); // 专门存储字符串
|
private stringFields = new Map<string, string[]>(); // 专门存储字符串
|
||||||
private serializedFields = new Map<string, string[]>(); // 序列化存储Map/Set/Array
|
private serializedFields = new Map<string, string[]>(); // 序列化存储Map/Set/Array
|
||||||
private complexFields = new Map<number, Map<string, any>>(); // 存储复杂对象
|
private complexFields = new Map<number, Map<string, unknown>>(); // 存储复杂对象
|
||||||
private entityToIndex = new Map<number, number>();
|
private entityToIndex = new Map<number, number>();
|
||||||
private indexToEntity: number[] = [];
|
private indexToEntity: number[] = [];
|
||||||
private freeIndices: number[] = [];
|
private freeIndices: number[] = [];
|
||||||
@@ -353,24 +384,24 @@ export class SoAStorage<T extends Component> {
|
|||||||
|
|
||||||
private initializeFields(componentType: ComponentType<T>): void {
|
private initializeFields(componentType: ComponentType<T>): void {
|
||||||
const instance = new componentType();
|
const instance = new componentType();
|
||||||
const highPrecisionFields = (componentType as any).__highPrecisionFields || new Set();
|
const highPrecisionFields = (componentType as unknown as ComponentTypeWithMetadata).__highPrecisionFields || new Set();
|
||||||
const float64Fields = (componentType as any).__float64Fields || new Set();
|
const float64Fields = (componentType as unknown as ComponentTypeWithMetadata).__float64Fields || new Set();
|
||||||
const float32Fields = (componentType as any).__float32Fields || new Set();
|
const float32Fields = (componentType as unknown as ComponentTypeWithMetadata).__float32Fields || new Set();
|
||||||
const int32Fields = (componentType as any).__int32Fields || new Set();
|
const int32Fields = (componentType as unknown as ComponentTypeWithMetadata).__int32Fields || new Set();
|
||||||
const uint32Fields = (componentType as any).__uint32Fields || new Set();
|
const uint32Fields = (componentType as unknown as ComponentTypeWithMetadata).__uint32Fields || new Set();
|
||||||
const int16Fields = (componentType as any).__int16Fields || new Set();
|
const int16Fields = (componentType as unknown as ComponentTypeWithMetadata).__int16Fields || new Set();
|
||||||
const uint16Fields = (componentType as any).__uint16Fields || new Set();
|
const uint16Fields = (componentType as unknown as ComponentTypeWithMetadata).__uint16Fields || new Set();
|
||||||
const int8Fields = (componentType as any).__int8Fields || new Set();
|
const int8Fields = (componentType as unknown as ComponentTypeWithMetadata).__int8Fields || new Set();
|
||||||
const uint8Fields = (componentType as any).__uint8Fields || new Set();
|
const uint8Fields = (componentType as unknown as ComponentTypeWithMetadata).__uint8Fields || new Set();
|
||||||
const uint8ClampedFields = (componentType as any).__uint8ClampedFields || new Set();
|
const uint8ClampedFields = (componentType as unknown as ComponentTypeWithMetadata).__uint8ClampedFields || new Set();
|
||||||
const autoTypedFields = (componentType as any).__autoTypedFields || new Map();
|
const autoTypedFields = (componentType as unknown as ComponentTypeWithMetadata).__autoTypedFields || new Map();
|
||||||
const serializeMapFields = (componentType as any).__serializeMapFields || new Set();
|
const serializeMapFields = (componentType as unknown as ComponentTypeWithMetadata).__serializeMapFields || new Set();
|
||||||
const serializeSetFields = (componentType as any).__serializeSetFields || new Set();
|
const serializeSetFields = (componentType as unknown as ComponentTypeWithMetadata).__serializeSetFields || new Set();
|
||||||
const serializeArrayFields = (componentType as any).__serializeArrayFields || new Set();
|
const serializeArrayFields = (componentType as unknown as ComponentTypeWithMetadata).__serializeArrayFields || new Set();
|
||||||
// const deepCopyFields = (componentType as any).__deepCopyFields || new Set(); // 未使用,但保留供future使用
|
// const deepCopyFields = (componentType as unknown as ComponentTypeWithMetadata).__deepCopyFields || new Set(); // 未使用,但保留供future使用
|
||||||
|
|
||||||
for (const key in instance) {
|
for (const key in instance) {
|
||||||
if (instance.hasOwnProperty(key) && key !== 'id') {
|
if (Object.prototype.hasOwnProperty.call(instance, key) && key !== 'id') {
|
||||||
const value = (instance as any)[key];
|
const value = (instance as any)[key];
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
|
|
||||||
@@ -473,7 +504,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
|
|
||||||
// 处理所有字段
|
// 处理所有字段
|
||||||
for (const key in component) {
|
for (const key in component) {
|
||||||
if (component.hasOwnProperty(key) && key !== 'id') {
|
if (Object.prototype.hasOwnProperty.call(component, key) && key !== 'id') {
|
||||||
const value = (component as any)[key];
|
const value = (component as any)[key];
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
|
|
||||||
@@ -578,7 +609,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof Array) {
|
if (obj instanceof Array) {
|
||||||
return obj.map(item => this.deepClone(item));
|
return obj.map((item) => this.deepClone(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof Map) {
|
if (obj instanceof Map) {
|
||||||
@@ -600,7 +631,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
// 普通对象
|
// 普通对象
|
||||||
const cloned: any = {};
|
const cloned: any = {};
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
if (obj.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||||
cloned[key] = this.deepClone(obj[key]);
|
cloned[key] = this.deepClone(obj[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type {Component} from '../Component';
|
import type { Component } from '../Component';
|
||||||
import type {EntitySystem} from '../Systems';
|
import type { EntitySystem } from '../Systems';
|
||||||
import {ComponentType} from "../../Types";
|
import { ComponentType } from '../../Types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储组件类型名称的Symbol键
|
* 存储组件类型名称的Symbol键
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ export class EntityComparer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 游戏实体类
|
* 游戏实体类
|
||||||
*
|
*
|
||||||
@@ -103,7 +102,16 @@ export class Entity {
|
|||||||
/**
|
/**
|
||||||
* 销毁状态标志
|
* 销毁状态标志
|
||||||
*/
|
*/
|
||||||
public _isDestroyed: boolean = false;
|
private _destroyed: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置销毁状态(仅供框架内部使用)
|
||||||
|
*
|
||||||
|
* @internal 此方法仅用于批量销毁优化,不应在外部调用
|
||||||
|
*/
|
||||||
|
public setDestroyed(value: boolean): void {
|
||||||
|
this._destroyed = value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 父实体引用
|
* 父实体引用
|
||||||
@@ -161,7 +169,7 @@ export class Entity {
|
|||||||
* @returns 如果实体已被销毁则返回true
|
* @returns 如果实体已被销毁则返回true
|
||||||
*/
|
*/
|
||||||
public get isDestroyed(): boolean {
|
public get isDestroyed(): boolean {
|
||||||
return this._isDestroyed;
|
return this._destroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -394,11 +402,11 @@ export class Entity {
|
|||||||
const componentType = component.constructor as ComponentType<T>;
|
const componentType = component.constructor as ComponentType<T>;
|
||||||
|
|
||||||
if (!this.scene) {
|
if (!this.scene) {
|
||||||
throw new Error(`Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()`);
|
throw new Error('Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.scene.componentStorageManager) {
|
if (!this.scene.componentStorageManager) {
|
||||||
throw new Error(`Scene does not have componentStorageManager`);
|
throw new Error('Scene does not have componentStorageManager');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasComponent(componentType)) {
|
if (this.hasComponent(componentType)) {
|
||||||
@@ -465,8 +473,6 @@ export class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查实体是否拥有指定类型的组件
|
* 检查实体是否拥有指定类型的组件
|
||||||
*
|
*
|
||||||
@@ -646,7 +652,6 @@ export class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有指定类型的组件
|
* 获取所有指定类型的组件
|
||||||
*
|
*
|
||||||
@@ -700,7 +705,7 @@ export class Entity {
|
|||||||
*/
|
*/
|
||||||
public addChild(child: Entity): Entity {
|
public addChild(child: Entity): Entity {
|
||||||
if (child === this) {
|
if (child === this) {
|
||||||
throw new Error("Entity cannot be its own child");
|
throw new Error('Entity cannot be its own child');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child._parent === this) {
|
if (child._parent === this) {
|
||||||
@@ -898,11 +903,11 @@ export class Entity {
|
|||||||
* 移除所有组件、子实体并标记为已销毁
|
* 移除所有组件、子实体并标记为已销毁
|
||||||
*/
|
*/
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
if (this._isDestroyed) {
|
if (this._destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isDestroyed = true;
|
this._destroyed = true;
|
||||||
|
|
||||||
if (this.scene && this.scene.referenceTracker) {
|
if (this.scene && this.scene.referenceTracker) {
|
||||||
this.scene.referenceTracker.clearReferencesTo(this.id);
|
this.scene.referenceTracker.clearReferencesTo(this.id);
|
||||||
@@ -949,7 +954,7 @@ export class Entity {
|
|||||||
collectChildren(this);
|
collectChildren(this);
|
||||||
|
|
||||||
for (const entity of toDestroy) {
|
for (const entity of toDestroy) {
|
||||||
entity._isDestroyed = true;
|
entity.setDestroyed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entity of toDestroy) {
|
for (const entity of toDestroy) {
|
||||||
@@ -1007,20 +1012,20 @@ export class Entity {
|
|||||||
childIds: number[];
|
childIds: number[];
|
||||||
depth: number;
|
depth: number;
|
||||||
cacheBuilt: boolean;
|
cacheBuilt: boolean;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
id: this.id,
|
id: this.id,
|
||||||
enabled: this._enabled,
|
enabled: this._enabled,
|
||||||
active: this._active,
|
active: this._active,
|
||||||
activeInHierarchy: this.activeInHierarchy,
|
activeInHierarchy: this.activeInHierarchy,
|
||||||
destroyed: this._isDestroyed,
|
destroyed: this._destroyed,
|
||||||
componentCount: this.components.length,
|
componentCount: this.components.length,
|
||||||
componentTypes: this.components.map(c => getComponentInstanceTypeName(c)),
|
componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)),
|
||||||
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
|
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
|
||||||
parentId: this._parent?.id || null,
|
parentId: this._parent?.id || null,
|
||||||
childCount: this._children.length,
|
childCount: this._children.length,
|
||||||
childIds: this._children.map(c => c.id),
|
childIds: this._children.map((c) => c.id),
|
||||||
depth: this.getDepth(),
|
depth: this.getDepth(),
|
||||||
cacheBuilt: this._componentCache !== null
|
cacheBuilt: this._componentCache !== null
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { TypeSafeEventSystem } from './Core/EventSystem';
|
|||||||
import { EventBus } from './Core/EventBus';
|
import { EventBus } from './Core/EventBus';
|
||||||
import { ReferenceTracker } from './Core/ReferenceTracker';
|
import { ReferenceTracker } from './Core/ReferenceTracker';
|
||||||
import { IScene, ISceneConfig } from './IScene';
|
import { IScene, ISceneConfig } from './IScene';
|
||||||
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from "./Decorators";
|
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from './Decorators';
|
||||||
import { TypedQueryBuilder } from './Core/Query/TypedQuery';
|
import { TypedQueryBuilder } from './Core/Query/TypedQuery';
|
||||||
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
|
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
|
||||||
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
|
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
|
||||||
@@ -30,7 +30,7 @@ export class Scene implements IScene {
|
|||||||
*
|
*
|
||||||
* 用于标识和调试的友好名称。
|
* 用于标识和调试的友好名称。
|
||||||
*/
|
*/
|
||||||
public name: string = "";
|
public name: string = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景自定义数据
|
* 场景自定义数据
|
||||||
@@ -338,7 +338,7 @@ export class Scene implements IScene {
|
|||||||
* @param name 实体名称
|
* @param name 实体名称
|
||||||
*/
|
*/
|
||||||
public createEntity(name: string) {
|
public createEntity(name: string) {
|
||||||
let entity = new Entity(name, this.identifierPool.checkOut());
|
const entity = new Entity(name, this.identifierPool.checkOut());
|
||||||
|
|
||||||
this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this });
|
this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this });
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ export class Scene implements IScene {
|
|||||||
* @param namePrefix 实体名称前缀
|
* @param namePrefix 实体名称前缀
|
||||||
* @returns 创建的实体列表
|
* @returns 创建的实体列表
|
||||||
*/
|
*/
|
||||||
public createEntities(count: number, namePrefix: string = "Entity"): Entity[] {
|
public createEntities(count: number, namePrefix: string = 'Entity'): Entity[] {
|
||||||
const entities: Entity[] = [];
|
const entities: Entity[] = [];
|
||||||
|
|
||||||
// 批量创建实体对象,不立即添加到系统
|
// 批量创建实体对象,不立即添加到系统
|
||||||
@@ -416,7 +416,7 @@ export class Scene implements IScene {
|
|||||||
if (entities.length === 0) return;
|
if (entities.length === 0) return;
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
entity._isDestroyed = true;
|
entity.setDestroyed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
@@ -609,7 +609,7 @@ export class Scene implements IScene {
|
|||||||
} else {
|
} else {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`Attempting to register a different instance of ${constructor.name}, ` +
|
`Attempting to register a different instance of ${constructor.name}, ` +
|
||||||
`but type is already registered. Returning existing instance.`
|
'but type is already registered. Returning existing instance.'
|
||||||
);
|
);
|
||||||
return existingSystem as T;
|
return existingSystem as T;
|
||||||
}
|
}
|
||||||
@@ -750,7 +750,7 @@ export class Scene implements IScene {
|
|||||||
entityCount: number;
|
entityCount: number;
|
||||||
processorCount: number;
|
processorCount: number;
|
||||||
componentStorageStats: Map<string, any>;
|
componentStorageStats: Map<string, any>;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
entityCount: this.entities.count,
|
entityCount: this.entities.count,
|
||||||
processorCount: this.systems.length,
|
processorCount: this.systems.length,
|
||||||
@@ -779,20 +779,20 @@ export class Scene implements IScene {
|
|||||||
entityCount: number;
|
entityCount: number;
|
||||||
}>;
|
}>;
|
||||||
componentStats: Map<string, any>;
|
componentStats: Map<string, any>;
|
||||||
} {
|
} {
|
||||||
const systems = this.systems;
|
const systems = this.systems;
|
||||||
return {
|
return {
|
||||||
name: this.name || this.constructor.name,
|
name: this.name || this.constructor.name,
|
||||||
entityCount: this.entities.count,
|
entityCount: this.entities.count,
|
||||||
processorCount: systems.length,
|
processorCount: systems.length,
|
||||||
isRunning: this._didSceneBegin,
|
isRunning: this._didSceneBegin,
|
||||||
entities: this.entities.buffer.map(entity => ({
|
entities: this.entities.buffer.map((entity) => ({
|
||||||
name: entity.name,
|
name: entity.name,
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
componentCount: entity.components.length,
|
componentCount: entity.components.length,
|
||||||
componentTypes: entity.components.map(c => getComponentInstanceTypeName(c))
|
componentTypes: entity.components.map((c) => getComponentInstanceTypeName(c))
|
||||||
})),
|
})),
|
||||||
processors: systems.map(processor => ({
|
processors: systems.map((processor) => ({
|
||||||
name: getSystemInstanceTypeName(processor),
|
name: getSystemInstanceTypeName(processor),
|
||||||
updateOrder: processor.updateOrder,
|
updateOrder: processor.updateOrder,
|
||||||
entityCount: (processor as any)._entities?.length || 0
|
entityCount: (processor as any)._entities?.length || 0
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ export class ComponentSerializer {
|
|||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(item => this.serializeValue(item));
|
return value.map((item) => this.serializeValue(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map (如果没有使用@SerializeMap装饰器)
|
// Map (如果没有使用@SerializeMap装饰器)
|
||||||
@@ -276,7 +276,7 @@ export class ComponentSerializer {
|
|||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(item => this.deserializeValue(item));
|
return value.map((item) => this.deserializeValue(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 普通对象
|
// 普通对象
|
||||||
@@ -340,10 +340,10 @@ export class ComponentSerializer {
|
|||||||
return {
|
return {
|
||||||
type: metadata.options.typeId || getComponentTypeName(componentType),
|
type: metadata.options.typeId || getComponentTypeName(componentType),
|
||||||
version: metadata.options.version,
|
version: metadata.options.version,
|
||||||
fields: Array.from(metadata.fields.keys()).map(k =>
|
fields: Array.from(metadata.fields.keys()).map((k) =>
|
||||||
typeof k === 'symbol' ? k.toString() : k
|
typeof k === 'symbol' ? k.toString() : k
|
||||||
),
|
),
|
||||||
ignoredFields: Array.from(metadata.ignoredFields).map(k =>
|
ignoredFields: Array.from(metadata.ignoredFields).map((k) =>
|
||||||
typeof k === 'symbol' ? k.toString() : k
|
typeof k === 'symbol' ? k.toString() : k
|
||||||
),
|
),
|
||||||
isSerializable: true
|
isSerializable: true
|
||||||
|
|||||||
@@ -696,22 +696,22 @@ export class IncrementalSerializer {
|
|||||||
componentChanges: incremental.componentChanges.length,
|
componentChanges: incremental.componentChanges.length,
|
||||||
sceneDataChanges: incremental.sceneDataChanges.length,
|
sceneDataChanges: incremental.sceneDataChanges.length,
|
||||||
addedEntities: incremental.entityChanges.filter(
|
addedEntities: incremental.entityChanges.filter(
|
||||||
c => c.operation === ChangeOperation.EntityAdded
|
(c) => c.operation === ChangeOperation.EntityAdded
|
||||||
).length,
|
).length,
|
||||||
removedEntities: incremental.entityChanges.filter(
|
removedEntities: incremental.entityChanges.filter(
|
||||||
c => c.operation === ChangeOperation.EntityRemoved
|
(c) => c.operation === ChangeOperation.EntityRemoved
|
||||||
).length,
|
).length,
|
||||||
updatedEntities: incremental.entityChanges.filter(
|
updatedEntities: incremental.entityChanges.filter(
|
||||||
c => c.operation === ChangeOperation.EntityUpdated
|
(c) => c.operation === ChangeOperation.EntityUpdated
|
||||||
).length,
|
).length,
|
||||||
addedComponents: incremental.componentChanges.filter(
|
addedComponents: incremental.componentChanges.filter(
|
||||||
c => c.operation === ChangeOperation.ComponentAdded
|
(c) => c.operation === ChangeOperation.ComponentAdded
|
||||||
).length,
|
).length,
|
||||||
removedComponents: incremental.componentChanges.filter(
|
removedComponents: incremental.componentChanges.filter(
|
||||||
c => c.operation === ChangeOperation.ComponentRemoved
|
(c) => c.operation === ChangeOperation.ComponentRemoved
|
||||||
).length,
|
).length,
|
||||||
updatedComponents: incremental.componentChanges.filter(
|
updatedComponents: incremental.componentChanges.filter(
|
||||||
c => c.operation === ChangeOperation.ComponentUpdated
|
(c) => c.operation === ChangeOperation.ComponentUpdated
|
||||||
).length
|
).length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,14 +363,14 @@ export class SceneSerializer {
|
|||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(item => this.serializeValue(item));
|
return value.map((item) => this.serializeValue(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 普通对象
|
// 普通对象
|
||||||
if (type === 'object') {
|
if (type === 'object') {
|
||||||
const result: Record<string, any> = {};
|
const result: Record<string, any> = {};
|
||||||
for (const key in value) {
|
for (const key in value) {
|
||||||
if (value.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
||||||
result[key] = this.serializeValue(value[key]);
|
result[key] = this.serializeValue(value[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,14 +409,14 @@ export class SceneSerializer {
|
|||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(item => this.deserializeValue(item));
|
return value.map((item) => this.deserializeValue(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 普通对象
|
// 普通对象
|
||||||
if (type === 'object') {
|
if (type === 'object') {
|
||||||
const result: Record<string, any> = {};
|
const result: Record<string, any> = {};
|
||||||
for (const key in value) {
|
for (const key in value) {
|
||||||
if (value.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
||||||
result[key] = this.deserializeValue(value[key]);
|
result[key] = this.deserializeValue(value[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -437,8 +437,8 @@ export class SceneSerializer {
|
|||||||
const componentTypeSet = new Set(options.components);
|
const componentTypeSet = new Set(options.components);
|
||||||
|
|
||||||
// 只返回拥有指定组件的实体
|
// 只返回拥有指定组件的实体
|
||||||
return entities.filter(entity => {
|
return entities.filter((entity) => {
|
||||||
return Array.from(entity.components).some(component =>
|
return Array.from(entity.components).some((component) =>
|
||||||
componentTypeSet.has(component.constructor as ComponentType)
|
componentTypeSet.has(component.constructor as ComponentType)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export class VersionMigrationManager {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
let migratedData = { ...component };
|
const migratedData = { ...component };
|
||||||
let version = currentVersion;
|
let version = currentVersion;
|
||||||
|
|
||||||
// 执行迁移链
|
// 执行迁移链
|
||||||
@@ -193,12 +193,12 @@ export class VersionMigrationManager {
|
|||||||
private static migrateSceneComponents(scene: SerializedScene): SerializedScene {
|
private static migrateSceneComponents(scene: SerializedScene): SerializedScene {
|
||||||
const migratedScene = { ...scene };
|
const migratedScene = { ...scene };
|
||||||
|
|
||||||
migratedScene.entities = scene.entities.map(entity => ({
|
migratedScene.entities = scene.entities.map((entity) => ({
|
||||||
...entity,
|
...entity,
|
||||||
components: entity.components.map(component => {
|
components: entity.components.map((component) => {
|
||||||
// 查找组件的目标版本
|
// 查找组件的目标版本
|
||||||
const typeInfo = scene.componentTypeRegistry.find(
|
const typeInfo = scene.componentTypeRegistry.find(
|
||||||
t => t.typeName === component.type
|
(t) => t.typeName === component.type
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeInfo && typeInfo.version !== component.version) {
|
if (typeInfo && typeInfo.version !== component.version) {
|
||||||
@@ -220,10 +220,10 @@ export class VersionMigrationManager {
|
|||||||
entities: any[],
|
entities: any[],
|
||||||
typeRegistry: Array<{ typeName: string; version: number }>
|
typeRegistry: Array<{ typeName: string; version: number }>
|
||||||
): any[] {
|
): any[] {
|
||||||
return entities.map(entity => ({
|
return entities.map((entity) => ({
|
||||||
...entity,
|
...entity,
|
||||||
components: entity.components.map((component: SerializedComponent) => {
|
components: entity.components.map((component: SerializedComponent) => {
|
||||||
const typeInfo = typeRegistry.find(t => t.typeName === component.type);
|
const typeInfo = typeRegistry.find((t) => t.typeName === component.type);
|
||||||
|
|
||||||
if (typeInfo && typeInfo.version !== component.version) {
|
if (typeInfo && typeInfo.version !== component.version) {
|
||||||
return this.migrateComponent(component, typeInfo.version);
|
return this.migrateComponent(component, typeInfo.version);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { createLogger } from '../../Utils/Logger';
|
|||||||
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
|
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
|
||||||
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
|
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
|
||||||
import type { IService } from '../../Core/ServiceContainer';
|
import type { IService } from '../../Core/ServiceContainer';
|
||||||
|
import type { ComponentType } from '../Core/ComponentStorage';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件监听器记录
|
* 事件监听器记录
|
||||||
@@ -259,8 +260,11 @@ export abstract class EntitySystem<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除实体缓存(内部使用)
|
* 清除实体缓存
|
||||||
* 当Scene中的实体发生变化时调用
|
*
|
||||||
|
* 当 Scene 中的实体发生变化时调用,使系统的实体缓存失效。
|
||||||
|
*
|
||||||
|
* @internal 框架内部使用,不应在外部代码中直接调用
|
||||||
*/
|
*/
|
||||||
public clearEntityCache(): void {
|
public clearEntityCache(): void {
|
||||||
this._entityCache.invalidate();
|
this._entityCache.invalidate();
|
||||||
@@ -299,7 +303,7 @@ export abstract class EntitySystem<
|
|||||||
|
|
||||||
// 空条件返回所有实体
|
// 空条件返回所有实体
|
||||||
if (this._matcher.isEmpty()) {
|
if (this._matcher.isEmpty()) {
|
||||||
currentEntities = querySystem.getAllEntities();
|
currentEntities = querySystem.queryAllEntities();
|
||||||
} else if (this.isSingleCondition(condition)) {
|
} else if (this.isSingleCondition(condition)) {
|
||||||
// 单一条件优化查询
|
// 单一条件优化查询
|
||||||
currentEntities = this.executeSingleConditionQuery(condition, querySystem);
|
currentEntities = this.executeSingleConditionQuery(condition, querySystem);
|
||||||
@@ -403,7 +407,7 @@ export abstract class EntitySystem<
|
|||||||
// 6. 应用none条件 (差集)
|
// 6. 应用none条件 (差集)
|
||||||
if (condition.none.length > 0) {
|
if (condition.none.length > 0) {
|
||||||
if (!resultIds) {
|
if (!resultIds) {
|
||||||
resultIds = this.extractEntityIds(querySystem.getAllEntities());
|
resultIds = this.extractEntityIds(querySystem.queryAllEntities());
|
||||||
}
|
}
|
||||||
|
|
||||||
const noneResult = querySystem.queryAny(...condition.none);
|
const noneResult = querySystem.queryAny(...condition.none);
|
||||||
@@ -411,16 +415,23 @@ export abstract class EntitySystem<
|
|||||||
resultIds = this.differenceIdSets(resultIds, noneIds);
|
resultIds = this.differenceIdSets(resultIds, noneIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.getAllEntities()) : [];
|
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.queryAllEntities()) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取实体ID集合
|
* 提取实体ID集合
|
||||||
|
*
|
||||||
|
* 使用位运算 | 0 强制转换为 32 位整数,帮助 JavaScript 引擎的 JIT 编译器
|
||||||
|
* 进行整数优化,在大规模实体集合操作时可以提供微小的性能提升。
|
||||||
|
*
|
||||||
|
* @param entities 实体数组
|
||||||
|
* @returns 包含所有实体ID的集合
|
||||||
*/
|
*/
|
||||||
private extractEntityIds(entities: readonly Entity[]): Set<number> {
|
private extractEntityIds(entities: readonly Entity[]): Set<number> {
|
||||||
const len = entities.length;
|
const len = entities.length;
|
||||||
const idSet = new Set<number>();
|
const idSet = new Set<number>();
|
||||||
|
|
||||||
|
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||||
idSet.add(entities[i]!.id | 0);
|
idSet.add(entities[i]!.id | 0);
|
||||||
}
|
}
|
||||||
@@ -482,6 +493,12 @@ export abstract class EntitySystem<
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建实体ID映射
|
* 重建实体ID映射
|
||||||
|
*
|
||||||
|
* 重新构建从实体ID到实体引用的映射表。使用位运算优化性能。
|
||||||
|
*
|
||||||
|
* @param allEntities 所有实体的数组
|
||||||
|
* @param version QuerySystem 的版本号,用于缓存失效判断
|
||||||
|
* @returns 重建后的实体ID映射表
|
||||||
*/
|
*/
|
||||||
private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
|
private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
|
||||||
let entityMap = this._entityIdMap;
|
let entityMap = this._entityIdMap;
|
||||||
@@ -493,6 +510,7 @@ export abstract class EntitySystem<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const len = allEntities.length;
|
const len = allEntities.length;
|
||||||
|
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||||
const entity = allEntities[i]!;
|
const entity = allEntities[i]!;
|
||||||
entityMap.set(entity.id | 0, entity);
|
entityMap.set(entity.id | 0, entity);
|
||||||
@@ -506,6 +524,12 @@ export abstract class EntitySystem<
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 从ID集合构建Entity数组
|
* 从ID集合构建Entity数组
|
||||||
|
*
|
||||||
|
* 将实体ID集合转换为实体引用数组。跳过无效的实体ID(已被删除的实体)。
|
||||||
|
*
|
||||||
|
* @param idSet 实体ID集合
|
||||||
|
* @param allEntities 所有实体的数组(用于构建映射表)
|
||||||
|
* @returns 实体引用数组
|
||||||
*/
|
*/
|
||||||
private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
|
private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
|
||||||
const entityMap = this.getEntityIdMap(allEntities);
|
const entityMap = this.getEntityIdMap(allEntities);
|
||||||
@@ -518,10 +542,12 @@ export abstract class EntitySystem<
|
|||||||
const entity = entityMap.get(id);
|
const entity = entityMap.get(id);
|
||||||
if (entity !== undefined) {
|
if (entity !== undefined) {
|
||||||
result[index] = entity;
|
result[index] = entity;
|
||||||
|
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||||
index = (index + 1) | 0;
|
index = (index + 1) | 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果有无效ID,调整数组长度
|
||||||
if (index < size) {
|
if (index < size) {
|
||||||
result.length = index;
|
result.length = index;
|
||||||
}
|
}
|
||||||
@@ -786,7 +812,7 @@ export abstract class EntitySystem<
|
|||||||
this._eventListeners.push({
|
this._eventListeners.push({
|
||||||
eventSystem: this.scene.eventSystem,
|
eventSystem: this.scene.eventSystem,
|
||||||
eventType,
|
eventType,
|
||||||
handler,
|
handler: handler as EventHandler,
|
||||||
listenerRef
|
listenerRef
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -803,7 +829,7 @@ export abstract class EntitySystem<
|
|||||||
handler: EventHandler<T>
|
handler: EventHandler<T>
|
||||||
): void {
|
): void {
|
||||||
const listenerIndex = this._eventListeners.findIndex(
|
const listenerIndex = this._eventListeners.findIndex(
|
||||||
listener => listener.eventType === eventType && listener.handler === handler
|
(listener) => listener.eventType === eventType && listener.handler === handler
|
||||||
);
|
);
|
||||||
|
|
||||||
if (listenerIndex >= 0) {
|
if (listenerIndex >= 0) {
|
||||||
@@ -891,7 +917,7 @@ export abstract class EntitySystem<
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
componentType: T
|
componentType: T
|
||||||
): ComponentInstance<T> {
|
): ComponentInstance<T> {
|
||||||
const component = entity.getComponent(componentType as any);
|
const component = entity.getComponent(componentType as ComponentType);
|
||||||
if (!component) {
|
if (!component) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`
|
`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`
|
||||||
@@ -929,7 +955,7 @@ export abstract class EntitySystem<
|
|||||||
): { [K in keyof T]: ComponentInstance<T[K]> } {
|
): { [K in keyof T]: ComponentInstance<T[K]> } {
|
||||||
return components.map((type) =>
|
return components.map((type) =>
|
||||||
this.requireComponent(entity, type)
|
this.requireComponent(entity, type)
|
||||||
) as any;
|
) as { [K in keyof T]: ComponentInstance<T[K]> };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
${sharedProcessFunctionBody}
|
${sharedProcessFunctionBody}
|
||||||
};
|
};
|
||||||
userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig);
|
userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig);
|
||||||
` : ``}
|
` : ''}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -494,7 +494,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
const deltaTime = Time.deltaTime;
|
const deltaTime = Time.deltaTime;
|
||||||
|
|
||||||
// 3. Worker执行阶段
|
// 3. Worker执行阶段
|
||||||
const promises = batches.map(batch =>
|
const promises = batches.map((batch) =>
|
||||||
this.workerPool!.execute({
|
this.workerPool!.execute({
|
||||||
entities: batch,
|
entities: batch,
|
||||||
deltaTime,
|
deltaTime,
|
||||||
@@ -525,7 +525,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
*/
|
*/
|
||||||
private processSynchronously(entities: readonly Entity[]): void {
|
private processSynchronously(entities: readonly Entity[]): void {
|
||||||
// 1. 数据提取阶段
|
// 1. 数据提取阶段
|
||||||
const entityData = entities.map(entity => this.extractEntityData(entity));
|
const entityData = entities.map((entity) => this.extractEntityData(entity));
|
||||||
|
|
||||||
// 2. 主线程处理阶段
|
// 2. 主线程处理阶段
|
||||||
const deltaTime = Time.deltaTime;
|
const deltaTime = Time.deltaTime;
|
||||||
@@ -534,7 +534,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
// 3. 结果应用阶段
|
// 3. 结果应用阶段
|
||||||
// 处理Promise返回值
|
// 处理Promise返回值
|
||||||
if (results && typeof (results as any).then === 'function') {
|
if (results && typeof (results as any).then === 'function') {
|
||||||
(results as Promise<TEntityData[]>).then(finalResults => {
|
(results as Promise<TEntityData[]>).then((finalResults) => {
|
||||||
entities.forEach((entity, index) => {
|
entities.forEach((entity, index) => {
|
||||||
this.applyResult(entity, finalResults[index]!);
|
this.applyResult(entity, finalResults[index]!);
|
||||||
});
|
});
|
||||||
@@ -813,7 +813,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
sharedArrayBufferSupported: boolean;
|
sharedArrayBufferSupported: boolean;
|
||||||
sharedArrayBufferEnabled: boolean;
|
sharedArrayBufferEnabled: boolean;
|
||||||
currentMode: 'shared-buffer' | 'worker' | 'sync';
|
currentMode: 'shared-buffer' | 'worker' | 'sync';
|
||||||
} {
|
} {
|
||||||
let currentMode: 'shared-buffer' | 'worker' | 'sync' = 'sync';
|
let currentMode: 'shared-buffer' | 'worker' | 'sync' = 'sync';
|
||||||
|
|
||||||
if (this.config.enableWorker && this.workerPool) {
|
if (this.config.enableWorker && this.workerPool) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class BitMask64Utils {
|
|||||||
return maskSegments.some((seg, index) => {
|
return maskSegments.some((seg, index) => {
|
||||||
const bitsSeg = bitsSegments[index];
|
const bitsSeg = bitsSegments[index];
|
||||||
return bitsSeg && ((seg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) !== 0 || (seg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) !== 0);
|
return bitsSeg && ((seg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) !== 0 || (seg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) !== 0);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -145,7 +145,7 @@ export class BitMask64Utils {
|
|||||||
return baseIsZero;
|
return baseIsZero;
|
||||||
}
|
}
|
||||||
// 额外检查扩展区域是否都为0
|
// 额外检查扩展区域是否都为0
|
||||||
return mask.segments.every(seg => seg[SegmentPart.LOW] === 0 && seg[SegmentPart.HIGH] === 0);
|
return mask.segments.every((seg) => seg[SegmentPart.LOW] === 0 && seg[SegmentPart.HIGH] === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,7 +155,7 @@ export class BitMask64Utils {
|
|||||||
* @returns 如果两个掩码完全相等则返回true
|
* @returns 如果两个掩码完全相等则返回true
|
||||||
*/
|
*/
|
||||||
public static equals(a: BitMask64Data, b: BitMask64Data): boolean {
|
public static equals(a: BitMask64Data, b: BitMask64Data): boolean {
|
||||||
let baseEquals = a.base[SegmentPart.LOW] === b.base[SegmentPart.LOW] && a.base[SegmentPart.HIGH] === b.base[SegmentPart.HIGH];
|
const baseEquals = a.base[SegmentPart.LOW] === b.base[SegmentPart.LOW] && a.base[SegmentPart.HIGH] === b.base[SegmentPart.HIGH];
|
||||||
// base不相等,或ab都没有扩展区域位,直接返回base比较结果
|
// base不相等,或ab都没有扩展区域位,直接返回base比较结果
|
||||||
if(!baseEquals || (!a.segments && !b.segments)) return baseEquals;
|
if(!baseEquals || (!a.segments && !b.segments)) return baseEquals;
|
||||||
// 不能假设a,b的segments都存在或长度相同.
|
// 不能假设a,b的segments都存在或长度相同.
|
||||||
@@ -355,7 +355,7 @@ export class BitMask64Utils {
|
|||||||
if(!source.segments || source.segments.length == 0) return;
|
if(!source.segments || source.segments.length == 0) return;
|
||||||
// 没有拓展段,则直接复制数组
|
// 没有拓展段,则直接复制数组
|
||||||
if(!target.segments){
|
if(!target.segments){
|
||||||
target.segments = source.segments.map(seg => [...seg]);
|
target.segments = source.segments.map((seg) => [...seg]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// source有扩展段,target扩展段不足,则补充长度
|
// source有扩展段,target扩展段不足,则补充长度
|
||||||
@@ -382,7 +382,7 @@ export class BitMask64Utils {
|
|||||||
public static clone(mask: BitMask64Data): BitMask64Data {
|
public static clone(mask: BitMask64Data): BitMask64Data {
|
||||||
return {
|
return {
|
||||||
base: mask.base.slice() as BitMask64Segment,
|
base: mask.base.slice() as BitMask64Segment,
|
||||||
...(mask.segments && { segments: mask.segments.map(seg => [...seg] as BitMask64Segment) })
|
...(mask.segments && { segments: mask.segments.map((seg) => [...seg] as BitMask64Segment) })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,8 +414,8 @@ export class BitMask64Utils {
|
|||||||
for (let i = -1; i < totalLength; i++) {
|
for (let i = -1; i < totalLength; i++) {
|
||||||
let segResult = '';
|
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];
|
const hi = bitMaskData[SegmentPart.HIGH];
|
||||||
let lo = bitMaskData[SegmentPart.LOW];
|
const lo = bitMaskData[SegmentPart.LOW];
|
||||||
if(radix == 2){
|
if(radix == 2){
|
||||||
const hiBits = hi.toString(2).padStart(32, '0');
|
const hiBits = hi.toString(2).padStart(32, '0');
|
||||||
const loBits = lo.toString(2).padStart(32, '0');
|
const loBits = lo.toString(2).padStart(32, '0');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BitMask64Data } from "./BigIntCompatibility";
|
import { BitMask64Data } from './BigIntCompatibility';
|
||||||
|
|
||||||
// FlatHashMapFast.ts
|
// FlatHashMapFast.ts
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export class ComponentSparseSet {
|
|||||||
this.removeEntity(entity);
|
this.removeEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
const entityComponents = new Set<ComponentType>();
|
const entityComponents = new Set<ComponentType>();
|
||||||
|
|
||||||
// 分析实体组件并构建位掩码
|
// 分析实体组件并构建位掩码
|
||||||
@@ -169,7 +169,7 @@ export class ComponentSparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建目标位掩码
|
// 构建目标位掩码
|
||||||
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const componentType of componentTypes) {
|
for (const componentType of componentTypes) {
|
||||||
if (!ComponentRegistry.isRegistered(componentType)) {
|
if (!ComponentRegistry.isRegistered(componentType)) {
|
||||||
return new Set<Entity>(); // 未注册的组件类型,结果为空
|
return new Set<Entity>(); // 未注册的组件类型,结果为空
|
||||||
@@ -209,7 +209,7 @@ export class ComponentSparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建目标位掩码
|
// 构建目标位掩码
|
||||||
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const componentType of componentTypes) {
|
for (const componentType of componentTypes) {
|
||||||
if (ComponentRegistry.isRegistered(componentType)) {
|
if (ComponentRegistry.isRegistered(componentType)) {
|
||||||
const bitMask = ComponentRegistry.getBitMask(componentType);
|
const bitMask = ComponentRegistry.getBitMask(componentType);
|
||||||
@@ -272,14 +272,26 @@ export class ComponentSparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有实体
|
* 查询所有实体
|
||||||
|
*
|
||||||
|
* 返回拥有此组件的所有实体。
|
||||||
*
|
*
|
||||||
* @returns 所有实体的数组
|
* @returns 所有实体的数组
|
||||||
*/
|
*/
|
||||||
public getAllEntities(): Entity[] {
|
public queryAllEntities(): Entity[] {
|
||||||
return this._entities.toArray();
|
return this._entities.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有实体
|
||||||
|
*
|
||||||
|
* @deprecated 使用 queryAllEntities() 代替,以保持命名一致性
|
||||||
|
* @see {@link queryAllEntities}
|
||||||
|
*/
|
||||||
|
public getAllEntities(): Entity[] {
|
||||||
|
return this.queryAllEntities();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取实体数量
|
* 获取实体数量
|
||||||
*/
|
*/
|
||||||
@@ -327,7 +339,7 @@ export class ComponentSparseSet {
|
|||||||
masksMemory: number;
|
masksMemory: number;
|
||||||
mappingsMemory: number;
|
mappingsMemory: number;
|
||||||
totalMemory: number;
|
totalMemory: number;
|
||||||
} {
|
} {
|
||||||
const entitiesStats = this._entities.getMemoryStats();
|
const entitiesStats = this._entities.getMemoryStats();
|
||||||
const masksMemory = this._componentMasks.length * 16; // 估计每个BigInt 16字节
|
const masksMemory = this._componentMasks.length * 16; // 估计每个BigInt 16字节
|
||||||
|
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ export class EntityList {
|
|||||||
pendingAdd: number;
|
pendingAdd: number;
|
||||||
pendingRemove: number;
|
pendingRemove: number;
|
||||||
nameIndexSize: number;
|
nameIndexSize: number;
|
||||||
} {
|
} {
|
||||||
let activeCount = 0;
|
let activeCount = 0;
|
||||||
for (const entity of this.buffer) {
|
for (const entity of this.buffer) {
|
||||||
if (entity.enabled && !entity.isDestroyed) {
|
if (entity.enabled && !entity.isDestroyed) {
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ export class IdentifierPool {
|
|||||||
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
|
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
|
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
|
||||||
`这意味着您已经分配了超过65535个不同的实体索引。` +
|
'这意味着您已经分配了超过65535个不同的实体索引。' +
|
||||||
`这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。`
|
'这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ export class IdentifierPool {
|
|||||||
|
|
||||||
// 检查是否已经在待回收队列中
|
// 检查是否已经在待回收队列中
|
||||||
const alreadyPending = this._pendingRecycle.some(
|
const alreadyPending = this._pendingRecycle.some(
|
||||||
item => item.index === index && item.generation === generation
|
(item) => item.index === index && item.generation === generation
|
||||||
);
|
);
|
||||||
|
|
||||||
if (alreadyPending) {
|
if (alreadyPending) {
|
||||||
@@ -217,7 +217,7 @@ export class IdentifierPool {
|
|||||||
averageGeneration: number;
|
averageGeneration: number;
|
||||||
/** 世代存储大小 */
|
/** 世代存储大小 */
|
||||||
generationStorageSize: number;
|
generationStorageSize: number;
|
||||||
} {
|
} {
|
||||||
// 计算平均世代版本
|
// 计算平均世代版本
|
||||||
let totalGeneration = 0;
|
let totalGeneration = 0;
|
||||||
let generationCount = 0;
|
let generationCount = 0;
|
||||||
|
|||||||
@@ -267,15 +267,15 @@ export class Matcher {
|
|||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
if (this.condition.all.length > 0) {
|
if (this.condition.all.length > 0) {
|
||||||
parts.push(`all(${this.condition.all.map(t => getComponentTypeName(t)).join(', ')})`);
|
parts.push(`all(${this.condition.all.map((t) => getComponentTypeName(t)).join(', ')})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.condition.any.length > 0) {
|
if (this.condition.any.length > 0) {
|
||||||
parts.push(`any(${this.condition.any.map(t => getComponentTypeName(t)).join(', ')})`);
|
parts.push(`any(${this.condition.any.map((t) => getComponentTypeName(t)).join(', ')})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.condition.none.length > 0) {
|
if (this.condition.none.length > 0) {
|
||||||
parts.push(`none(${this.condition.none.map(t => getComponentTypeName(t)).join(', ')})`);
|
parts.push(`none(${this.condition.none.map((t) => getComponentTypeName(t)).join(', ')})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.condition.tag !== undefined) {
|
if (this.condition.tag !== undefined) {
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ export class SparseSet<T> {
|
|||||||
denseArraySize: number;
|
denseArraySize: number;
|
||||||
sparseMapSize: number;
|
sparseMapSize: number;
|
||||||
totalMemory: number;
|
totalMemory: number;
|
||||||
} {
|
} {
|
||||||
const denseArraySize = this._dense.length * 8; // 估计每个引用8字节
|
const denseArraySize = this._dense.length * 8; // 估计每个引用8字节
|
||||||
const sparseMapSize = this._sparse.size * 16; // 估计每个Map条目16字节
|
const sparseMapSize = this._sparse.size * 16; // 估计每个Map条目16字节
|
||||||
|
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ export class World {
|
|||||||
globalSystemCount: this._globalSystems.length,
|
globalSystemCount: this._globalSystems.length,
|
||||||
createdAt: this._createdAt,
|
createdAt: this._createdAt,
|
||||||
config: { ...this._config },
|
config: { ...this._config },
|
||||||
scenes: Array.from(this._scenes.keys()).map(sceneId => ({
|
scenes: Array.from(this._scenes.keys()).map((sceneId) => ({
|
||||||
id: sceneId,
|
id: sceneId,
|
||||||
isActive: this._activeScenes.has(sceneId),
|
isActive: this._activeScenes.has(sceneId),
|
||||||
name: this._scenes.get(sceneId)?.name || sceneId
|
name: this._scenes.get(sceneId)?.name || sceneId
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ export class WorldManager implements IService {
|
|||||||
|
|
||||||
// 检查是否所有Scene都是空的
|
// 检查是否所有Scene都是空的
|
||||||
const allScenes = world.getAllScenes();
|
const allScenes = world.getAllScenes();
|
||||||
const hasEntities = allScenes.some(scene =>
|
const hasEntities = allScenes.some((scene) =>
|
||||||
scene.entities && scene.entities.count > 0
|
scene.entities && scene.entities.count > 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export class PlatformManager {
|
|||||||
platformSupportsSharedArrayBuffer: boolean;
|
platformSupportsSharedArrayBuffer: boolean;
|
||||||
platformMaxWorkerCount: number;
|
platformMaxWorkerCount: number;
|
||||||
platformLimitations: any;
|
platformLimitations: any;
|
||||||
} {
|
} {
|
||||||
if (!this.adapter) {
|
if (!this.adapter) {
|
||||||
return {
|
return {
|
||||||
platformSupportsWorker: false,
|
platformSupportsWorker: false,
|
||||||
|
|||||||
@@ -208,8 +208,8 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
return {
|
return {
|
||||||
name: scene.name,
|
name: scene.name,
|
||||||
entityCount: entities.length,
|
entityCount: entities.length,
|
||||||
systems: systems.map(sys => this.getSystemInfo(sys)),
|
systems: systems.map((sys) => this.getSystemInfo(sys)),
|
||||||
entities: entities.map(entity => this.getEntityInfo(entity))
|
entities: entities.map((entity) => this.getEntityInfo(entity))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
enabled: entity.enabled,
|
enabled: entity.enabled,
|
||||||
tag: entity.tag,
|
tag: entity.tag,
|
||||||
componentCount: components.length,
|
componentCount: components.length,
|
||||||
components: components.map(comp => this.getComponentInfo(comp))
|
components: components.map((comp) => this.getComponentInfo(comp))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
|
|
||||||
if (filter.hasComponent) {
|
if (filter.hasComponent) {
|
||||||
const hasComp = entity.components.some(
|
const hasComp = entity.components.some(
|
||||||
c => c.constructor.name === filter.hasComponent
|
(c) => c.constructor.name === filter.hasComponent
|
||||||
);
|
);
|
||||||
if (!hasComp) {
|
if (!hasComp) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ export class ComponentDataCollector {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 获取池利用率信息
|
// 获取池利用率信息
|
||||||
let poolUtilizations = new Map<string, number>();
|
const poolUtilizations = new Map<string, number>();
|
||||||
let poolSizes = new Map<string, number>();
|
const poolSizes = new Map<string, number>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const poolManager = ComponentPoolManager.getInstance();
|
const poolManager = ComponentPoolManager.getInstance();
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
* 格式化日志消息
|
* 格式化日志消息
|
||||||
*/
|
*/
|
||||||
private formatLogMessage(args: unknown[]): string {
|
private formatLogMessage(args: unknown[]): string {
|
||||||
return args.map(arg => {
|
return args.map((arg) => {
|
||||||
if (typeof arg === 'string') return arg;
|
if (typeof arg === 'string') return arg;
|
||||||
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
||||||
if (arg === null) return 'null';
|
if (arg === null) return 'null';
|
||||||
@@ -173,7 +173,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
seen.add(value);
|
seen.add(value);
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
const result = value.map(item => stringify(item, depth + 1));
|
const result = value.map((item) => stringify(item, depth + 1));
|
||||||
seen.delete(value);
|
seen.delete(value);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -436,9 +436,6 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理内存快照请求
|
* 处理内存快照请求
|
||||||
*/
|
*/
|
||||||
@@ -519,7 +516,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
jsHeapSizeLimit: number;
|
jsHeapSizeLimit: number;
|
||||||
} | null;
|
} | null;
|
||||||
detailedMemory?: unknown;
|
detailedMemory?: unknown;
|
||||||
} {
|
} {
|
||||||
const memoryInfo = {
|
const memoryInfo = {
|
||||||
totalMemory: 0,
|
totalMemory: 0,
|
||||||
usedMemory: 0,
|
usedMemory: 0,
|
||||||
@@ -575,7 +572,6 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 收集组件内存统计(仅用于内存快照)
|
* 收集组件内存统计(仅用于内存快照)
|
||||||
*/
|
*/
|
||||||
@@ -672,7 +668,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
updateOrder: number;
|
updateOrder: number;
|
||||||
}>;
|
}>;
|
||||||
} {
|
} {
|
||||||
const scene = this.sceneManager.currentScene;
|
const scene = this.sceneManager.currentScene;
|
||||||
let totalSystemMemory = 0;
|
let totalSystemMemory = 0;
|
||||||
const systemBreakdown: Array<{
|
const systemBreakdown: Array<{
|
||||||
@@ -766,7 +762,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
utilization: number;
|
utilization: number;
|
||||||
hitRate?: number;
|
hitRate?: number;
|
||||||
}>;
|
}>;
|
||||||
} {
|
} {
|
||||||
let totalPoolMemory = 0;
|
let totalPoolMemory = 0;
|
||||||
const poolBreakdown: Array<{
|
const poolBreakdown: Array<{
|
||||||
typeName: string;
|
typeName: string;
|
||||||
@@ -845,7 +841,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
samples: number;
|
samples: number;
|
||||||
}>;
|
}>;
|
||||||
error?: string;
|
error?: string;
|
||||||
} {
|
} {
|
||||||
try {
|
try {
|
||||||
if (!this.performanceMonitor) {
|
if (!this.performanceMonitor) {
|
||||||
return { enabled: false };
|
return { enabled: false };
|
||||||
|
|||||||
@@ -182,17 +182,17 @@ export class EntityDataCollector {
|
|||||||
try {
|
try {
|
||||||
stats = entityList.getStats ? entityList.getStats() : this.calculateFallbackEntityStats(entityList);
|
stats = entityList.getStats ? entityList.getStats() : this.calculateFallbackEntityStats(entityList);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
totalEntities: 0,
|
totalEntities: 0,
|
||||||
activeEntities: 0,
|
activeEntities: 0,
|
||||||
pendingAdd: 0,
|
pendingAdd: 0,
|
||||||
pendingRemove: 0,
|
pendingRemove: 0,
|
||||||
entitiesPerArchetype: [],
|
entitiesPerArchetype: [],
|
||||||
topEntitiesByComponents: [],
|
topEntitiesByComponents: [],
|
||||||
entityHierarchy: [],
|
entityHierarchy: [],
|
||||||
entityDetailsMap: {}
|
entityDetailsMap: {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const archetypeData = this.collectArchetypeDataWithMemory(scene);
|
const archetypeData = this.collectArchetypeDataWithMemory(scene);
|
||||||
|
|
||||||
@@ -369,7 +369,6 @@ export class EntityDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
|
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
|
||||||
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
|
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
|
||||||
|
|
||||||
@@ -437,7 +436,7 @@ export class EntityDataCollector {
|
|||||||
private calculateFallbackEntityStats(entityList: any): any {
|
private calculateFallbackEntityStats(entityList: any): any {
|
||||||
const allEntities = entityList.buffer || [];
|
const allEntities = entityList.buffer || [];
|
||||||
const activeEntities = allEntities.filter((entity: any) =>
|
const activeEntities = allEntities.filter((entity: any) =>
|
||||||
entity.enabled && !entity._isDestroyed
|
entity.enabled && !entity.isDestroyed
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -694,7 +693,7 @@ export class EntityDataCollector {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const propertyKeys = Object.keys(component);
|
const propertyKeys = Object.keys(component);
|
||||||
propertyKeys.forEach(propertyKey => {
|
propertyKeys.forEach((propertyKey) => {
|
||||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') {
|
if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') {
|
||||||
const propertyValue = (component as any)[propertyKey];
|
const propertyValue = (component as any)[propertyKey];
|
||||||
if (propertyValue !== undefined && propertyValue !== null) {
|
if (propertyValue !== undefined && propertyValue !== null) {
|
||||||
@@ -739,20 +738,20 @@ export class EntityDataCollector {
|
|||||||
const component = entity.components[componentIndex];
|
const component = entity.components[componentIndex];
|
||||||
const properties: Record<string, any> = {};
|
const properties: Record<string, any> = {};
|
||||||
|
|
||||||
const propertyKeys = Object.keys(component);
|
const propertyKeys = Object.keys(component);
|
||||||
propertyKeys.forEach(propertyKey => {
|
propertyKeys.forEach((propertyKey) => {
|
||||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
|
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
|
||||||
const propertyValue = (component as any)[propertyKey];
|
const propertyValue = (component as any)[propertyKey];
|
||||||
if (propertyValue !== undefined && propertyValue !== null) {
|
if (propertyValue !== undefined && propertyValue !== null) {
|
||||||
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { _error: '属性提取失败' };
|
return { _error: '属性提取失败' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -786,7 +785,7 @@ export class EntityDataCollector {
|
|||||||
if (obj.length === 0) return [];
|
if (obj.length === 0) return [];
|
||||||
|
|
||||||
if (obj.length > 10) {
|
if (obj.length > 10) {
|
||||||
const sample = obj.slice(0, 3).map(item => this.formatPropertyValue(item, 1));
|
const sample = obj.slice(0, 3).map((item) => this.formatPropertyValue(item, 1));
|
||||||
return {
|
return {
|
||||||
_isLazyArray: true,
|
_isLazyArray: true,
|
||||||
_arrayLength: obj.length,
|
_arrayLength: obj.length,
|
||||||
@@ -795,7 +794,7 @@ export class EntityDataCollector {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj.map(item => this.formatPropertyValue(item, 1));
|
return obj.map((item) => this.formatPropertyValue(item, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = Object.keys(obj);
|
const keys = Object.keys(obj);
|
||||||
@@ -843,7 +842,7 @@ export class EntityDataCollector {
|
|||||||
const typeName = obj.constructor?.name || 'Object';
|
const typeName = obj.constructor?.name || 'Object';
|
||||||
const summary = this.getObjectSummary(obj, typeName);
|
const summary = this.getObjectSummary(obj, typeName);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_isLazyObject: true,
|
_isLazyObject: true,
|
||||||
_typeName: typeName,
|
_typeName: typeName,
|
||||||
_summary: summary,
|
_summary: summary,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export class PerformanceDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 计算ECS执行时间统计
|
// 计算ECS执行时间统计
|
||||||
const history = this.frameTimeHistory.filter(t => t >= 0);
|
const history = this.frameTimeHistory.filter((t) => t >= 0);
|
||||||
const averageECSTime = history.length > 0 ? history.reduce((a, b) => a + b, 0) / history.length : ecsExecutionTimeMs;
|
const averageECSTime = history.length > 0 ? history.reduce((a, b) => a + b, 0) / history.length : ecsExecutionTimeMs;
|
||||||
const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs;
|
const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs;
|
||||||
const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs;
|
const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs;
|
||||||
@@ -100,7 +100,7 @@ export class PerformanceDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 计算各系统占ECS总时间的百分比
|
// 计算各系统占ECS总时间的百分比
|
||||||
systemBreakdown.forEach(system => {
|
systemBreakdown.forEach((system) => {
|
||||||
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
|
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ export class WebSocketManager {
|
|||||||
try {
|
try {
|
||||||
const message = typeof data === 'string' ? data : JSON.stringify(data);
|
const message = typeof data === 'string' ? data : JSON.stringify(data);
|
||||||
this.ws.send(message);
|
this.ws.send(message);
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
|
// 发送失败时静默忽略,WebSocket 断开会触发 error 事件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +113,7 @@ export class WebSocketManager {
|
|||||||
this.reconnectAttempts++;
|
this.reconnectAttempts++;
|
||||||
|
|
||||||
this.reconnectTimer = setTimeout(() => {
|
this.reconnectTimer = setTimeout(() => {
|
||||||
this.connect().catch(_error => {
|
this.connect().catch((_error) => {
|
||||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||||
this.scheduleReconnect();
|
this.scheduleReconnect();
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,8 @@ export class WebSocketManager {
|
|||||||
if (this.messageHandler) {
|
if (this.messageHandler) {
|
||||||
this.messageHandler(message);
|
this.messageHandler(message);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
|
// 解析失败时静默忽略,避免非 JSON 消息导致错误
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
type EventHandler = (...args: unknown[]) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于包装事件的一个小类
|
* 用于包装事件的一个小类
|
||||||
*/
|
*/
|
||||||
export class FuncPack<TContext = unknown> {
|
export class FuncPack<TContext = unknown> {
|
||||||
/** 函数 */
|
/** 函数 */
|
||||||
public func: Function;
|
public func: EventHandler;
|
||||||
/** 上下文 */
|
/** 上下文 */
|
||||||
public context: TContext;
|
public context: TContext;
|
||||||
|
|
||||||
constructor(func: Function, context: TContext) {
|
constructor(func: EventHandler, context: TContext) {
|
||||||
this.func = func;
|
this.func = func;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
@@ -29,7 +31,7 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param handler 监听函数
|
* @param handler 监听函数
|
||||||
* @param context 监听上下文
|
* @param context 监听上下文
|
||||||
*/
|
*/
|
||||||
public addObserver(eventType: T, handler: Function, context: TContext) {
|
public addObserver(eventType: T, handler: EventHandler, context: TContext) {
|
||||||
let list = this._messageTable.get(eventType);
|
let list = this._messageTable.get(eventType);
|
||||||
if (!list) {
|
if (!list) {
|
||||||
list = [];
|
list = [];
|
||||||
@@ -46,10 +48,10 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param eventType 事件类型
|
* @param eventType 事件类型
|
||||||
* @param handler 事件函数
|
* @param handler 事件函数
|
||||||
*/
|
*/
|
||||||
public removeObserver(eventType: T, handler: Function) {
|
public removeObserver(eventType: T, handler: EventHandler) {
|
||||||
let messageData = this._messageTable.get(eventType);
|
const messageData = this._messageTable.get(eventType);
|
||||||
if (messageData) {
|
if (messageData) {
|
||||||
let index = messageData.findIndex(data => data.func == handler);
|
const index = messageData.findIndex((data) => data.func == handler);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
messageData.splice(index, 1);
|
messageData.splice(index, 1);
|
||||||
}
|
}
|
||||||
@@ -61,9 +63,9 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param data 事件数据
|
* @param data 事件数据
|
||||||
*/
|
*/
|
||||||
public emit<TData = unknown>(eventType: T, ...data: TData[]) {
|
public emit<TData = unknown>(eventType: T, ...data: TData[]) {
|
||||||
let list = this._messageTable.get(eventType);
|
const list = this._messageTable.get(eventType);
|
||||||
if (list) {
|
if (list) {
|
||||||
for (let observer of list) {
|
for (const observer of list) {
|
||||||
observer.func.call(observer.context, ...data);
|
observer.func.call(observer.context, ...data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,9 +76,9 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param eventType 事件类型
|
* @param eventType 事件类型
|
||||||
* @param handler 事件函数
|
* @param handler 事件函数
|
||||||
*/
|
*/
|
||||||
public hasObserver(eventType: T, handler: Function): boolean {
|
public hasObserver(eventType: T, handler: EventHandler): boolean {
|
||||||
let list = this._messageTable.get(eventType);
|
const list = this._messageTable.get(eventType);
|
||||||
return list ? list.some(observer => observer.func === handler) : false;
|
return list ? list.some((observer) => observer.func === handler) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Colors, LogLevel } from "./Constants";
|
import { Colors, LogLevel } from './Constants';
|
||||||
import { ILogger, LoggerColorConfig, LoggerConfig } from "./Types";
|
import { ILogger, LoggerColorConfig, LoggerConfig } from './Types';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ConsoleLogger } from "./ConsoleLogger";
|
import { ConsoleLogger } from './ConsoleLogger';
|
||||||
import { LogLevel } from "./Constants";
|
import { LogLevel } from './Constants';
|
||||||
import { ILogger, LoggerColorConfig } from "./Types";
|
import { ILogger, LoggerColorConfig } from './Types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志管理器
|
* 日志管理器
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { LogLevel } from "./Constants";
|
import type { LogLevel } from './Constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志接口
|
* 日志接口
|
||||||
|
|||||||
@@ -276,12 +276,12 @@ export class PerformanceMonitor implements IService {
|
|||||||
*/
|
*/
|
||||||
public getPerformanceReport(): string {
|
public getPerformanceReport(): string {
|
||||||
if (!this._isEnabled) {
|
if (!this._isEnabled) {
|
||||||
return "Performance monitoring is disabled.";
|
return 'Performance monitoring is disabled.';
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
lines.push("=== ECS Performance Report ===");
|
lines.push('=== ECS Performance Report ===');
|
||||||
lines.push("");
|
lines.push('');
|
||||||
|
|
||||||
// 按平均执行时间排序
|
// 按平均执行时间排序
|
||||||
const sortedSystems = Array.from(this._systemStats.entries())
|
const sortedSystems = Array.from(this._systemStats.entries())
|
||||||
@@ -300,7 +300,7 @@ export class PerformanceMonitor implements IService {
|
|||||||
lines.push(` Per Entity: ${data.averageTimePerEntity.toFixed(4)}ms`);
|
lines.push(` Per Entity: ${data.averageTimePerEntity.toFixed(4)}ms`);
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push("");
|
lines.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 总体统计
|
// 总体统计
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { IPoolable, PoolStats } from './IPoolable';
|
import { IPoolable, PoolStats } from './IPoolable';
|
||||||
|
|
||||||
|
type Constructor<T = unknown> = new (...args: unknown[]) => T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高性能通用对象池
|
* 高性能通用对象池
|
||||||
* 支持任意类型的对象池化,包含详细的统计信息
|
* 支持任意类型的对象池化,包含详细的统计信息
|
||||||
*/
|
*/
|
||||||
export class Pool<T extends IPoolable> {
|
export class Pool<T extends IPoolable> {
|
||||||
private static _pools = new Map<Function, Pool<any>>();
|
private static _pools = new Map<Constructor, Pool<IPoolable>>();
|
||||||
|
|
||||||
private _objects: T[] = [];
|
private _objects: T[] = [];
|
||||||
private _createFn: () => T;
|
private _createFn: () => T;
|
||||||
@@ -46,11 +48,11 @@ export class Pool<T extends IPoolable> {
|
|||||||
maxSize: number = 100,
|
maxSize: number = 100,
|
||||||
estimatedObjectSize: number = 1024
|
estimatedObjectSize: number = 1024
|
||||||
): Pool<T> {
|
): Pool<T> {
|
||||||
let pool = this._pools.get(type);
|
let pool = this._pools.get(type) as Pool<T> | undefined;
|
||||||
|
|
||||||
if (!pool) {
|
if (!pool) {
|
||||||
pool = new Pool<T>(() => new type(), maxSize, estimatedObjectSize);
|
pool = new Pool<T>(() => new type(), maxSize, estimatedObjectSize);
|
||||||
this._pools.set(type, pool);
|
this._pools.set(type, pool as Pool<IPoolable>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
@@ -197,7 +199,7 @@ export class Pool<T extends IPoolable> {
|
|||||||
* 获取所有已注册的池类型
|
* 获取所有已注册的池类型
|
||||||
* @returns 所有池类型的数组
|
* @returns 所有池类型的数组
|
||||||
*/
|
*/
|
||||||
public static getAllPoolTypes(): Function[] {
|
public static getAllPoolTypes(): Constructor[] {
|
||||||
return Array.from(this._pools.keys());
|
return Array.from(this._pools.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type { IService } from '../../Core/ServiceContainer';
|
|||||||
* 统一管理所有对象池
|
* 统一管理所有对象池
|
||||||
*/
|
*/
|
||||||
export class PoolManager implements IService {
|
export class PoolManager implements IService {
|
||||||
private pools = new Map<string, Pool<any>>();
|
private pools = new Map<string, Pool<IPoolable>>();
|
||||||
private autoCompactInterval = 60000; // 60秒
|
private autoCompactInterval = 60000; // 60秒
|
||||||
private lastCompactTime = 0;
|
private lastCompactTime = 0;
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ export class PoolManager implements IService {
|
|||||||
* @returns 池实例
|
* @returns 池实例
|
||||||
*/
|
*/
|
||||||
public getPool<T extends IPoolable>(name: string): Pool<T> | null {
|
public getPool<T extends IPoolable>(name: string): Pool<T> | null {
|
||||||
return this.pools.get(name) || null;
|
return (this.pools.get(name) as Pool<T> | undefined) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class TimerManager implements IService, IUpdatable {
|
|||||||
* @param onTime
|
* @param onTime
|
||||||
*/
|
*/
|
||||||
public schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean, context: TContext, onTime: (timer: ITimer<TContext>)=>void): Timer<TContext> {
|
public schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean, context: TContext, onTime: (timer: ITimer<TContext>)=>void): Timer<TContext> {
|
||||||
let timer = new Timer<TContext>();
|
const timer = new Timer<TContext>();
|
||||||
timer.initialize(timeInSeconds, repeats, context, onTime);
|
timer.initialize(timeInSeconds, repeats, context, onTime);
|
||||||
this._timers.push(timer as Timer<unknown>);
|
this._timers.push(timer as Timer<unknown>);
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ describe('Component - 组件基类测试', () => {
|
|||||||
let scene: Scene;
|
let scene: Scene;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Component._idGenerator = 0;
|
|
||||||
component = new TestComponent();
|
component = new TestComponent();
|
||||||
scene = new Scene();
|
scene = new Scene();
|
||||||
entity = scene.createEntity('TestEntity');
|
entity = scene.createEntity('TestEntity');
|
||||||
@@ -51,7 +50,7 @@ describe('Component - 组件基类测试', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('组件ID应该递增分配', () => {
|
test('组件ID应该递增分配', () => {
|
||||||
const startId = Component._idGenerator;
|
const startId = Component.nextComponentId;
|
||||||
const component1 = new TestComponent();
|
const component1 = new TestComponent();
|
||||||
const component2 = new TestComponent();
|
const component2 = new TestComponent();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user