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:
@@ -0,0 +1,103 @@
|
||||
import { Component, ECSComponent, Serializable, Serialize, Property } from '@esengine/ecs-framework';
|
||||
import type { IChunkCoord, IChunkBounds } from '../types';
|
||||
import { EChunkState } from '../types';
|
||||
|
||||
/**
|
||||
* 区块组件
|
||||
*
|
||||
* Attached to chunk root entities. Tracks chunk state and bounds.
|
||||
*
|
||||
* 区块组件挂载在区块根实体上,用于管理区块状态和边界信息。
|
||||
*/
|
||||
@ECSComponent('Chunk')
|
||||
@Serializable({ version: 1, typeId: 'Chunk' })
|
||||
export class ChunkComponent extends Component {
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Coord X', readOnly: true })
|
||||
private _coordX: number = 0;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Coord Y', readOnly: true })
|
||||
private _coordY: number = 0;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'string', label: 'State', readOnly: true })
|
||||
private _state: EChunkState = EChunkState.Unloaded;
|
||||
|
||||
@Serialize()
|
||||
private _minX: number = 0;
|
||||
|
||||
@Serialize()
|
||||
private _minY: number = 0;
|
||||
|
||||
@Serialize()
|
||||
private _maxX: number = 0;
|
||||
|
||||
@Serialize()
|
||||
private _maxY: number = 0;
|
||||
|
||||
private _lastAccessTime: number = 0;
|
||||
|
||||
get coord(): IChunkCoord {
|
||||
return { x: this._coordX, y: this._coordY };
|
||||
}
|
||||
|
||||
get bounds(): IChunkBounds {
|
||||
return {
|
||||
minX: this._minX,
|
||||
minY: this._minY,
|
||||
maxX: this._maxX,
|
||||
maxY: this._maxY
|
||||
};
|
||||
}
|
||||
|
||||
get state(): EChunkState {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
get lastAccessTime(): number {
|
||||
return this._lastAccessTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化区块
|
||||
*
|
||||
* Initialize chunk with coordinates and bounds.
|
||||
*/
|
||||
initialize(coord: IChunkCoord, bounds: IChunkBounds): void {
|
||||
this._coordX = coord.x;
|
||||
this._coordY = coord.y;
|
||||
this._minX = bounds.minX;
|
||||
this._minY = bounds.minY;
|
||||
this._maxX = bounds.maxX;
|
||||
this._maxY = bounds.maxY;
|
||||
this._lastAccessTime = Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置区块状态
|
||||
*
|
||||
* Set chunk state.
|
||||
*/
|
||||
setState(state: EChunkState): void {
|
||||
this._state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新访问时间
|
||||
*
|
||||
* Update last access time for LRU tracking.
|
||||
*/
|
||||
touch(): void {
|
||||
this._lastAccessTime = Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查点是否在区块内
|
||||
*
|
||||
* Check if a point is within chunk bounds.
|
||||
*/
|
||||
containsPoint(x: number, y: number): boolean {
|
||||
return x >= this._minX && x < this._maxX && y >= this._minY && y < this._maxY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { Component, ECSComponent, Serializable, Serialize, Property } from '@esengine/ecs-framework';
|
||||
import type { IChunkCoord, IStreamingConfig } from '../types';
|
||||
import { DEFAULT_STREAMING_CONFIG } from '../types';
|
||||
|
||||
/**
|
||||
* 区块加载器组件
|
||||
*
|
||||
* Singleton component that manages streaming configuration.
|
||||
* Attach to a manager entity in the scene.
|
||||
*
|
||||
* 单例组件,管理流式加载配置。挂载在场景管理实体上。
|
||||
*/
|
||||
@ECSComponent('ChunkLoader')
|
||||
@Serializable({ version: 1, typeId: 'ChunkLoader' })
|
||||
export class ChunkLoaderComponent extends Component {
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Chunk Size', min: 64, max: 4096 })
|
||||
private _chunkSize: number = DEFAULT_STREAMING_CONFIG.chunkSize;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Load Radius', min: 1, max: 10 })
|
||||
private _loadRadius: number = DEFAULT_STREAMING_CONFIG.loadRadius;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Unload Radius', min: 2, max: 20 })
|
||||
private _unloadRadius: number = DEFAULT_STREAMING_CONFIG.unloadRadius;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Max Loads Per Frame', min: 1, max: 10 })
|
||||
private _maxLoadsPerFrame: number = DEFAULT_STREAMING_CONFIG.maxLoadsPerFrame;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Max Unloads Per Frame', min: 1, max: 10 })
|
||||
private _maxUnloadsPerFrame: number = DEFAULT_STREAMING_CONFIG.maxUnloadsPerFrame;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Unload Delay (ms)', min: 0, max: 30000 })
|
||||
private _unloadDelay: number = DEFAULT_STREAMING_CONFIG.unloadDelay;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'boolean', label: 'Enable Prefetch' })
|
||||
private _bEnablePrefetch: boolean = DEFAULT_STREAMING_CONFIG.bEnablePrefetch;
|
||||
|
||||
@Serialize()
|
||||
@Property({ type: 'integer', label: 'Prefetch Radius', min: 0, max: 5 })
|
||||
private _prefetchRadius: number = DEFAULT_STREAMING_CONFIG.prefetchRadius;
|
||||
|
||||
get chunkSize(): number {
|
||||
return this._chunkSize;
|
||||
}
|
||||
|
||||
get loadRadius(): number {
|
||||
return this._loadRadius;
|
||||
}
|
||||
|
||||
get unloadRadius(): number {
|
||||
return this._unloadRadius;
|
||||
}
|
||||
|
||||
get maxLoadsPerFrame(): number {
|
||||
return this._maxLoadsPerFrame;
|
||||
}
|
||||
|
||||
get maxUnloadsPerFrame(): number {
|
||||
return this._maxUnloadsPerFrame;
|
||||
}
|
||||
|
||||
get unloadDelay(): number {
|
||||
return this._unloadDelay;
|
||||
}
|
||||
|
||||
get bEnablePrefetch(): boolean {
|
||||
return this._bEnablePrefetch;
|
||||
}
|
||||
|
||||
get prefetchRadius(): number {
|
||||
return this._prefetchRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用配置
|
||||
*
|
||||
* Apply streaming configuration.
|
||||
*/
|
||||
applyConfig(config: Partial<IStreamingConfig>): void {
|
||||
if (config.chunkSize !== undefined) this._chunkSize = config.chunkSize;
|
||||
if (config.loadRadius !== undefined) this._loadRadius = config.loadRadius;
|
||||
if (config.unloadRadius !== undefined) this._unloadRadius = config.unloadRadius;
|
||||
if (config.maxLoadsPerFrame !== undefined) this._maxLoadsPerFrame = config.maxLoadsPerFrame;
|
||||
if (config.maxUnloadsPerFrame !== undefined) this._maxUnloadsPerFrame = config.maxUnloadsPerFrame;
|
||||
if (config.unloadDelay !== undefined) this._unloadDelay = config.unloadDelay;
|
||||
if (config.bEnablePrefetch !== undefined) this._bEnablePrefetch = config.bEnablePrefetch;
|
||||
if (config.prefetchRadius !== undefined) this._prefetchRadius = config.prefetchRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* 世界坐标转区块坐标
|
||||
*
|
||||
* Convert world position to chunk coordinates.
|
||||
*/
|
||||
worldToChunk(worldX: number, worldY: number): IChunkCoord {
|
||||
return {
|
||||
x: Math.floor(worldX / this._chunkSize),
|
||||
y: Math.floor(worldY / this._chunkSize)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 区块坐标转世界坐标(返回区块中心)
|
||||
*
|
||||
* Convert chunk coordinates to world position (chunk center).
|
||||
*/
|
||||
chunkToWorld(coord: IChunkCoord): { x: number; y: number } {
|
||||
return {
|
||||
x: coord.x * this._chunkSize + this._chunkSize * 0.5,
|
||||
y: coord.y * this._chunkSize + this._chunkSize * 0.5
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区块边界
|
||||
*
|
||||
* Get chunk world-space bounds.
|
||||
*/
|
||||
getChunkBounds(coord: IChunkCoord): { minX: number; minY: number; maxX: number; maxY: number } {
|
||||
return {
|
||||
minX: coord.x * this._chunkSize,
|
||||
minY: coord.y * this._chunkSize,
|
||||
maxX: (coord.x + 1) * this._chunkSize,
|
||||
maxY: (coord.y + 1) * this._chunkSize
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Component, ECSComponent, Serializable, Serialize, Property } from '@esengine/ecs-framework';
|
||||
|
||||
/**
|
||||
* 流式锚点组件
|
||||
*
|
||||
* Marks an entity as a streaming anchor point.
|
||||
* Chunks are loaded/unloaded based on distance to anchors.
|
||||
*
|
||||
* 标记实体作为流式加载锚点。通常挂载在玩家或摄像机实体上,
|
||||
* 系统会根据锚点位置加载/卸载周围区块。
|
||||
*/
|
||||
@ECSComponent('StreamingAnchor')
|
||||
@Serializable({ version: 1, typeId: 'StreamingAnchor' })
|
||||
export class StreamingAnchorComponent extends Component {
|
||||
/**
|
||||
* 锚点权重
|
||||
*
|
||||
* Weight multiplier for this anchor's load radius.
|
||||
* Higher values mean larger load radius around this anchor.
|
||||
*/
|
||||
@Serialize()
|
||||
@Property({ type: 'number', label: 'Weight', min: 0.1, max: 10 })
|
||||
weight: number = 1.0;
|
||||
|
||||
/**
|
||||
* 是否启用预加载
|
||||
*
|
||||
* Enable directional prefetching based on movement.
|
||||
*/
|
||||
@Serialize()
|
||||
@Property({ type: 'boolean', label: 'Enable Prefetch' })
|
||||
bEnablePrefetch: boolean = true;
|
||||
|
||||
/**
|
||||
* 上一帧位置 X
|
||||
*
|
||||
* Previous frame X position for velocity calculation.
|
||||
*/
|
||||
previousX: number = 0;
|
||||
|
||||
/**
|
||||
* 上一帧位置 Y
|
||||
*
|
||||
* Previous frame Y position for velocity calculation.
|
||||
*/
|
||||
previousY: number = 0;
|
||||
|
||||
/**
|
||||
* 速度 X 分量
|
||||
*
|
||||
* X component of velocity (units per second).
|
||||
*/
|
||||
velocityX: number = 0;
|
||||
|
||||
/**
|
||||
* 速度 Y 分量
|
||||
*
|
||||
* Y component of velocity (units per second).
|
||||
*/
|
||||
velocityY: number = 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { ChunkComponent } from './ChunkComponent';
|
||||
export { StreamingAnchorComponent } from './StreamingAnchorComponent';
|
||||
export { ChunkLoaderComponent } from './ChunkLoaderComponent';
|
||||
Reference in New Issue
Block a user