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,638 @@
import { EventDispatcher } from '../events/EventDispatcher';
import { FGUIEvents } from '../events/Events';
import { Point, Rectangle } from '../utils/MathTypes';
import type { IRenderCollector } from '../render/IRenderCollector';
import type { GObject } from '../core/GObject';
/**
* DisplayObject
*
* Abstract display object base class for all visual elements.
*
* 抽象显示对象基类,所有可视元素的基础
*/
export abstract class DisplayObject extends EventDispatcher {
/** Name of this display object | 显示对象名称 */
public name: string = '';
// Transform properties | 变换属性
protected _x: number = 0;
protected _y: number = 0;
protected _width: number = 0;
protected _height: number = 0;
protected _scaleX: number = 1;
protected _scaleY: number = 1;
protected _rotation: number = 0;
protected _pivotX: number = 0;
protected _pivotY: number = 0;
protected _skewX: number = 0;
protected _skewY: number = 0;
// Display properties | 显示属性
protected _alpha: number = 1;
protected _visible: boolean = true;
protected _touchable: boolean = true;
protected _grayed: boolean = false;
// Hierarchy | 层级关系
protected _parent: DisplayObject | null = null;
protected _children: DisplayObject[] = [];
// Stage reference | 舞台引用
protected _stage: DisplayObject | null = null;
// Dirty flags | 脏标记
protected _transformDirty: boolean = true;
protected _boundsDirty: boolean = true;
// Cached values | 缓存值
protected _worldAlpha: number = 1;
protected _worldMatrix: Float32Array = new Float32Array([1, 0, 0, 1, 0, 0]);
protected _bounds: Rectangle = new Rectangle();
// User data | 用户数据
public userData: unknown = null;
/** Owner GObject reference | 所属 GObject 引用 */
public gOwner: GObject | null = null;
constructor() {
super();
}
// Position | 位置
public get x(): number {
return this._x;
}
public set x(value: number) {
if (this._x !== value) {
this._x = value;
this.markTransformDirty();
}
}
public get y(): number {
return this._y;
}
public set y(value: number) {
if (this._y !== value) {
this._y = value;
this.markTransformDirty();
}
}
public setPosition(x: number, y: number): void {
if (this._x !== x || this._y !== y) {
this._x = x;
this._y = y;
this.markTransformDirty();
}
}
// Size | 尺寸
public get width(): number {
return this._width;
}
public set width(value: number) {
if (this._width !== value) {
this._width = value;
this.markBoundsDirty();
}
}
public get height(): number {
return this._height;
}
public set height(value: number) {
if (this._height !== value) {
this._height = value;
this.markBoundsDirty();
}
}
public setSize(width: number, height: number): void {
if (this._width !== width || this._height !== height) {
this._width = width;
this._height = height;
this.markBoundsDirty();
}
}
// Scale | 缩放
public get scaleX(): number {
return this._scaleX;
}
public set scaleX(value: number) {
if (this._scaleX !== value) {
this._scaleX = value;
this.markTransformDirty();
}
}
public get scaleY(): number {
return this._scaleY;
}
public set scaleY(value: number) {
if (this._scaleY !== value) {
this._scaleY = value;
this.markTransformDirty();
}
}
public setScale(scaleX: number, scaleY: number): void {
if (this._scaleX !== scaleX || this._scaleY !== scaleY) {
this._scaleX = scaleX;
this._scaleY = scaleY;
this.markTransformDirty();
}
}
// Rotation | 旋转
public get rotation(): number {
return this._rotation;
}
public set rotation(value: number) {
if (this._rotation !== value) {
this._rotation = value;
this.markTransformDirty();
}
}
// Pivot | 轴心点
public get pivotX(): number {
return this._pivotX;
}
public set pivotX(value: number) {
if (this._pivotX !== value) {
this._pivotX = value;
this.markTransformDirty();
}
}
public get pivotY(): number {
return this._pivotY;
}
public set pivotY(value: number) {
if (this._pivotY !== value) {
this._pivotY = value;
this.markTransformDirty();
}
}
public setPivot(pivotX: number, pivotY: number): void {
if (this._pivotX !== pivotX || this._pivotY !== pivotY) {
this._pivotX = pivotX;
this._pivotY = pivotY;
this.markTransformDirty();
}
}
// Skew | 倾斜
public get skewX(): number {
return this._skewX;
}
public set skewX(value: number) {
if (this._skewX !== value) {
this._skewX = value;
this.markTransformDirty();
}
}
public get skewY(): number {
return this._skewY;
}
public set skewY(value: number) {
if (this._skewY !== value) {
this._skewY = value;
this.markTransformDirty();
}
}
// Alpha | 透明度
public get alpha(): number {
return this._alpha;
}
public set alpha(value: number) {
if (this._alpha !== value) {
this._alpha = value;
}
}
// Visibility | 可见性
public get visible(): boolean {
return this._visible;
}
public set visible(value: boolean) {
this._visible = value;
}
// Touchable | 可触摸
public get touchable(): boolean {
return this._touchable;
}
public set touchable(value: boolean) {
this._touchable = value;
}
// Grayed | 灰度
public get grayed(): boolean {
return this._grayed;
}
public set grayed(value: boolean) {
this._grayed = value;
}
// Hierarchy | 层级
public get parent(): DisplayObject | null {
return this._parent;
}
/**
* Get stage reference
* 获取舞台引用
*/
public get stage(): DisplayObject | null {
return this._stage;
}
/**
* Set stage reference (internal use)
* 设置舞台引用(内部使用)
*
* @internal
*/
public setStage(stage: DisplayObject | null): void {
this._stage = stage;
}
public get numChildren(): number {
return this._children.length;
}
/**
* Add a child display object
* 添加子显示对象
*/
public addChild(child: DisplayObject): void {
this.addChildAt(child, this._children.length);
}
/**
* Add a child at specific index
* 在指定位置添加子显示对象
*/
public addChildAt(child: DisplayObject, index: number): void {
if (child._parent === this) {
this.setChildIndex(child, index);
return;
}
if (child._parent) {
child._parent.removeChild(child);
}
index = Math.max(0, Math.min(index, this._children.length));
this._children.splice(index, 0, child);
child._parent = this;
child.markTransformDirty();
// Dispatch addedToStage event if this is on stage
// 如果当前对象在舞台上,分发 addedToStage 事件
if (this._stage !== null) {
this.setChildStage(child, this._stage);
}
}
/**
* Set stage for child and its descendants, dispatch events
* 为子对象及其后代设置舞台,分发事件
*/
private setChildStage(child: DisplayObject, stage: DisplayObject | null): void {
const wasOnStage = child._stage !== null;
const isOnStage = stage !== null;
child._stage = stage;
if (!wasOnStage && isOnStage) {
// Dispatch addedToStage event
child.emit(FGUIEvents.ADDED_TO_STAGE);
} else if (wasOnStage && !isOnStage) {
// Dispatch removedFromStage event
child.emit(FGUIEvents.REMOVED_FROM_STAGE);
}
// Recursively set stage for all children
for (const grandChild of child._children) {
this.setChildStage(grandChild, stage);
}
}
/**
* Remove a child display object
* 移除子显示对象
*/
public removeChild(child: DisplayObject): void {
const index = this._children.indexOf(child);
if (index >= 0) {
this.removeChildAt(index);
}
}
/**
* Remove child at specific index
* 移除指定位置的子显示对象
*/
public removeChildAt(index: number): DisplayObject | null {
if (index < 0 || index >= this._children.length) {
return null;
}
const child = this._children[index];
// Dispatch removedFromStage event if on stage
// 如果在舞台上,分发 removedFromStage 事件
if (this._stage !== null) {
this.setChildStage(child, null);
}
this._children.splice(index, 1);
child._parent = null;
return child;
}
/**
* Remove all children
* 移除所有子显示对象
*/
public removeChildren(): void {
// Dispatch removedFromStage events if on stage
// 如果在舞台上,分发 removedFromStage 事件
if (this._stage !== null) {
for (const child of this._children) {
this.setChildStage(child, null);
}
}
for (const child of this._children) {
child._parent = null;
}
this._children.length = 0;
}
/**
* Get child at index
* 获取指定位置的子显示对象
*/
public getChildAt(index: number): DisplayObject | null {
if (index < 0 || index >= this._children.length) {
return null;
}
return this._children[index];
}
/**
* Get child index
* 获取子显示对象的索引
*/
public getChildIndex(child: DisplayObject): number {
return this._children.indexOf(child);
}
/**
* Set child index
* 设置子显示对象的索引
*/
public setChildIndex(child: DisplayObject, index: number): void {
const currentIndex = this._children.indexOf(child);
if (currentIndex < 0) return;
index = Math.max(0, Math.min(index, this._children.length - 1));
if (currentIndex === index) return;
this._children.splice(currentIndex, 1);
this._children.splice(index, 0, child);
}
/**
* Swap two children
* 交换两个子显示对象
*/
public swapChildren(child1: DisplayObject, child2: DisplayObject): void {
const index1 = this._children.indexOf(child1);
const index2 = this._children.indexOf(child2);
if (index1 >= 0 && index2 >= 0) {
this._children[index1] = child2;
this._children[index2] = child1;
}
}
/**
* Get child by name
* 通过名称获取子显示对象
*/
public getChildByName(name: string): DisplayObject | null {
for (const child of this._children) {
if (child.name === name) {
return child;
}
}
return null;
}
// Transform | 变换
/**
* Update world matrix
* 更新世界矩阵
*
* World matrix is in FGUI's coordinate system (top-left origin, Y-down).
* Coordinate system conversion to engine (center origin, Y-up) is done in FGUIRenderDataProvider.
*
* 世界矩阵使用 FGUI 坐标系左上角原点Y 向下)。
* 坐标系转换到引擎中心原点Y 向上)在 FGUIRenderDataProvider 中完成。
*/
public updateTransform(): void {
if (!this._transformDirty) return;
const m = this._worldMatrix;
const rad = (this._rotation * Math.PI) / 180;
const cos = Math.cos(rad);
const sin = Math.sin(rad);
m[0] = cos * this._scaleX;
m[1] = sin * this._scaleX;
m[2] = -sin * this._scaleY;
m[3] = cos * this._scaleY;
// Keep FGUI's coordinate system (top-left origin, Y-down)
// 保持 FGUI 坐标系左上角原点Y 向下)
m[4] = this._x - this._pivotX * m[0] - this._pivotY * m[2];
m[5] = this._y - this._pivotX * m[1] - this._pivotY * m[3];
if (this._parent) {
const pm = this._parent._worldMatrix;
const a = m[0], b = m[1], c = m[2], d = m[3], tx = m[4], ty = m[5];
m[0] = a * pm[0] + b * pm[2];
m[1] = a * pm[1] + b * pm[3];
m[2] = c * pm[0] + d * pm[2];
m[3] = c * pm[1] + d * pm[3];
m[4] = tx * pm[0] + ty * pm[2] + pm[4];
m[5] = tx * pm[1] + ty * pm[3] + pm[5];
this._worldAlpha = this._alpha * this._parent._worldAlpha;
} else {
this._worldAlpha = this._alpha;
}
this._transformDirty = false;
for (const child of this._children) {
child.markTransformDirty();
child.updateTransform();
}
}
/**
* Local to global point conversion
* 本地坐标转全局坐标
*/
public localToGlobal(localPoint: Point, outPoint?: Point): Point {
this.updateTransform();
outPoint = outPoint || new Point();
const m = this._worldMatrix;
outPoint.x = localPoint.x * m[0] + localPoint.y * m[2] + m[4];
outPoint.y = localPoint.x * m[1] + localPoint.y * m[3] + m[5];
return outPoint;
}
/**
* Global to local point conversion
* 全局坐标转本地坐标
*/
public globalToLocal(globalPoint: Point, outPoint?: Point): Point {
this.updateTransform();
outPoint = outPoint || new Point();
const m = this._worldMatrix;
const det = m[0] * m[3] - m[1] * m[2];
if (det === 0) {
outPoint.x = 0;
outPoint.y = 0;
} else {
const invDet = 1 / det;
const x = globalPoint.x - m[4];
const y = globalPoint.y - m[5];
outPoint.x = (x * m[3] - y * m[2]) * invDet;
outPoint.y = (y * m[0] - x * m[1]) * invDet;
}
return outPoint;
}
/**
* Hit test
* 碰撞检测
*/
public hitTest(globalX: number, globalY: number): DisplayObject | null {
if (!this._visible || !this._touchable) {
return null;
}
const localPoint = this.globalToLocal(new Point(globalX, globalY));
if (
localPoint.x >= 0 &&
localPoint.x < this._width &&
localPoint.y >= 0 &&
localPoint.y < this._height
) {
for (let i = this._children.length - 1; i >= 0; i--) {
const hit = this._children[i].hitTest(globalX, globalY);
if (hit) return hit;
}
return this;
}
return null;
}
// Dirty flags | 脏标记
protected markTransformDirty(): void {
this._transformDirty = true;
this._boundsDirty = true;
}
protected markBoundsDirty(): void {
this._boundsDirty = true;
}
// Render data collection | 渲染数据收集
/**
* Collect render data (abstract - implemented by subclasses)
* 收集渲染数据(抽象方法 - 由子类实现)
*/
public abstract collectRenderData(collector: IRenderCollector): void;
/**
* Get world matrix
* 获取世界矩阵
*/
public get worldMatrix(): Float32Array {
return this._worldMatrix;
}
/**
* Get world alpha
* 获取世界透明度
*/
public get worldAlpha(): number {
return this._worldAlpha;
}
/**
* Dispose
* 销毁
*/
public dispose(): void {
if (this._parent) {
this._parent.removeChild(this);
}
for (const child of this._children) {
child.dispose();
}
this._children.length = 0;
super.dispose();
}
}