Merge pull request #257 from esengine/feat/system-stable-sorting

feat(ecs): 添加系统稳定排序支持
This commit is contained in:
YHH
2025-12-03 21:01:52 +08:00
committed by GitHub
3 changed files with 144 additions and 2 deletions

View File

@@ -143,6 +143,14 @@ export class Scene implements IScene {
*/
private _maxErrorCount: number = 10;
/**
* 系统添加计数器
*
* 用于为每个添加的系统分配唯一的添加顺序,保证排序稳定性
* Counter for assigning unique add order to each system for stable sorting
*/
private _systemAddCounter: number = 0;
/**
* 获取场景中所有已注册的EntitySystem
*
@@ -180,10 +188,15 @@ export class Scene implements IScene {
}
/**
* 按updateOrder排序系统
* 按 updateOrder 排序系统,相同时按 addOrder 保证稳定性
* Sort systems by updateOrder, use addOrder as secondary key for stability
*/
private _sortSystemsByUpdateOrder(systems: EntitySystem[]): EntitySystem[] {
return systems.sort((a, b) => a.updateOrder - b.updateOrder);
return systems.sort((a, b) => {
const orderDiff = a.updateOrder - b.updateOrder;
if (orderDiff !== 0) return orderDiff;
return a.addOrder - b.addOrder;
});
}
/**
@@ -707,6 +720,9 @@ export class Scene implements IScene {
system.scene = this;
// 分配添加顺序,用于稳定排序 | Assign add order for stable sorting
system.addOrder = this._systemAddCounter++;
system.setPerformanceMonitor(this.performanceMonitor);
const metadata = getSystemMetadata(constructor);

View File

@@ -66,6 +66,12 @@ interface EventListenerRecord {
*/
export abstract class EntitySystem implements ISystemBase, IService {
private _updateOrder: number;
/**
* 添加顺序,用于 updateOrder 相同时的稳定排序
* Add order for stable sorting when updateOrder is the same
* @internal
*/
private _addOrder: number;
private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null;
private _systemName: string;
@@ -116,6 +122,24 @@ export abstract class EntitySystem implements ISystemBase, IService {
this.setUpdateOrder(value);
}
/**
* 获取系统的添加顺序
* Get the add order of the system
* @internal
*/
public get addOrder(): number {
return this._addOrder;
}
/**
* 设置系统的添加顺序(由 Scene 在添加时设置)
* Set the add order of the system (set by Scene when adding)
* @internal
*/
public set addOrder(value: number) {
this._addOrder = value;
}
/**
* 获取系统的启用状态
*/
@@ -139,6 +163,7 @@ export abstract class EntitySystem implements ISystemBase, IService {
constructor(matcher?: Matcher) {
this._updateOrder = 0;
this._addOrder = 0;
this._enabled = true;
this._performanceMonitor = null;
this._systemName = getSystemInstanceTypeName(this);

View File

@@ -825,5 +825,106 @@ describe('Scene - 场景管理系统测试', () => {
expect(scene.entities.count).toBe(2);
});
});
describe('系统排序稳定性', () => {
test('相同 updateOrder 的系统应按添加顺序稳定排序', () => {
// 创建多个 updateOrder 都为 0 的系统
// Create multiple systems with updateOrder = 0
class SystemA extends EntitySystem {
name = 'SystemA';
constructor() { super(); }
}
class SystemB extends EntitySystem {
name = 'SystemB';
constructor() { super(); }
}
class SystemC extends EntitySystem {
name = 'SystemC';
constructor() { super(); }
}
const systemA = new SystemA();
const systemB = new SystemB();
const systemC = new SystemC();
// 按 A, B, C 顺序添加
scene.addEntityProcessor(systemA);
scene.addEntityProcessor(systemB);
scene.addEntityProcessor(systemC);
// 验证 addOrder 按添加顺序递增
expect(systemA.addOrder).toBe(0);
expect(systemB.addOrder).toBe(1);
expect(systemC.addOrder).toBe(2);
// 验证系统列表按添加顺序排列
const systems = scene.systems;
expect(systems[0]).toBe(systemA);
expect(systems[1]).toBe(systemB);
expect(systems[2]).toBe(systemC);
});
test('updateOrder 优先于 addOrder 排序', () => {
class SystemA extends EntitySystem {
name = 'SystemA';
constructor() { super(); }
}
class SystemB extends EntitySystem {
name = 'SystemB';
constructor() { super(); }
}
class SystemC extends EntitySystem {
name = 'SystemC';
constructor() { super(); }
}
const systemA = new SystemA();
const systemB = new SystemB();
const systemC = new SystemC();
// 按 A, B, C 顺序添加,但设置不同的 updateOrder
scene.addEntityProcessor(systemA);
systemA.updateOrder = 10;
scene.addEntityProcessor(systemB);
systemB.updateOrder = 5;
scene.addEntityProcessor(systemC);
systemC.updateOrder = 5; // 与 B 相同
// 验证排序B(5,1), C(5,2), A(10,0)
const systems = scene.systems;
expect(systems[0]).toBe(systemB); // updateOrder=5, addOrder=1
expect(systems[1]).toBe(systemC); // updateOrder=5, addOrder=2
expect(systems[2]).toBe(systemA); // updateOrder=10, addOrder=0
});
test('多次重新排序后仍保持稳定性', () => {
class SystemA extends EntitySystem {
name = 'SystemA';
constructor() { super(); }
}
class SystemB extends EntitySystem {
name = 'SystemB';
constructor() { super(); }
}
const systemA = new SystemA();
const systemB = new SystemB();
scene.addEntityProcessor(systemA);
scene.addEntityProcessor(systemB);
// 多次触发重新排序
for (let i = 0; i < 10; i++) {
scene.markSystemsOrderDirty();
const systems = scene.systems;
// 每次排序后顺序应该相同
expect(systems[0]).toBe(systemA);
expect(systems[1]).toBe(systemB);
}
});
});
});
});