feat(world-streaming): 添加世界流式加载系统 (#288)
实现基于区块的世界流式加载系统,支持开放世界游戏: 运行时包 (@esengine/world-streaming): - ChunkComponent: 区块实体组件,包含坐标、边界、状态 - StreamingAnchorComponent: 流式锚点组件(玩家/摄像机) - ChunkLoaderComponent: 流式加载配置组件 - ChunkStreamingSystem: 区块加载/卸载调度系统 - ChunkCullingSystem: 区块可见性剔除系统 - ChunkManager: 区块生命周期管理服务 - SpatialHashGrid: 空间哈希网格 - ChunkSerializer: 区块序列化 编辑器包 (@esengine/world-streaming-editor): - ChunkVisualizer: 区块可视化覆盖层 - ChunkLoaderInspectorProvider: 区块加载器检视器 - StreamingAnchorInspectorProvider: 流式锚点检视器 - WorldStreamingPlugin: 完整插件导出
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* ChunkLoader Inspector Provider
|
||||
*
|
||||
* Custom inspector for ChunkLoaderComponent with streaming configuration.
|
||||
*/
|
||||
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Settings, Play, Pause, RefreshCw } from 'lucide-react';
|
||||
import type { IInspectorProvider, InspectorContext } from '@esengine/editor-core';
|
||||
import type { ChunkLoaderComponent } from '@esengine/world-streaming';
|
||||
|
||||
interface ChunkLoaderInspectorData {
|
||||
entityId: string;
|
||||
component: ChunkLoaderComponent;
|
||||
}
|
||||
|
||||
export class ChunkLoaderInspectorProvider implements IInspectorProvider<ChunkLoaderInspectorData> {
|
||||
readonly id = 'chunk-loader-inspector';
|
||||
readonly name = 'Chunk Loader Inspector';
|
||||
readonly priority = 100;
|
||||
|
||||
canHandle(target: unknown): target is ChunkLoaderInspectorData {
|
||||
if (typeof target !== 'object' || target === null) return false;
|
||||
const obj = target as Record<string, unknown>;
|
||||
return 'entityId' in obj && 'component' in obj &&
|
||||
obj.component !== null &&
|
||||
typeof obj.component === 'object' &&
|
||||
'chunkSize' in (obj.component as Record<string, unknown>) &&
|
||||
'loadRadius' in (obj.component as Record<string, unknown>);
|
||||
}
|
||||
|
||||
render(data: ChunkLoaderInspectorData, _context: InspectorContext): React.ReactElement {
|
||||
const { component } = data;
|
||||
|
||||
return (
|
||||
<div className="entity-inspector">
|
||||
<div className="inspector-section">
|
||||
<div className="section-title">
|
||||
<Settings size={14} style={{ marginRight: '6px' }} />
|
||||
Streaming Configuration
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Chunk Size</label>
|
||||
<span>{component.chunkSize} units</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Load Radius</label>
|
||||
<span>{component.loadRadius} chunks</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Unload Radius</label>
|
||||
<span>{component.unloadRadius} chunks</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Max Loads/Frame</label>
|
||||
<span>{component.maxLoadsPerFrame}</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Unload Delay</label>
|
||||
<span>{component.unloadDelay}ms</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Prefetch</label>
|
||||
<span>{component.bEnablePrefetch ? 'Enabled' : 'Disabled'}</span>
|
||||
</div>
|
||||
|
||||
{component.bEnablePrefetch && (
|
||||
<div className="property-row">
|
||||
<label>Prefetch Radius</label>
|
||||
<span>{component.prefetchRadius} chunks</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* StreamingAnchor Inspector Provider
|
||||
*
|
||||
* Custom inspector for StreamingAnchorComponent.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Anchor, Navigation } from 'lucide-react';
|
||||
import type { IInspectorProvider, InspectorContext } from '@esengine/editor-core';
|
||||
import type { StreamingAnchorComponent } from '@esengine/world-streaming';
|
||||
|
||||
interface StreamingAnchorInspectorData {
|
||||
entityId: string;
|
||||
component: StreamingAnchorComponent;
|
||||
}
|
||||
|
||||
export class StreamingAnchorInspectorProvider implements IInspectorProvider<StreamingAnchorInspectorData> {
|
||||
readonly id = 'streaming-anchor-inspector';
|
||||
readonly name = 'Streaming Anchor Inspector';
|
||||
readonly priority = 100;
|
||||
|
||||
canHandle(target: unknown): target is StreamingAnchorInspectorData {
|
||||
if (typeof target !== 'object' || target === null) return false;
|
||||
const obj = target as Record<string, unknown>;
|
||||
return 'entityId' in obj && 'component' in obj &&
|
||||
obj.component !== null &&
|
||||
typeof obj.component === 'object' &&
|
||||
'weight' in (obj.component as Record<string, unknown>) &&
|
||||
'bEnablePrefetch' in (obj.component as Record<string, unknown>) &&
|
||||
'velocityX' in (obj.component as Record<string, unknown>);
|
||||
}
|
||||
|
||||
render(data: StreamingAnchorInspectorData, _context: InspectorContext): React.ReactElement {
|
||||
const { component } = data;
|
||||
|
||||
const velocity = Math.sqrt(
|
||||
component.velocityX * component.velocityX +
|
||||
component.velocityY * component.velocityY
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="entity-inspector">
|
||||
<div className="inspector-section">
|
||||
<div className="section-title">
|
||||
<Anchor size={14} style={{ marginRight: '6px' }} />
|
||||
Streaming Anchor
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Weight</label>
|
||||
<span>{component.weight.toFixed(2)}</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Prefetch</label>
|
||||
<span>{component.bEnablePrefetch ? 'Enabled' : 'Disabled'}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="inspector-section">
|
||||
<div className="section-title">
|
||||
<Navigation size={14} style={{ marginRight: '6px' }} />
|
||||
Movement (Runtime)
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Velocity</label>
|
||||
<span>{velocity.toFixed(1)} u/s</span>
|
||||
</div>
|
||||
|
||||
<div className="property-row">
|
||||
<label>Direction</label>
|
||||
<span>
|
||||
({component.velocityX.toFixed(1)}, {component.velocityY.toFixed(1)})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user