refactor: reorganize package structure and decouple framework packages (#338)

* refactor: reorganize package structure and decouple framework packages

## Package Structure Reorganization
- Reorganized 55 packages into categorized subdirectories:
  - packages/framework/ - Generic framework (Laya/Cocos compatible)
  - packages/engine/ - ESEngine core modules
  - packages/rendering/ - Rendering modules (WASM dependent)
  - packages/physics/ - Physics modules
  - packages/streaming/ - World streaming
  - packages/network-ext/ - Network extensions
  - packages/editor/ - Editor framework and plugins
  - packages/rust/ - Rust WASM engine
  - packages/tools/ - Build tools and SDK

## Framework Package Decoupling
- Decoupled behavior-tree and blueprint packages from ESEngine dependencies
- Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent)
- ESEngine-specific code moved to esengine/ subpath exports
- Framework packages now usable with Cocos/Laya without ESEngine

## CI Configuration
- Updated CI to only type-check and lint framework packages
- Added type-check:framework and lint:framework scripts

## Breaking Changes
- Package import paths changed due to directory reorganization
- ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine')

* fix: update es-engine file path after directory reorganization

* docs: update README to focus on framework over engine

* ci: only build framework packages, remove Rust/WASM dependencies

* fix: remove esengine subpath from behavior-tree and blueprint builds

ESEngine integration code will only be available in full engine builds.
Framework packages are now purely engine-agnostic.

* fix: move network-protocols to framework, build both in CI

* fix: update workflow paths from packages/core to packages/framework/core

* fix: exclude esengine folder from type-check in behavior-tree and blueprint

* fix: update network tsconfig references to new paths

* fix: add test:ci:framework to only test framework packages in CI

* fix: only build core and math npm packages in CI

* fix: exclude test files from CodeQL and fix string escaping security issue
This commit is contained in:
YHH
2025-12-26 14:50:35 +08:00
committed by GitHub
parent a84ff902e4
commit 155411e743
1936 changed files with 4147 additions and 11578 deletions

View File

@@ -0,0 +1,245 @@
/**
* Collision Layer Configuration Service
* 碰撞层配置服务
*
* 管理碰撞层的定义和碰撞矩阵配置
*/
/**
* 碰撞层定义
*/
export interface CollisionLayerDefinition {
/** 层索引 (0-15) */
index: number;
/** 层名称 */
name: string;
/** 层描述 */
description?: string;
}
/**
* 碰撞层配置
*/
export interface CollisionLayerSettings {
/** 层定义列表 */
layers: CollisionLayerDefinition[];
/** 碰撞矩阵 (16x16 位图matrix[i] 表示第 i 层可以与哪些层碰撞) */
collisionMatrix: number[];
}
/**
* 默认碰撞层配置
*/
export const DEFAULT_COLLISION_LAYERS: CollisionLayerDefinition[] = [
{ index: 0, name: 'Default', description: '默认层' },
{ index: 1, name: 'Player', description: '玩家' },
{ index: 2, name: 'Enemy', description: '敌人' },
{ index: 3, name: 'Projectile', description: '投射物' },
{ index: 4, name: 'Ground', description: '地面' },
{ index: 5, name: 'Platform', description: '平台' },
{ index: 6, name: 'Trigger', description: '触发器' },
{ index: 7, name: 'Item', description: '物品' },
{ index: 8, name: 'Layer8', description: '自定义层8' },
{ index: 9, name: 'Layer9', description: '自定义层9' },
{ index: 10, name: 'Layer10', description: '自定义层10' },
{ index: 11, name: 'Layer11', description: '自定义层11' },
{ index: 12, name: 'Layer12', description: '自定义层12' },
{ index: 13, name: 'Layer13', description: '自定义层13' },
{ index: 14, name: 'Layer14', description: '自定义层14' },
{ index: 15, name: 'Layer15', description: '自定义层15' },
];
/**
* 默认碰撞矩阵 - 所有层都可以互相碰撞
*/
export const DEFAULT_COLLISION_MATRIX: number[] = Array(16).fill(0xFFFF);
/**
* 碰撞层配置管理器
*/
export class CollisionLayerConfig {
private static instance: CollisionLayerConfig | null = null;
private layers: CollisionLayerDefinition[] = [...DEFAULT_COLLISION_LAYERS];
private collisionMatrix: number[] = [...DEFAULT_COLLISION_MATRIX];
private listeners: Set<() => void> = new Set();
private constructor() {}
public static getInstance(): CollisionLayerConfig {
if (!CollisionLayerConfig.instance) {
CollisionLayerConfig.instance = new CollisionLayerConfig();
}
return CollisionLayerConfig.instance;
}
/**
* 获取所有层定义
*/
public getLayers(): readonly CollisionLayerDefinition[] {
return this.layers;
}
/**
* 获取层名称
*/
public getLayerName(index: number): string {
if (index < 0 || index >= 16) return `Layer${index}`;
return this.layers[index]?.name ?? `Layer${index}`;
}
/**
* 设置层名称
*/
public setLayerName(index: number, name: string): void {
if (index < 0 || index >= 16) return;
if (this.layers[index]) {
this.layers[index].name = name;
this.notifyListeners();
}
}
/**
* 设置层描述
*/
public setLayerDescription(index: number, description: string): void {
if (index < 0 || index >= 16) return;
if (this.layers[index]) {
this.layers[index].description = description;
this.notifyListeners();
}
}
/**
* 获取碰撞矩阵
*/
public getCollisionMatrix(): readonly number[] {
return this.collisionMatrix;
}
/**
* 检查两个层是否可以碰撞
*/
public canLayersCollide(layerA: number, layerB: number): boolean {
if (layerA < 0 || layerA >= 16 || layerB < 0 || layerB >= 16) {
return false;
}
return (this.collisionMatrix[layerA] & (1 << layerB)) !== 0;
}
/**
* 设置两个层是否可以碰撞
*/
public setLayersCanCollide(layerA: number, layerB: number, canCollide: boolean): void {
if (layerA < 0 || layerA >= 16 || layerB < 0 || layerB >= 16) {
return;
}
if (canCollide) {
this.collisionMatrix[layerA] |= (1 << layerB);
this.collisionMatrix[layerB] |= (1 << layerA);
} else {
this.collisionMatrix[layerA] &= ~(1 << layerB);
this.collisionMatrix[layerB] &= ~(1 << layerA);
}
this.notifyListeners();
}
/**
* 获取指定层的碰撞掩码
*/
public getLayerMask(layerIndex: number): number {
if (layerIndex < 0 || layerIndex >= 16) return 0xFFFF;
return this.collisionMatrix[layerIndex];
}
/**
* 根据层索引获取层位值
*/
public getLayerBit(layerIndex: number): number {
if (layerIndex < 0 || layerIndex >= 16) return 1;
return 1 << layerIndex;
}
/**
* 从层位值获取层索引
*/
public getLayerIndex(layerBit: number): number {
for (let i = 0; i < 16; i++) {
if (layerBit === (1 << i)) {
return i;
}
}
// 如果是多层位值,返回第一个设置的位
for (let i = 0; i < 16; i++) {
if ((layerBit & (1 << i)) !== 0) {
return i;
}
}
return 0;
}
/**
* 加载配置
*/
public loadSettings(settings: Partial<CollisionLayerSettings>): void {
if (settings.layers) {
this.layers = settings.layers.map((layer, i) => ({
index: layer.index ?? i,
name: layer.name ?? `Layer${i}`,
description: layer.description
}));
// 确保有16个层
while (this.layers.length < 16) {
const idx = this.layers.length;
this.layers.push({ index: idx, name: `Layer${idx}` });
}
}
if (settings.collisionMatrix) {
this.collisionMatrix = [...settings.collisionMatrix];
while (this.collisionMatrix.length < 16) {
this.collisionMatrix.push(0xFFFF);
}
}
this.notifyListeners();
}
/**
* 导出配置
*/
public exportSettings(): CollisionLayerSettings {
return {
layers: [...this.layers],
collisionMatrix: [...this.collisionMatrix]
};
}
/**
* 重置为默认配置
*/
public resetToDefault(): void {
this.layers = [...DEFAULT_COLLISION_LAYERS];
this.collisionMatrix = [...DEFAULT_COLLISION_MATRIX];
this.notifyListeners();
}
/**
* 添加监听器
*/
public addListener(listener: () => void): void {
this.listeners.add(listener);
}
/**
* 移除监听器
*/
public removeListener(listener: () => void): void {
this.listeners.delete(listener);
}
private notifyListeners(): void {
for (const listener of this.listeners) {
listener();
}
}
}

View File

@@ -0,0 +1,214 @@
/**
* Physics2DService
* 2D 物理服务
*
* 提供全局物理配置和实用方法
*/
import type { IService } from '@esengine/ecs-framework';
import type { IVector2 } from '@esengine/ecs-framework-math';
import type { Physics2DConfig, RaycastHit2D, OverlapResult2D } from '../types/Physics2DTypes';
import { DEFAULT_PHYSICS_CONFIG, CollisionLayer2D } from '../types/Physics2DTypes';
import type { Physics2DSystem } from '../systems/Physics2DSystem';
/**
* 2D 物理服务
*
* 提供场景级别的物理配置和全局查询方法。
* 作为服务注册到 ServiceContainer 中。
*
* @example
* ```typescript
* // 从服务容器获取
* const physicsService = scene.services.resolve(Physics2DService);
*
* // 使用射线检测
* const hit = physicsService.raycast(origin, direction, 100);
* if (hit) {
* console.log('Hit entity:', hit.entityId);
* }
* ```
*/
export class Physics2DService implements IService {
private _config: Physics2DConfig = { ...DEFAULT_PHYSICS_CONFIG };
private _physicsSystem: Physics2DSystem | null = null;
/**
* 设置物理系统引用
* @internal
*/
public setPhysicsSystem(system: Physics2DSystem): void {
this._physicsSystem = system;
}
/**
* 获取物理系统
*/
public getPhysicsSystem(): Physics2DSystem | null {
return this._physicsSystem;
}
// ==================== 配置 ====================
/**
* 获取物理配置
*/
public getConfig(): Readonly<Physics2DConfig> {
return this._config;
}
/**
* 设置重力
*/
public setGravity(gravity: IVector2): void {
this._config.gravity = { ...gravity };
this._physicsSystem?.setGravity(gravity);
}
/**
* 获取重力
*/
public getGravity(): IVector2 {
return this._physicsSystem?.getGravity() ?? { ...this._config.gravity };
}
/**
* 设置时间步长
*/
public setTimestep(timestep: number): void {
this._config.timestep = timestep;
}
/**
* 获取时间步长
*/
public getTimestep(): number {
return this._config.timestep;
}
// ==================== 查询 ====================
/**
* 射线检测(第一个命中)
* @param origin 起点
* @param direction 方向(归一化)
* @param maxDistance 最大距离
* @param collisionMask 碰撞掩码(默认所有层)
*/
public raycast(
origin: IVector2,
direction: IVector2,
maxDistance: number,
collisionMask: number = CollisionLayer2D.All
): RaycastHit2D | null {
return this._physicsSystem?.raycast(origin, direction, maxDistance, collisionMask) ?? null;
}
/**
* 射线检测(所有命中)
* @param origin 起点
* @param direction 方向(归一化)
* @param maxDistance 最大距离
* @param collisionMask 碰撞掩码(默认所有层)
*/
public raycastAll(
origin: IVector2,
direction: IVector2,
maxDistance: number,
collisionMask: number = CollisionLayer2D.All
): RaycastHit2D[] {
return this._physicsSystem?.raycastAll(origin, direction, maxDistance, collisionMask) ?? [];
}
/**
* 点重叠检测
* @param point 检测点
* @param collisionMask 碰撞掩码
*/
public overlapPoint(point: IVector2, collisionMask: number = CollisionLayer2D.All): OverlapResult2D {
return this._physicsSystem?.overlapPoint(point, collisionMask) ?? { entityIds: [], colliderHandles: [] };
}
/**
* 圆形重叠检测
* @param center 圆心
* @param radius 半径
* @param collisionMask 碰撞掩码
*/
public overlapCircle(
center: IVector2,
radius: number,
collisionMask: number = CollisionLayer2D.All
): OverlapResult2D {
return this._physicsSystem?.overlapCircle(center, radius, collisionMask) ?? { entityIds: [], colliderHandles: [] };
}
/**
* 矩形重叠检测
* @param center 中心点
* @param halfExtents 半宽高
* @param rotation 旋转角度
* @param collisionMask 碰撞掩码
*/
public overlapBox(
center: IVector2,
halfExtents: IVector2,
rotation: number = 0,
collisionMask: number = CollisionLayer2D.All
): OverlapResult2D {
return (
this._physicsSystem?.overlapBox(center, halfExtents, rotation, collisionMask) ?? {
entityIds: [],
colliderHandles: []
}
);
}
// ==================== 工具方法 ====================
/**
* 归一化向量
*/
public normalize(v: IVector2): IVector2 {
const length = Math.sqrt(v.x * v.x + v.y * v.y);
if (length === 0) return { x: 0, y: 0 };
return { x: v.x / length, y: v.y / length };
}
/**
* 计算两点之间的距离
*/
public distance(a: IVector2, b: IVector2): number {
const dx = b.x - a.x;
const dy = b.y - a.y;
return Math.sqrt(dx * dx + dy * dy);
}
/**
* 计算向量长度
*/
public magnitude(v: IVector2): number {
return Math.sqrt(v.x * v.x + v.y * v.y);
}
/**
* 向量点积
*/
public dot(a: IVector2, b: IVector2): number {
return a.x * b.x + a.y * b.y;
}
/**
* 向量叉积返回标量2D 特有)
*/
public cross(a: IVector2, b: IVector2): number {
return a.x * b.y - a.y * b.x;
}
/**
* 释放资源
*/
public dispose(): void {
this._physicsSystem = null;
}
}

View File

@@ -0,0 +1,14 @@
/**
* Physics 2D Services exports
*/
export { Physics2DService } from './Physics2DService';
export {
CollisionLayerConfig,
DEFAULT_COLLISION_LAYERS,
DEFAULT_COLLISION_MATRIX
} from './CollisionLayerConfig';
export type {
CollisionLayerDefinition,
CollisionLayerSettings
} from './CollisionLayerConfig';