core核心rust实现
This commit is contained in:
34
packages/core-rust/Cargo.toml
Normal file
34
packages/core-rust/Cargo.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "ecs-core-rust"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
description = "基于Rust和WebAssembly的高性能ECS框架核心实现"
|
||||
authors = ["yhh"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/esengine/ecs-framework.git"
|
||||
keywords = ["ecs", "entity-component-system", "game-engine", "wasm", "webassembly"]
|
||||
|
||||
[package.metadata.wasm-pack.profile.release.wasm-bindgen]
|
||||
out-name = "ecs-core-rust"
|
||||
|
||||
[package.metadata.wasm-pack]
|
||||
name = "@esengine/ecs-framework-wasm"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||
js-sys = "0.3"
|
||||
web-sys = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde-wasm-bindgen = "0.4"
|
||||
serde_json = "1.0"
|
||||
rustc-hash = "1.1"
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook"]
|
||||
|
||||
[package.metadata.wasm-pack.profile.release]
|
||||
wasm-opt = false
|
||||
41
packages/core-rust/build-to-core.bat
Normal file
41
packages/core-rust/build-to-core.bat
Normal file
@@ -0,0 +1,41 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM 构建WASM到core库的脚本 (Windows版本)
|
||||
|
||||
echo 🚀 开始构建 WASM 到 core 库...
|
||||
|
||||
REM 确保在正确的目录
|
||||
cd /d "%~dp0"
|
||||
|
||||
REM 确保目标目录存在
|
||||
if not exist "..\core\wasm" mkdir "..\core\wasm"
|
||||
|
||||
REM 构建WASM包
|
||||
echo 📦 构建 WASM 包...
|
||||
wasm-pack build --target web --out-dir temp-pkg
|
||||
|
||||
REM 检查构建是否成功
|
||||
if not exist "temp-pkg" (
|
||||
echo ❌ WASM构建失败
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 复制文件到core库
|
||||
echo 📁 复制文件到 core\wasm...
|
||||
copy "temp-pkg\*.wasm" "..\core\wasm\" >nul
|
||||
copy "temp-pkg\*.js" "..\core\wasm\" >nul
|
||||
copy "temp-pkg\*.ts" "..\core\wasm\" >nul
|
||||
|
||||
REM 清理临时文件
|
||||
echo 🧹 清理临时文件...
|
||||
rmdir /s /q temp-pkg
|
||||
|
||||
echo ✅ 构建完成!WASM文件已输出到 packages\core\wasm\
|
||||
echo.
|
||||
echo 文件列表:
|
||||
dir "..\core\wasm\"
|
||||
echo.
|
||||
echo 🎯 现在可以在 TypeScript 中直接导入 WASM 模块了!
|
||||
|
||||
pause
|
||||
40
packages/core-rust/build-to-core.sh
Normal file
40
packages/core-rust/build-to-core.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 构建WASM到core库的脚本
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 开始构建 WASM 到 core 库..."
|
||||
|
||||
# 确保在正确的目录
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# 确保目标目录存在
|
||||
mkdir -p ../core/wasm
|
||||
|
||||
# 构建WASM包
|
||||
echo "📦 构建 WASM 包..."
|
||||
wasm-pack build --target web --out-dir temp-pkg
|
||||
|
||||
# 检查构建是否成功
|
||||
if [ ! -d "temp-pkg" ]; then
|
||||
echo "❌ WASM构建失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 复制文件到core库,排除不需要的文件
|
||||
echo "📁 复制文件到 core/wasm..."
|
||||
cp temp-pkg/*.wasm ../core/wasm/
|
||||
cp temp-pkg/*.js ../core/wasm/
|
||||
cp temp-pkg/*.ts ../core/wasm/
|
||||
|
||||
# 清理临时文件
|
||||
echo "🧹 清理临时文件..."
|
||||
rm -rf temp-pkg
|
||||
|
||||
echo "✅ 构建完成!WASM文件已输出到 packages/core/wasm/"
|
||||
echo ""
|
||||
echo "文件列表:"
|
||||
ls -la ../core/wasm/
|
||||
echo ""
|
||||
echo "🎯 现在可以在 TypeScript 中直接导入 WASM 模块了!"
|
||||
89
packages/core-rust/build.ps1
Normal file
89
packages/core-rust/build.ps1
Normal file
@@ -0,0 +1,89 @@
|
||||
# Windows PowerShell构建脚本
|
||||
param(
|
||||
[switch]$Install,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
if ($Help) {
|
||||
Write-Host "ECS Core Rust WASM构建脚本"
|
||||
Write-Host ""
|
||||
Write-Host "用法:"
|
||||
Write-Host " .\build.ps1 # 构建WASM包"
|
||||
Write-Host " .\build.ps1 -Install # 安装依赖并构建"
|
||||
Write-Host " .\build.ps1 -Help # 显示帮助"
|
||||
Write-Host ""
|
||||
Write-Host "环境要求:"
|
||||
Write-Host " - Rust (rustup)"
|
||||
Write-Host " - wasm-pack"
|
||||
exit
|
||||
}
|
||||
|
||||
Write-Host "开始构建Rust WASM包..." -ForegroundColor Green
|
||||
|
||||
# 检查Rust是否安装
|
||||
if (!(Get-Command cargo -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "错误: 未找到cargo命令" -ForegroundColor Red
|
||||
if ($Install) {
|
||||
Write-Host "正在安装Rust..." -ForegroundColor Yellow
|
||||
# 下载并运行Rust安装程序
|
||||
Invoke-RestMethod -Uri https://win.rustup.rs/ -OutFile rustup-init.exe
|
||||
.\rustup-init.exe -y --default-toolchain stable
|
||||
Remove-Item rustup-init.exe
|
||||
|
||||
# 重新加载PATH
|
||||
$env:PATH = [System.Environment]::GetEnvironmentVariable("PATH","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH","User")
|
||||
|
||||
# 添加Cargo到当前会话的PATH
|
||||
if (Test-Path "$env:USERPROFILE\.cargo\bin") {
|
||||
$env:PATH += ";$env:USERPROFILE\.cargo\bin"
|
||||
}
|
||||
} else {
|
||||
Write-Host "请先安装Rust: https://rustup.rs/" -ForegroundColor Red
|
||||
Write-Host "或者使用 -Install 参数自动安装" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# 检查wasm-pack是否安装
|
||||
if (!(Get-Command wasm-pack -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "未找到wasm-pack,正在安装..." -ForegroundColor Yellow
|
||||
if ($Install -or (Read-Host "是否安装wasm-pack? (y/N)").ToLower() -eq 'y') {
|
||||
# 使用cargo安装wasm-pack
|
||||
cargo install wasm-pack
|
||||
} else {
|
||||
Write-Host "请先安装wasm-pack: https://rustwasm.github.io/wasm-pack/installer/" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# 添加wasm32目标
|
||||
Write-Host "添加wasm32目标..." -ForegroundColor Yellow
|
||||
rustup target add wasm32-unknown-unknown
|
||||
|
||||
# 构建WASM包
|
||||
Write-Host "构建WASM包..." -ForegroundColor Yellow
|
||||
$env:RUST_LOG = "warn" # 减少日志输出
|
||||
|
||||
try {
|
||||
wasm-pack build --target web --out-dir ..\core\src\wasm --out-name ecs-core-rust
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "构建成功!" -ForegroundColor Green
|
||||
Write-Host "生成的文件位于: ..\core\src\wasm\" -ForegroundColor Green
|
||||
|
||||
# 显示生成的文件
|
||||
Write-Host "`n生成的文件:" -ForegroundColor Cyan
|
||||
Get-ChildItem ..\core\src\wasm\ | ForEach-Object {
|
||||
Write-Host " $($_.Name)" -ForegroundColor Gray
|
||||
}
|
||||
} else {
|
||||
Write-Host "构建失败,退出码: $LASTEXITCODE" -ForegroundColor Red
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
} catch {
|
||||
Write-Host "构建过程中发生错误: $($_.Exception.Message)" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "`n构建完成!" -ForegroundColor Green
|
||||
Write-Host "现在可以在TypeScript中使用WASM版本的ECS核心了。" -ForegroundColor Green
|
||||
91
packages/core-rust/build.sh
Normal file
91
packages/core-rust/build.sh
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Linux/macOS构建脚本
|
||||
|
||||
print_help() {
|
||||
echo "ECS Core Rust WASM构建脚本"
|
||||
echo ""
|
||||
echo "用法:"
|
||||
echo " ./build.sh # 构建WASM包"
|
||||
echo " ./build.sh --install # 安装依赖并构建"
|
||||
echo " ./build.sh --help # 显示帮助"
|
||||
echo ""
|
||||
echo "环境要求:"
|
||||
echo " - Rust (rustup)"
|
||||
echo " - wasm-pack"
|
||||
}
|
||||
|
||||
# 解析参数
|
||||
INSTALL=false
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--install)
|
||||
INSTALL=true
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "未知参数: $arg"
|
||||
print_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "开始构建Rust WASM包..."
|
||||
|
||||
# 检查Rust是否安装
|
||||
if ! command -v cargo &> /dev/null; then
|
||||
echo "错误: 未找到cargo命令"
|
||||
if [ "$INSTALL" = true ]; then
|
||||
echo "正在安装Rust..."
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
source ~/.cargo/env
|
||||
else
|
||||
echo "请先安装Rust: https://rustup.rs/"
|
||||
echo "或者使用 --install 参数自动安装"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 确保环境变量加载
|
||||
if [ -f ~/.cargo/env ]; then
|
||||
source ~/.cargo/env
|
||||
fi
|
||||
|
||||
# 检查wasm-pack是否安装
|
||||
if ! command -v wasm-pack &> /dev/null; then
|
||||
echo "未找到wasm-pack,正在安装..."
|
||||
if [ "$INSTALL" = true ] || { echo "是否安装wasm-pack? (y/N)"; read -r response; [ "$response" = "y" ] || [ "$response" = "Y" ]; }; then
|
||||
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
else
|
||||
echo "请先安装wasm-pack: https://rustwasm.github.io/wasm-pack/installer/"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 添加wasm32目标
|
||||
echo "添加wasm32目标..."
|
||||
rustup target add wasm32-unknown-unknown
|
||||
|
||||
# 构建WASM包
|
||||
echo "构建WASM包..."
|
||||
export RUST_LOG=warn # 减少日志输出
|
||||
|
||||
if wasm-pack build --target web --out-dir ../core/src/wasm --out-name ecs-core-rust; then
|
||||
echo "构建成功!"
|
||||
echo "生成的文件位于: ../core/src/wasm/"
|
||||
|
||||
# 显示生成的文件
|
||||
echo -e "\n生成的文件:"
|
||||
ls -la ../core/src/wasm/ | grep -v '^d' | awk '{print " " $9}' | grep -v '^$'
|
||||
else
|
||||
echo "构建失败,退出码: $?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n构建完成!"
|
||||
echo "现在可以在TypeScript中使用WASM版本的ECS核心了。"
|
||||
758
packages/core-rust/src/core/archetype_system.rs
Normal file
758
packages/core-rust/src/core/archetype_system.rs
Normal file
@@ -0,0 +1,758 @@
|
||||
use crate::utils::ComponentType;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/**
|
||||
* 原型标识符
|
||||
* 基于组件类型组合生成的唯一标识符
|
||||
*/
|
||||
pub type ArchetypeId = String;
|
||||
|
||||
/**
|
||||
* 原型数据结构
|
||||
* 将具有相同组件组合的实体分组存储
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Archetype {
|
||||
/// 原型唯一标识符
|
||||
pub id: ArchetypeId,
|
||||
/// 包含的组件类型集合
|
||||
pub component_types: Vec<ComponentType>,
|
||||
/// 属于该原型的实体列表
|
||||
pub entities: Vec<u32>,
|
||||
/// 原型创建时间(毫秒时间戳)
|
||||
pub created_at: u64,
|
||||
/// 最后更新时间(毫秒时间戳)
|
||||
pub updated_at: u64,
|
||||
/// 组件类型的位掩码(快速匹配)
|
||||
pub component_mask: u64,
|
||||
}
|
||||
|
||||
impl Archetype {
|
||||
/**
|
||||
* 创建新的原型
|
||||
*/
|
||||
pub fn new(component_types: Vec<ComponentType>) -> Self {
|
||||
let id = Self::generate_id(&component_types);
|
||||
let component_mask = Self::calculate_mask(&component_types);
|
||||
let now = current_timestamp();
|
||||
|
||||
Self {
|
||||
id,
|
||||
component_types,
|
||||
entities: Vec::new(),
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
component_mask,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成原型ID
|
||||
*/
|
||||
fn generate_id(component_types: &[ComponentType]) -> ArchetypeId {
|
||||
let mut sorted_types = component_types.to_vec();
|
||||
sorted_types.sort_by_key(|t| format!("{:?}", t));
|
||||
|
||||
// 使用组件类型的哈希值组合生成ID
|
||||
let combined = sorted_types.iter()
|
||||
.map(|t| format!("{:?}", t))
|
||||
.collect::<Vec<_>>()
|
||||
.join("|");
|
||||
|
||||
format!("archetype_{:x}", hash_string(&combined))
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算组件类型的位掩码
|
||||
*/
|
||||
fn calculate_mask(component_types: &[ComponentType]) -> u64 {
|
||||
// 简化实现:使用组件类型哈希的前64位作为掩码
|
||||
let mut mask = 0u64;
|
||||
for (i, component_type) in component_types.iter().enumerate() {
|
||||
if i >= 64 { break; } // 最多支持64种组件类型的掩码
|
||||
let type_hash = hash_component_type(*component_type);
|
||||
mask |= 1u64 << (type_hash % 64);
|
||||
}
|
||||
mask
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体到原型
|
||||
*/
|
||||
pub fn add_entity(&mut self, entity_id: u32) {
|
||||
if !self.entities.contains(&entity_id) {
|
||||
self.entities.push(entity_id);
|
||||
self.updated_at = current_timestamp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从原型中移除实体
|
||||
*/
|
||||
pub fn remove_entity(&mut self, entity_id: u32) -> bool {
|
||||
if let Some(pos) = self.entities.iter().position(|&id| id == entity_id) {
|
||||
self.entities.remove(pos);
|
||||
self.updated_at = current_timestamp();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查原型是否包含指定组件类型
|
||||
*/
|
||||
pub fn contains_component(&self, component_type: ComponentType) -> bool {
|
||||
self.component_types.contains(&component_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查原型是否包含所有指定的组件类型
|
||||
*/
|
||||
pub fn contains_all_components(&self, component_types: &[ComponentType]) -> bool {
|
||||
component_types.iter().all(|t| self.contains_component(*t))
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查原型是否包含任意一个指定的组件类型
|
||||
*/
|
||||
pub fn contains_any_component(&self, component_types: &[ComponentType]) -> bool {
|
||||
component_types.iter().any(|t| self.contains_component(*t))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体数量
|
||||
*/
|
||||
pub fn entity_count(&self) -> usize {
|
||||
self.entities.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查原型是否为空
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entities.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 原型查询结果
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct ArchetypeQueryResult {
|
||||
/// 匹配的原型列表
|
||||
pub archetypes: Vec<Archetype>,
|
||||
/// 所有匹配实体的总数
|
||||
pub total_entities: usize,
|
||||
/// 查询执行时间(毫秒)
|
||||
pub execution_time: f64,
|
||||
/// 是否使用了缓存
|
||||
pub from_cache: bool,
|
||||
}
|
||||
|
||||
/**
|
||||
* 原型查询统计信息
|
||||
*/
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ArchetypeSystemStats {
|
||||
/// 总原型数量
|
||||
pub total_archetypes: usize,
|
||||
/// 总实体数量
|
||||
pub total_entities: usize,
|
||||
/// 平均每个原型的实体数量
|
||||
pub average_entities_per_archetype: f64,
|
||||
/// 查询次数
|
||||
pub total_queries: u32,
|
||||
/// 缓存命中次数
|
||||
pub cache_hits: u32,
|
||||
/// 缓存命中率
|
||||
pub cache_hit_rate: f32,
|
||||
/// 内存使用量(估算)
|
||||
pub memory_usage_bytes: usize,
|
||||
}
|
||||
|
||||
/**
|
||||
* 原型系统
|
||||
*
|
||||
* 根据实体的组件组合将实体分组到不同的原型中,提供高效的查询性能。
|
||||
* 这是现代ECS的核心优化技术之一。
|
||||
*/
|
||||
pub struct ArchetypeSystem {
|
||||
/// 所有原型的映射表(ID -> 原型)
|
||||
archetypes: FxHashMap<ArchetypeId, Archetype>,
|
||||
|
||||
/// 实体到原型的映射
|
||||
entity_to_archetype: FxHashMap<u32, ArchetypeId>,
|
||||
|
||||
/// 组件类型到原型集合的映射(用于快速查找)
|
||||
component_to_archetypes: FxHashMap<ComponentType, HashSet<ArchetypeId>>,
|
||||
|
||||
/// 查询缓存
|
||||
query_cache: FxHashMap<String, CachedQueryResult>,
|
||||
|
||||
/// 缓存配置
|
||||
cache_timeout_ms: u64,
|
||||
max_cache_size: usize,
|
||||
|
||||
/// 统计信息
|
||||
stats: ArchetypeSystemStats,
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存查询结果
|
||||
*/
|
||||
struct CachedQueryResult {
|
||||
result: ArchetypeQueryResult,
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
impl ArchetypeSystem {
|
||||
/**
|
||||
* 创建新的原型系统
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
archetypes: FxHashMap::default(),
|
||||
entity_to_archetype: FxHashMap::default(),
|
||||
component_to_archetypes: FxHashMap::default(),
|
||||
query_cache: FxHashMap::default(),
|
||||
cache_timeout_ms: 5000, // 5秒缓存超时
|
||||
max_cache_size: 100,
|
||||
stats: ArchetypeSystemStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存配置
|
||||
*/
|
||||
pub fn configure_cache(&mut self, timeout_ms: u64, max_size: usize) {
|
||||
self.cache_timeout_ms = timeout_ms;
|
||||
self.max_cache_size = max_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体到原型系统
|
||||
*/
|
||||
pub fn add_entity(&mut self, entity_id: u32, component_types: Vec<ComponentType>) {
|
||||
if component_types.is_empty() {
|
||||
return; // 不处理没有组件的实体
|
||||
}
|
||||
|
||||
let archetype_id = Archetype::generate_id(&component_types);
|
||||
|
||||
// 如果原型不存在,创建新原型
|
||||
if !self.archetypes.contains_key(&archetype_id) {
|
||||
let archetype = Archetype::new(component_types.clone());
|
||||
self.create_archetype(archetype);
|
||||
}
|
||||
|
||||
// 添加实体到原型
|
||||
if let Some(archetype) = self.archetypes.get_mut(&archetype_id) {
|
||||
archetype.add_entity(entity_id);
|
||||
}
|
||||
|
||||
// 更新实体到原型的映射
|
||||
if let Some(old_archetype_id) = self.entity_to_archetype.get(&entity_id).cloned() {
|
||||
// 如果实体已存在于其他原型中,先移除
|
||||
if old_archetype_id != archetype_id {
|
||||
self.remove_entity_from_archetype(entity_id, &old_archetype_id);
|
||||
}
|
||||
}
|
||||
|
||||
self.entity_to_archetype.insert(entity_id, archetype_id);
|
||||
|
||||
// 清空查询缓存(因为原型变化了)
|
||||
self.invalidate_query_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从原型系统中移除实体
|
||||
*/
|
||||
pub fn remove_entity(&mut self, entity_id: u32) -> bool {
|
||||
if let Some(archetype_id) = self.entity_to_archetype.remove(&entity_id) {
|
||||
let success = self.remove_entity_from_archetype(entity_id, &archetype_id);
|
||||
|
||||
if success {
|
||||
self.invalidate_query_cache();
|
||||
|
||||
// 如果原型变空了,可以考虑清理(但这里保留空原型以提高性能)
|
||||
// 实际生产中可能需要定期清理空原型
|
||||
}
|
||||
|
||||
success
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体组件发生变化时更新原型
|
||||
*/
|
||||
pub fn update_entity_components(&mut self, entity_id: u32, new_component_types: Vec<ComponentType>) {
|
||||
// 先移除实体,再重新添加
|
||||
self.remove_entity(entity_id);
|
||||
if !new_component_types.is_empty() {
|
||||
self.add_entity(entity_id, new_component_types);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询包含所有指定组件的原型
|
||||
*/
|
||||
pub fn query_all_components(&mut self, component_types: &[ComponentType]) -> ArchetypeQueryResult {
|
||||
let cache_key = format!("all:{:?}", component_types);
|
||||
|
||||
// 检查缓存
|
||||
if let Some(cached) = self.get_cached_result(&cache_key) {
|
||||
self.stats.cache_hits += 1;
|
||||
self.stats.total_queries += 1;
|
||||
return cached;
|
||||
}
|
||||
|
||||
let start_time = current_timestamp_f64();
|
||||
let mut matching_archetypes = Vec::new();
|
||||
let mut total_entities = 0;
|
||||
|
||||
for archetype in self.archetypes.values() {
|
||||
if archetype.contains_all_components(component_types) {
|
||||
total_entities += archetype.entity_count();
|
||||
matching_archetypes.push(archetype.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let execution_time = current_timestamp_f64() - start_time;
|
||||
let result = ArchetypeQueryResult {
|
||||
archetypes: matching_archetypes,
|
||||
total_entities,
|
||||
execution_time,
|
||||
from_cache: false,
|
||||
};
|
||||
|
||||
// 缓存结果
|
||||
self.cache_query_result(cache_key, &result);
|
||||
self.stats.total_queries += 1;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询包含任意指定组件的原型
|
||||
*/
|
||||
pub fn query_any_component(&mut self, component_types: &[ComponentType]) -> ArchetypeQueryResult {
|
||||
let cache_key = format!("any:{:?}", component_types);
|
||||
|
||||
if let Some(cached) = self.get_cached_result(&cache_key) {
|
||||
self.stats.cache_hits += 1;
|
||||
self.stats.total_queries += 1;
|
||||
return cached;
|
||||
}
|
||||
|
||||
let start_time = current_timestamp_f64();
|
||||
let mut matching_archetypes = Vec::new();
|
||||
let mut total_entities = 0;
|
||||
|
||||
for archetype in self.archetypes.values() {
|
||||
if archetype.contains_any_component(component_types) {
|
||||
total_entities += archetype.entity_count();
|
||||
matching_archetypes.push(archetype.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let execution_time = current_timestamp_f64() - start_time;
|
||||
let result = ArchetypeQueryResult {
|
||||
archetypes: matching_archetypes,
|
||||
total_entities,
|
||||
execution_time,
|
||||
from_cache: false,
|
||||
};
|
||||
|
||||
self.cache_query_result(cache_key, &result);
|
||||
self.stats.total_queries += 1;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据组件掩码查询原型
|
||||
*/
|
||||
pub fn query_by_mask(&mut self, component_mask: u64) -> ArchetypeQueryResult {
|
||||
let cache_key = format!("mask:{}", component_mask);
|
||||
|
||||
if let Some(cached) = self.get_cached_result(&cache_key) {
|
||||
self.stats.cache_hits += 1;
|
||||
self.stats.total_queries += 1;
|
||||
return cached;
|
||||
}
|
||||
|
||||
let start_time = current_timestamp_f64();
|
||||
let mut matching_archetypes = Vec::new();
|
||||
let mut total_entities = 0;
|
||||
|
||||
for archetype in self.archetypes.values() {
|
||||
if (archetype.component_mask & component_mask) == component_mask {
|
||||
total_entities += archetype.entity_count();
|
||||
matching_archetypes.push(archetype.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let execution_time = current_timestamp_f64() - start_time;
|
||||
let result = ArchetypeQueryResult {
|
||||
archetypes: matching_archetypes,
|
||||
total_entities,
|
||||
execution_time,
|
||||
from_cache: false,
|
||||
};
|
||||
|
||||
self.cache_query_result(cache_key, &result);
|
||||
self.stats.total_queries += 1;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体所属的原型
|
||||
*/
|
||||
pub fn get_entity_archetype(&self, entity_id: u32) -> Option<&Archetype> {
|
||||
if let Some(archetype_id) = self.entity_to_archetype.get(&entity_id) {
|
||||
self.archetypes.get(archetype_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有原型的列表
|
||||
*/
|
||||
pub fn get_all_archetypes(&self) -> Vec<&Archetype> {
|
||||
self.archetypes.values().collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> ArchetypeSystemStats {
|
||||
let total_archetypes = self.archetypes.len();
|
||||
let total_entities = self.archetypes.values()
|
||||
.map(|a| a.entity_count())
|
||||
.sum();
|
||||
|
||||
let average_entities = if total_archetypes > 0 {
|
||||
total_entities as f64 / total_archetypes as f64
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let cache_hit_rate = if self.stats.total_queries > 0 {
|
||||
(self.stats.cache_hits as f32 / self.stats.total_queries as f32) * 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let memory_usage = self.estimate_memory_usage();
|
||||
|
||||
ArchetypeSystemStats {
|
||||
total_archetypes,
|
||||
total_entities,
|
||||
average_entities_per_archetype: average_entities,
|
||||
total_queries: self.stats.total_queries,
|
||||
cache_hits: self.stats.cache_hits,
|
||||
cache_hit_rate,
|
||||
memory_usage_bytes: memory_usage,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有数据
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.archetypes.clear();
|
||||
self.entity_to_archetype.clear();
|
||||
self.component_to_archetypes.clear();
|
||||
self.query_cache.clear();
|
||||
self.stats = ArchetypeSystemStats::default();
|
||||
}
|
||||
|
||||
// ========== 私有方法 ==========
|
||||
|
||||
/**
|
||||
* 创建新原型并建立索引
|
||||
*/
|
||||
fn create_archetype(&mut self, archetype: Archetype) {
|
||||
let archetype_id = archetype.id.clone();
|
||||
|
||||
// 为每个组件类型建立索引
|
||||
for &component_type in &archetype.component_types {
|
||||
self.component_to_archetypes
|
||||
.entry(component_type)
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(archetype_id.clone());
|
||||
}
|
||||
|
||||
self.archetypes.insert(archetype_id, archetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定原型中移除实体
|
||||
*/
|
||||
fn remove_entity_from_archetype(&mut self, entity_id: u32, archetype_id: &str) -> bool {
|
||||
if let Some(archetype) = self.archetypes.get_mut(archetype_id) {
|
||||
archetype.remove_entity(entity_id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的查询结果
|
||||
*/
|
||||
fn get_cached_result(&self, cache_key: &str) -> Option<ArchetypeQueryResult> {
|
||||
if let Some(cached) = self.query_cache.get(cache_key) {
|
||||
let now = current_timestamp();
|
||||
if now - cached.timestamp < self.cache_timeout_ms {
|
||||
return Some(ArchetypeQueryResult {
|
||||
archetypes: cached.result.archetypes.clone(),
|
||||
total_entities: cached.result.total_entities,
|
||||
execution_time: cached.result.execution_time,
|
||||
from_cache: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存查询结果
|
||||
*/
|
||||
fn cache_query_result(&mut self, cache_key: String, result: &ArchetypeQueryResult) {
|
||||
// 如果缓存已满,清理旧条目
|
||||
if self.query_cache.len() >= self.max_cache_size {
|
||||
self.cleanup_old_cache_entries();
|
||||
}
|
||||
|
||||
let cached_result = CachedQueryResult {
|
||||
result: ArchetypeQueryResult {
|
||||
archetypes: result.archetypes.clone(),
|
||||
total_entities: result.total_entities,
|
||||
execution_time: result.execution_time,
|
||||
from_cache: false,
|
||||
},
|
||||
timestamp: current_timestamp(),
|
||||
};
|
||||
|
||||
self.query_cache.insert(cache_key, cached_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期的缓存条目
|
||||
*/
|
||||
fn cleanup_old_cache_entries(&mut self) {
|
||||
let now = current_timestamp();
|
||||
let timeout = self.cache_timeout_ms;
|
||||
|
||||
self.query_cache.retain(|_, cached| {
|
||||
now - cached.timestamp < timeout
|
||||
});
|
||||
|
||||
// 如果清理后仍然太多,移除最旧的一半
|
||||
if self.query_cache.len() >= self.max_cache_size {
|
||||
let keys_to_remove: Vec<_> = self.query_cache.keys()
|
||||
.take(self.query_cache.len() / 2)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
for key in keys_to_remove {
|
||||
self.query_cache.remove(&key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使查询缓存失效
|
||||
*/
|
||||
fn invalidate_query_cache(&mut self) {
|
||||
self.query_cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 估算内存使用量
|
||||
*/
|
||||
fn estimate_memory_usage(&self) -> usize {
|
||||
let archetypes_size = self.archetypes.len() * std::mem::size_of::<Archetype>();
|
||||
let entity_mapping_size = self.entity_to_archetype.len() * (std::mem::size_of::<u32>() + std::mem::size_of::<String>());
|
||||
let component_mapping_size = self.component_to_archetypes.len() * std::mem::size_of::<(ComponentType, HashSet<ArchetypeId>)>();
|
||||
let cache_size = self.query_cache.len() * std::mem::size_of::<CachedQueryResult>();
|
||||
|
||||
archetypes_size + entity_mapping_size + component_mapping_size + cache_size
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ArchetypeSystem {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 辅助函数 ==========
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(毫秒)
|
||||
*/
|
||||
fn current_timestamp() -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(浮点毫秒,用于精确计时)
|
||||
*/
|
||||
fn current_timestamp_f64() -> f64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs_f64() * 1000.0
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算字符串哈希
|
||||
*/
|
||||
fn hash_string(s: &str) -> u64 {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
s.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算组件类型哈希
|
||||
*/
|
||||
fn hash_component_type(component_type: ComponentType) -> u64 {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
component_type.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::TypeId;
|
||||
|
||||
// 测试用的示例组件
|
||||
struct TestComponentA;
|
||||
struct TestComponentB;
|
||||
struct TestComponentC;
|
||||
|
||||
#[test]
|
||||
fn test_archetype_creation() {
|
||||
let component_types = vec![
|
||||
TypeId::of::<TestComponentA>(),
|
||||
TypeId::of::<TestComponentB>(),
|
||||
];
|
||||
|
||||
let archetype = Archetype::new(component_types.clone());
|
||||
assert_eq!(archetype.component_types.len(), 2);
|
||||
assert_eq!(archetype.entity_count(), 0);
|
||||
assert!(!archetype.id.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_archetype_system_basic() {
|
||||
let mut system = ArchetypeSystem::new();
|
||||
|
||||
let component_types_a = vec![
|
||||
TypeId::of::<TestComponentA>(),
|
||||
TypeId::of::<TestComponentB>(),
|
||||
];
|
||||
|
||||
let component_types_b = vec![
|
||||
TypeId::of::<TestComponentA>(),
|
||||
TypeId::of::<TestComponentC>(),
|
||||
];
|
||||
|
||||
// 添加实体
|
||||
system.add_entity(1, component_types_a.clone());
|
||||
system.add_entity(2, component_types_a.clone());
|
||||
system.add_entity(3, component_types_b);
|
||||
|
||||
let stats = system.get_stats();
|
||||
assert_eq!(stats.total_archetypes, 2);
|
||||
assert_eq!(stats.total_entities, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_archetype_queries() {
|
||||
let mut system = ArchetypeSystem::new();
|
||||
|
||||
let component_types_ab = vec![
|
||||
TypeId::of::<TestComponentA>(),
|
||||
TypeId::of::<TestComponentB>(),
|
||||
];
|
||||
|
||||
let component_types_ac = vec![
|
||||
TypeId::of::<TestComponentA>(),
|
||||
TypeId::of::<TestComponentC>(),
|
||||
];
|
||||
|
||||
system.add_entity(1, component_types_ab);
|
||||
system.add_entity(2, component_types_ac);
|
||||
|
||||
// 查询包含ComponentA的原型
|
||||
let result = system.query_all_components(&[TypeId::of::<TestComponentA>()]);
|
||||
assert_eq!(result.archetypes.len(), 2);
|
||||
assert_eq!(result.total_entities, 2);
|
||||
|
||||
// 查询包含ComponentB的原型
|
||||
let result = system.query_all_components(&[TypeId::of::<TestComponentB>()]);
|
||||
assert_eq!(result.archetypes.len(), 1);
|
||||
assert_eq!(result.total_entities, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entity_updates() {
|
||||
let mut system = ArchetypeSystem::new();
|
||||
|
||||
let initial_components = vec![TypeId::of::<TestComponentA>()];
|
||||
system.add_entity(1, initial_components);
|
||||
|
||||
assert_eq!(system.get_stats().total_archetypes, 1);
|
||||
|
||||
// 更新实体组件
|
||||
let new_components = vec![
|
||||
TypeId::of::<TestComponentA>(),
|
||||
TypeId::of::<TestComponentB>(),
|
||||
];
|
||||
system.update_entity_components(1, new_components);
|
||||
|
||||
// 应该创建新的原型
|
||||
assert_eq!(system.get_stats().total_archetypes, 2);
|
||||
assert_eq!(system.get_stats().total_entities, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_functionality() {
|
||||
let mut system = ArchetypeSystem::new();
|
||||
system.configure_cache(1000, 10); // 1秒缓存,最多10条
|
||||
|
||||
let component_types = vec![TypeId::of::<TestComponentA>()];
|
||||
system.add_entity(1, component_types);
|
||||
|
||||
// 第一次查询
|
||||
let result1 = system.query_all_components(&[TypeId::of::<TestComponentA>()]);
|
||||
assert!(!result1.from_cache);
|
||||
|
||||
// 第二次查询应该从缓存获取
|
||||
let result2 = system.query_all_components(&[TypeId::of::<TestComponentA>()]);
|
||||
assert!(result2.from_cache);
|
||||
|
||||
let stats = system.get_stats();
|
||||
assert_eq!(stats.cache_hits, 1);
|
||||
assert_eq!(stats.total_queries, 2);
|
||||
}
|
||||
}
|
||||
376
packages/core-rust/src/core/component.rs
Normal file
376
packages/core-rust/src/core/component.rs
Normal file
@@ -0,0 +1,376 @@
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
/**
|
||||
* 组件ID生成器
|
||||
* 全局静态变量,为每个组件实例分配唯一ID
|
||||
*/
|
||||
static COMPONENT_ID_GENERATOR: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
|
||||
/**
|
||||
* 组件注册表
|
||||
* 管理组件类型的位掩码分配
|
||||
*/
|
||||
pub struct ComponentRegistry {
|
||||
component_types: FxHashMap<TypeId, u32>,
|
||||
component_names: FxHashMap<String, TypeId>,
|
||||
component_name_to_id: FxHashMap<String, u32>,
|
||||
next_bit_index: u32,
|
||||
max_components: u32,
|
||||
}
|
||||
|
||||
impl ComponentRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
component_types: FxHashMap::default(),
|
||||
component_names: FxHashMap::default(),
|
||||
component_name_to_id: FxHashMap::default(),
|
||||
next_bit_index: 0,
|
||||
max_components: 64,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册组件类型并分配位掩码
|
||||
* @param type_id 组件类型ID
|
||||
* @param name 组件名称
|
||||
* @returns 分配的位索引
|
||||
*/
|
||||
pub fn register(&mut self, type_id: TypeId, name: String) -> Result<u32, String> {
|
||||
if let Some(&existing_index) = self.component_types.get(&type_id) {
|
||||
return Ok(existing_index);
|
||||
}
|
||||
|
||||
if self.next_bit_index >= self.max_components {
|
||||
return Err(format!(
|
||||
"Maximum number of component types ({}) exceeded",
|
||||
self.max_components
|
||||
));
|
||||
}
|
||||
|
||||
let bit_index = self.next_bit_index;
|
||||
self.next_bit_index += 1;
|
||||
|
||||
self.component_types.insert(type_id, bit_index);
|
||||
self.component_names.insert(name.clone(), type_id);
|
||||
self.component_name_to_id.insert(name, bit_index);
|
||||
|
||||
Ok(bit_index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件类型的位掩码
|
||||
* @param type_id 组件类型ID
|
||||
* @returns 位掩码
|
||||
*/
|
||||
pub fn get_bit_mask(&self, type_id: &TypeId) -> Option<u64> {
|
||||
self.component_types.get(type_id).map(|&bit_index| 1u64 << bit_index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件类型的位索引
|
||||
* @param type_id 组件类型ID
|
||||
* @returns 位索引
|
||||
*/
|
||||
pub fn get_bit_index(&self, type_id: &TypeId) -> Option<u32> {
|
||||
self.component_types.get(type_id).copied()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查组件类型是否已注册
|
||||
* @param type_id 组件类型ID
|
||||
* @returns 是否已注册
|
||||
*/
|
||||
pub fn is_registered(&self, type_id: &TypeId) -> bool {
|
||||
self.component_types.contains_key(type_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过名称获取组件类型ID
|
||||
* @param name 组件名称
|
||||
* @returns 组件类型ID
|
||||
*/
|
||||
pub fn get_component_id(&self, name: &str) -> Option<u32> {
|
||||
self.component_name_to_id.get(name).copied()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建组件掩码
|
||||
* @param component_names 组件名称数组
|
||||
* @returns 组合掩码
|
||||
*/
|
||||
pub fn create_component_mask(&self, component_names: &[String]) -> u64 {
|
||||
let mut mask = 0u64;
|
||||
for name in component_names {
|
||||
if let Some(&component_id) = self.component_name_to_id.get(name) {
|
||||
mask |= 1u64 << component_id;
|
||||
}
|
||||
}
|
||||
mask
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置注册表
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.component_types.clear();
|
||||
self.component_names.clear();
|
||||
self.component_name_to_id.clear();
|
||||
self.next_bit_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏组件基础trait
|
||||
*
|
||||
* ECS架构中的组件(Component),用于实现具体的游戏功能。
|
||||
* 组件包含数据和行为,可以被添加到实体上以扩展实体的功能。
|
||||
*/
|
||||
pub trait Component: Send + Sync where Self: 'static {
|
||||
/**
|
||||
* 获取组件的唯一标识符
|
||||
* 在整个游戏生命周期中唯一的数字ID
|
||||
*/
|
||||
fn id(&self) -> u32;
|
||||
|
||||
/**
|
||||
* 获取组件启用状态
|
||||
* 组件的实际启用状态取决于自身状态和所属实体的状态
|
||||
*/
|
||||
fn enabled(&self) -> bool {
|
||||
true // 默认启用
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置组件启用状态
|
||||
* 当状态改变时会触发相应的生命周期回调
|
||||
*/
|
||||
fn set_enabled(&mut self, enabled: bool);
|
||||
|
||||
/**
|
||||
* 获取更新顺序
|
||||
* 决定组件在更新循环中的执行顺序
|
||||
*/
|
||||
fn update_order(&self) -> i32 {
|
||||
0 // 默认更新顺序
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置更新顺序
|
||||
*/
|
||||
fn set_update_order(&mut self, order: i32);
|
||||
|
||||
/**
|
||||
* 组件添加到实体时的回调
|
||||
* 当组件被添加到实体时调用,可以在此方法中进行初始化操作
|
||||
*/
|
||||
fn on_added_to_entity(&mut self) {}
|
||||
|
||||
/**
|
||||
* 组件从实体移除时的回调
|
||||
* 当组件从实体中移除时调用,可以在此方法中进行清理操作
|
||||
*/
|
||||
fn on_removed_from_entity(&mut self) {}
|
||||
|
||||
/**
|
||||
* 组件启用时的回调
|
||||
* 当组件被启用时调用
|
||||
*/
|
||||
fn on_enabled(&mut self) {}
|
||||
|
||||
/**
|
||||
* 组件禁用时的回调
|
||||
* 当组件被禁用时调用
|
||||
*/
|
||||
fn on_disabled(&mut self) {}
|
||||
|
||||
/**
|
||||
* 实体激活状态改变时的回调
|
||||
* 当所属实体的激活状态改变时调用
|
||||
*/
|
||||
fn on_active_changed(&mut self) {}
|
||||
|
||||
/**
|
||||
* 更新组件
|
||||
* 每帧调用,用于更新组件的逻辑
|
||||
* 子类应该重写此方法来实现具体的更新逻辑
|
||||
*/
|
||||
fn update(&mut self) {}
|
||||
|
||||
// ========== Any trait 方法 ==========
|
||||
|
||||
/**
|
||||
* 获取组件作为Any引用,用于类型转换
|
||||
*/
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/**
|
||||
* 获取组件作为可变Any引用,用于类型转换
|
||||
*/
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/**
|
||||
* 克隆组件到Box中
|
||||
*/
|
||||
fn clone_box(&self) -> Box<dyn Component>;
|
||||
|
||||
/**
|
||||
* 获取组件的TypeId
|
||||
*/
|
||||
fn type_id(&self) -> TypeId {
|
||||
TypeId::of::<Self>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件类型名称(用于调试)
|
||||
*/
|
||||
fn type_name(&self) -> &'static str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为Box<dyn Component>实现Clone
|
||||
*/
|
||||
impl Clone for Box<dyn Component> {
|
||||
fn clone(&self) -> Box<dyn Component> {
|
||||
self.clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础组件实现
|
||||
* 提供默认的组件行为,具体组件可以继承此结构体
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BaseComponent {
|
||||
/// 组件唯一标识符
|
||||
id: u32,
|
||||
/// 组件启用状态
|
||||
enabled: bool,
|
||||
/// 更新顺序
|
||||
update_order: i32,
|
||||
}
|
||||
|
||||
impl BaseComponent {
|
||||
/**
|
||||
* 创建新的基础组件
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
id: COMPONENT_ID_GENERATOR.fetch_add(1, Ordering::SeqCst),
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成下一个组件ID
|
||||
*/
|
||||
pub fn next_component_id() -> u32 {
|
||||
COMPONENT_ID_GENERATOR.fetch_add(1, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置组件ID
|
||||
*/
|
||||
pub fn set_id(&mut self, id: u32) {
|
||||
self.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BaseComponent {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for BaseComponent {
|
||||
fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
if self.enabled != enabled {
|
||||
self.enabled = enabled;
|
||||
if enabled {
|
||||
self.on_enabled();
|
||||
} else {
|
||||
self.on_disabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.update_order = order;
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn Component> {
|
||||
Box::new(BaseComponent {
|
||||
id: BaseComponent::next_component_id(), // 新的克隆应该有新的ID
|
||||
enabled: self.enabled,
|
||||
update_order: self.update_order,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件宏,用于简化自定义组件的实现
|
||||
*/
|
||||
#[macro_export]
|
||||
macro_rules! impl_component {
|
||||
($component_type:ty) => {
|
||||
impl Component for $component_type {
|
||||
fn id(&self) -> u32 {
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
self.base.enabled()
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.base.set_enabled(enabled)
|
||||
}
|
||||
|
||||
fn update_order(&self) -> i32 {
|
||||
self.base.update_order()
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.base.set_update_order(order)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn Component> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
352
packages/core-rust/src/core/component_builder.rs
Normal file
352
packages/core-rust/src/core/component_builder.rs
Normal file
@@ -0,0 +1,352 @@
|
||||
use std::marker::PhantomData;
|
||||
use crate::core::{Component, BaseComponent};
|
||||
|
||||
/**
|
||||
* 组件构建器
|
||||
* 提供流式API创建和配置组件
|
||||
*/
|
||||
pub struct ComponentBuilder<T: Component> {
|
||||
component: T,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Component> ComponentBuilder<T> {
|
||||
/**
|
||||
* 创建组件构建器
|
||||
*/
|
||||
pub fn new(component: T) -> Self {
|
||||
Self {
|
||||
component,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置组件启用状态
|
||||
*/
|
||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||
self.component.set_enabled(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性设置启用状态
|
||||
*/
|
||||
pub fn enabled_if(mut self, condition: bool, enabled: bool) -> Self {
|
||||
if condition {
|
||||
self.component.set_enabled(enabled);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置函数设置组件
|
||||
*/
|
||||
pub fn configure<F>(mut self, configurator: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut T),
|
||||
{
|
||||
configurator(&mut self.component);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性配置组件
|
||||
*/
|
||||
pub fn configure_if<F>(mut self, condition: bool, configurator: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut T),
|
||||
{
|
||||
if condition {
|
||||
configurator(&mut self.component);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建并返回组件
|
||||
*/
|
||||
pub fn build(self) -> T {
|
||||
self.component
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证组件配置并构建
|
||||
*/
|
||||
pub fn validate_and_build<F>(self, validator: F) -> Result<T, String>
|
||||
where
|
||||
F: FnOnce(&T) -> Result<(), String>,
|
||||
{
|
||||
match validator(&self.component) {
|
||||
Ok(()) => Ok(self.component),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础组件构建器
|
||||
* 为BaseComponent提供特化的构建器实现
|
||||
*/
|
||||
pub struct BaseComponentBuilder {
|
||||
component: BaseComponent,
|
||||
}
|
||||
|
||||
impl BaseComponentBuilder {
|
||||
/**
|
||||
* 创建基础组件构建器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
component: BaseComponent::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置组件启用状态
|
||||
*/
|
||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||
self.component.set_enabled(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置组件ID
|
||||
*/
|
||||
pub fn with_id(mut self, id: u32) -> Self {
|
||||
self.component.set_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性设置启用状态
|
||||
*/
|
||||
pub fn enabled_if(mut self, condition: bool, enabled: bool) -> Self {
|
||||
if condition {
|
||||
self.component.set_enabled(enabled);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置函数设置组件
|
||||
*/
|
||||
pub fn configure<F>(mut self, configurator: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut BaseComponent),
|
||||
{
|
||||
configurator(&mut self.component);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建并返回组件
|
||||
*/
|
||||
pub fn build(self) -> BaseComponent {
|
||||
self.component
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件构建器工厂
|
||||
* 提供创建各种组件构建器的便捷方法
|
||||
*/
|
||||
pub struct ComponentBuilderFactory;
|
||||
|
||||
impl ComponentBuilderFactory {
|
||||
/**
|
||||
* 创建基础组件构建器
|
||||
*/
|
||||
pub fn base_component() -> BaseComponentBuilder {
|
||||
BaseComponentBuilder::new()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建通用组件构建器
|
||||
*/
|
||||
pub fn component<T: Component>(component: T) -> ComponentBuilder<T> {
|
||||
ComponentBuilder::new(component)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建启用的基础组件
|
||||
*/
|
||||
pub fn enabled_base_component() -> BaseComponentBuilder {
|
||||
BaseComponentBuilder::new().enabled(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建禁用的基础组件
|
||||
*/
|
||||
pub fn disabled_base_component() -> BaseComponentBuilder {
|
||||
BaseComponentBuilder::new().enabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件构建器统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ComponentBuilderStats {
|
||||
pub total_components_built: u64,
|
||||
pub base_components_built: u64,
|
||||
pub custom_components_built: u64,
|
||||
pub validation_failures: u64,
|
||||
}
|
||||
|
||||
impl ComponentBuilderStats {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_components_built: 0,
|
||||
base_components_built: 0,
|
||||
custom_components_built: 0,
|
||||
validation_failures: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置统计信息
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.total_components_built = 0;
|
||||
self.base_components_built = 0;
|
||||
self.custom_components_built = 0;
|
||||
self.validation_failures = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录基础组件构建
|
||||
*/
|
||||
pub fn record_base_component_built(&mut self) {
|
||||
self.total_components_built += 1;
|
||||
self.base_components_built += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录自定义组件构建
|
||||
*/
|
||||
pub fn record_custom_component_built(&mut self) {
|
||||
self.total_components_built += 1;
|
||||
self.custom_components_built += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录验证失败
|
||||
*/
|
||||
pub fn record_validation_failure(&mut self) {
|
||||
self.validation_failures += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取构建成功率
|
||||
*/
|
||||
pub fn success_rate(&self) -> f64 {
|
||||
if self.total_components_built + self.validation_failures == 0 {
|
||||
return 1.0;
|
||||
}
|
||||
self.total_components_built as f64 /
|
||||
(self.total_components_built + self.validation_failures) as f64
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_base_component_builder() {
|
||||
let component = BaseComponentBuilder::new()
|
||||
.enabled(true)
|
||||
.with_id(123)
|
||||
.build();
|
||||
|
||||
assert!(component.enabled());
|
||||
assert_eq!(component.id(), 123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base_component_builder_conditional() {
|
||||
let component = BaseComponentBuilder::new()
|
||||
.enabled_if(true, true)
|
||||
.enabled_if(false, false)
|
||||
.build();
|
||||
|
||||
assert!(component.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base_component_builder_configure() {
|
||||
let component = BaseComponentBuilder::new()
|
||||
.configure(|comp| {
|
||||
comp.set_enabled(true);
|
||||
comp.set_id(456);
|
||||
})
|
||||
.build();
|
||||
|
||||
assert!(component.enabled());
|
||||
assert_eq!(component.id(), 456);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_builder_factory() {
|
||||
let base_comp = ComponentBuilderFactory::base_component().build();
|
||||
assert!(!base_comp.enabled()); // 默认为禁用
|
||||
|
||||
let enabled_comp = ComponentBuilderFactory::enabled_base_component().build();
|
||||
assert!(enabled_comp.enabled());
|
||||
|
||||
let disabled_comp = ComponentBuilderFactory::disabled_base_component().build();
|
||||
assert!(!disabled_comp.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_builder_validation() {
|
||||
let component = BaseComponent::new();
|
||||
let builder = ComponentBuilder::new(component);
|
||||
|
||||
// 验证成功
|
||||
let result = builder.validate_and_build(|_| Ok(()));
|
||||
assert!(result.is_ok());
|
||||
|
||||
// 验证失败
|
||||
let component2 = BaseComponent::new();
|
||||
let builder2 = ComponentBuilder::new(component2);
|
||||
let result2 = builder2.validate_and_build(|_| Err("Invalid component".to_string()));
|
||||
assert!(result2.is_err());
|
||||
assert_eq!(result2.unwrap_err(), "Invalid component");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_builder_stats() {
|
||||
let mut stats = ComponentBuilderStats::new();
|
||||
|
||||
stats.record_base_component_built();
|
||||
stats.record_custom_component_built();
|
||||
stats.record_validation_failure();
|
||||
|
||||
assert_eq!(stats.total_components_built, 2);
|
||||
assert_eq!(stats.base_components_built, 1);
|
||||
assert_eq!(stats.custom_components_built, 1);
|
||||
assert_eq!(stats.validation_failures, 1);
|
||||
assert!((stats.success_rate() - 0.6666666666666666).abs() < 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_builder_stats_reset() {
|
||||
let mut stats = ComponentBuilderStats::new();
|
||||
|
||||
stats.record_base_component_built();
|
||||
stats.reset();
|
||||
|
||||
assert_eq!(stats.total_components_built, 0);
|
||||
assert_eq!(stats.base_components_built, 0);
|
||||
assert_eq!(stats.custom_components_built, 0);
|
||||
assert_eq!(stats.validation_failures, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_builder_stats_success_rate_empty() {
|
||||
let stats = ComponentBuilderStats::new();
|
||||
assert_eq!(stats.success_rate(), 1.0);
|
||||
}
|
||||
}
|
||||
638
packages/core-rust/src/core/entity.rs
Normal file
638
packages/core-rust/src/core/entity.rs
Normal file
@@ -0,0 +1,638 @@
|
||||
use crate::core::component::Component;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::any::TypeId;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// 将TypeId转换为u64的帮助函数
|
||||
fn type_id_to_u64(type_id: TypeId) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
type_id.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体比较器
|
||||
*
|
||||
* 用于比较两个实体的优先级,首先按更新顺序比较,然后按ID比较
|
||||
*/
|
||||
pub struct EntityComparer;
|
||||
|
||||
impl EntityComparer {
|
||||
/**
|
||||
* 比较两个实体
|
||||
*
|
||||
* @param self_entity - 第一个实体
|
||||
* @param other_entity - 第二个实体
|
||||
* @returns 比较结果,负数表示self优先级更高,正数表示other优先级更高,0表示相等
|
||||
*/
|
||||
pub fn compare(self_entity: &Entity, other_entity: &Entity) -> i32 {
|
||||
let mut compare = self_entity.update_order - other_entity.update_order;
|
||||
if compare == 0 {
|
||||
compare = self_entity.id as i32 - other_entity.id as i32;
|
||||
}
|
||||
compare
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏实体类
|
||||
*
|
||||
* ECS架构中的实体(Entity),作为组件的容器。
|
||||
* 实体本身不包含游戏逻辑,所有功能都通过组件来实现。
|
||||
* 支持父子关系,可以构建实体层次结构。
|
||||
*/
|
||||
#[derive(Clone)]
|
||||
pub struct Entity {
|
||||
/// 实体名称,用于标识和调试的友好名称
|
||||
pub name: String,
|
||||
|
||||
/// 实体唯一标识符,在场景中唯一的数字标识符
|
||||
pub id: u32,
|
||||
|
||||
/// 更新间隔,控制实体更新的频率,值越大更新越不频繁
|
||||
pub update_interval: u32,
|
||||
|
||||
/// 私有字段,通过getter/setter访问
|
||||
active: bool,
|
||||
enabled: bool,
|
||||
is_destroyed: bool,
|
||||
tag: u32,
|
||||
update_order: i32,
|
||||
|
||||
/// 父实体ID
|
||||
parent_id: Option<u32>,
|
||||
|
||||
/// 子实体ID集合
|
||||
children_ids: Vec<u32>,
|
||||
|
||||
/// 组件位掩码,用于快速查询实体拥有的组件类型
|
||||
component_mask: u64,
|
||||
|
||||
/// 组件实例存储 (TypeId -> 组件数据)
|
||||
components: FxHashMap<TypeId, Box<dyn Component>>,
|
||||
|
||||
/// 组件类型到索引的映射,用于快速定位组件在数组中的位置
|
||||
component_type_to_index: FxHashMap<TypeId, usize>,
|
||||
|
||||
/// 组件列表(用于保持插入顺序和索引访问)
|
||||
component_list: Vec<Option<Box<dyn Component>>>,
|
||||
}
|
||||
|
||||
|
||||
impl Entity {
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
pub fn new(id: u32) -> Self {
|
||||
Self {
|
||||
name: String::new(),
|
||||
id,
|
||||
update_interval: 1,
|
||||
active: true,
|
||||
enabled: true,
|
||||
is_destroyed: false,
|
||||
tag: 0,
|
||||
update_order: 0,
|
||||
parent_id: None,
|
||||
children_ids: Vec::new(),
|
||||
component_mask: 0,
|
||||
components: FxHashMap::default(),
|
||||
component_type_to_index: FxHashMap::default(),
|
||||
component_list: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数(带名称)
|
||||
*/
|
||||
pub fn new_with_name(name: String, id: u32) -> Self {
|
||||
Self {
|
||||
name,
|
||||
id,
|
||||
update_interval: 1,
|
||||
active: true,
|
||||
enabled: true,
|
||||
is_destroyed: false,
|
||||
tag: 0,
|
||||
update_order: 0,
|
||||
parent_id: None,
|
||||
children_ids: Vec::new(),
|
||||
component_mask: 0,
|
||||
components: FxHashMap::default(),
|
||||
component_type_to_index: FxHashMap::default(),
|
||||
component_list: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 属性访问器 ==========
|
||||
|
||||
/**
|
||||
* 获取实体ID
|
||||
*/
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体ID
|
||||
*/
|
||||
pub fn set_id(&mut self, id: u32) {
|
||||
self.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体名称
|
||||
*/
|
||||
pub fn name(&self) -> Option<String> {
|
||||
if self.name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.name.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体名称
|
||||
*/
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签集合(暂时返回单个标签作为集合)
|
||||
*/
|
||||
pub fn tags(&self) -> std::collections::HashSet<u32> {
|
||||
let mut tags = std::collections::HashSet::new();
|
||||
if self.tag != 0 {
|
||||
tags.insert(self.tag);
|
||||
}
|
||||
tags
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有指定标签
|
||||
*/
|
||||
pub fn has_tag(&self, tag: u32) -> bool {
|
||||
self.tag == tag
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加标签
|
||||
*/
|
||||
pub fn add_tag(&mut self, tag: u32) {
|
||||
self.tag = tag; // 简化版本,只支持单个标签
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除标签
|
||||
*/
|
||||
pub fn remove_tag(&mut self, tag: u32) {
|
||||
if self.tag == tag {
|
||||
self.tag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active(&self) -> bool {
|
||||
self.active
|
||||
}
|
||||
|
||||
pub fn set_active(&mut self, value: bool) {
|
||||
if self.active != value {
|
||||
self.active = value;
|
||||
self.on_active_changed();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
pub fn set_enabled(&mut self, value: bool) {
|
||||
self.enabled = value;
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> u32 {
|
||||
self.tag
|
||||
}
|
||||
|
||||
pub fn set_tag(&mut self, value: u32) {
|
||||
self.tag = value;
|
||||
}
|
||||
|
||||
pub fn update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
pub fn set_update_order(&mut self, value: i32) {
|
||||
self.update_order = value;
|
||||
}
|
||||
|
||||
pub fn is_destroyed(&self) -> bool {
|
||||
self.is_destroyed
|
||||
}
|
||||
|
||||
pub fn get_parent_id(&self) -> Option<u32> {
|
||||
self.parent_id
|
||||
}
|
||||
|
||||
pub fn child_count(&self) -> usize {
|
||||
self.children_ids.len()
|
||||
}
|
||||
|
||||
pub fn get_component_mask(&self) -> u64 {
|
||||
self.component_mask
|
||||
}
|
||||
|
||||
pub fn get_children_ids(&self) -> Vec<u32> {
|
||||
self.children_ids.clone()
|
||||
}
|
||||
|
||||
// ========== 内部访问方法 ==========
|
||||
|
||||
/**
|
||||
* 获取子实体ID的切片引用(内部使用)
|
||||
*/
|
||||
pub fn children_ids(&self) -> &[u32] {
|
||||
&self.children_ids
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父实体ID(内部使用)
|
||||
*/
|
||||
pub fn parent_id(&self) -> Option<u32> {
|
||||
self.parent_id
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置组件位掩码(内部使用)
|
||||
*/
|
||||
pub fn set_component_mask(&mut self, mask: u64) {
|
||||
self.component_mask = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试信息字符串
|
||||
*/
|
||||
pub fn get_debug_info(&self) -> String {
|
||||
format!(
|
||||
"{{\"name\":\"{}\",\"id\":{},\"enabled\":{},\"active\":{},\"destroyed\":{},\"component_count\":{},\"tag\":{},\"update_order\":{},\"child_count\":{}}}",
|
||||
self.name,
|
||||
self.id,
|
||||
self.enabled,
|
||||
self.active,
|
||||
self.is_destroyed,
|
||||
self.components.len(),
|
||||
self.tag,
|
||||
self.update_order,
|
||||
self.children_ids.len()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试信息结构体(内部使用)
|
||||
*/
|
||||
pub fn get_debug_info_struct(&self) -> EntityDebugInfo {
|
||||
EntityDebugInfo {
|
||||
name: self.name.clone(),
|
||||
id: self.id,
|
||||
enabled: self.enabled,
|
||||
active: self.active,
|
||||
destroyed: self.is_destroyed,
|
||||
component_count: self.components.len(),
|
||||
component_mask: format!("{:b}", self.component_mask),
|
||||
parent_id: self.parent_id,
|
||||
child_count: self.children_ids.len(),
|
||||
child_ids: self.children_ids.clone(),
|
||||
tag: self.tag,
|
||||
update_order: self.update_order,
|
||||
index_mapping_size: self.component_type_to_index.len(),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 组件管理 ==========
|
||||
|
||||
/**
|
||||
* 内部添加组件方法(不进行重复检查,用于初始化)
|
||||
*/
|
||||
fn add_component_internal<T: Component + 'static>(&mut self, component: T) -> &T {
|
||||
let type_id = TypeId::of::<T>();
|
||||
let boxed_component = Box::new(component);
|
||||
|
||||
// 添加到组件列表并建立索引映射
|
||||
let index = self.component_list.len();
|
||||
self.component_list.push(Some(boxed_component.clone_box()));
|
||||
self.component_type_to_index.insert(type_id, index);
|
||||
|
||||
// 添加到类型映射
|
||||
self.components.insert(type_id, boxed_component);
|
||||
|
||||
// 这里应该更新位掩码,但需要ComponentRegistry
|
||||
// 暂时使用简单的类型ID哈希作为掩码
|
||||
self.component_mask |= 1u64.wrapping_shl(type_id_to_u64(type_id) as u32 % 64);
|
||||
|
||||
// 返回引用(这里简化处理)
|
||||
self.components.get(&type_id).unwrap().as_any().downcast_ref::<T>().unwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组件到实体
|
||||
*/
|
||||
pub fn add_component<T: Component + 'static>(&mut self, component: T) -> Result<&T, String> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
// 检查是否已有此类型的组件
|
||||
if self.has_component::<T>() {
|
||||
return Err(format!("Entity {} already has component of type {:?}", self.name, type_id));
|
||||
}
|
||||
|
||||
// 使用内部方法添加组件
|
||||
Ok(self.add_component_internal(component))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类型的组件
|
||||
*/
|
||||
pub fn get_component<T: Component + 'static>(&self) -> Option<&T> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
// 首先检查位掩码,快速排除(简化版本)
|
||||
let type_mask = 1u64.wrapping_shl(type_id_to_u64(type_id) as u32 % 64);
|
||||
if (self.component_mask & type_mask) == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 从类型映射获取
|
||||
self.components.get(&type_id).and_then(|component| {
|
||||
component.as_any().downcast_ref::<T>()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类型的可变组件
|
||||
*/
|
||||
pub fn get_component_mut<T: Component + 'static>(&mut self) -> Option<&mut T> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
// 首先检查位掩码,快速排除
|
||||
let type_mask = 1u64.wrapping_shl(type_id_to_u64(type_id) as u32 % 64);
|
||||
if (self.component_mask & type_mask) == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 从类型映射获取可变引用
|
||||
self.components.get_mut(&type_id).and_then(|component| {
|
||||
component.as_any_mut().downcast_mut::<T>()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否有指定类型的组件
|
||||
*/
|
||||
pub fn has_component<T: Component + 'static>(&self) -> bool {
|
||||
let type_id = TypeId::of::<T>();
|
||||
let type_mask = 1u64.wrapping_shl(type_id_to_u64(type_id) as u32 % 64);
|
||||
(self.component_mask & type_mask) != 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建指定类型的组件
|
||||
*/
|
||||
pub fn get_or_create_component<T: Component + Default + 'static>(&mut self) -> &T {
|
||||
if self.has_component::<T>() {
|
||||
self.get_component::<T>().unwrap()
|
||||
} else {
|
||||
let component = T::default();
|
||||
self.add_component_internal(component)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定类型的组件
|
||||
*/
|
||||
pub fn remove_component<T: Component + 'static>(&mut self) -> Option<Box<dyn Component>> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
if let Some(component) = self.components.remove(&type_id) {
|
||||
// 更新位掩码
|
||||
let type_mask = 1u64.wrapping_shl(type_id_to_u64(type_id) as u32 % 64);
|
||||
self.component_mask &= !type_mask;
|
||||
|
||||
// 从索引映射中移除并重建索引
|
||||
if let Some(index) = self.component_type_to_index.remove(&type_id) {
|
||||
if index < self.component_list.len() {
|
||||
self.component_list[index] = None;
|
||||
}
|
||||
self.rebuild_component_index();
|
||||
}
|
||||
|
||||
Some(component)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有组件
|
||||
*/
|
||||
pub fn remove_all_components(&mut self) {
|
||||
self.component_type_to_index.clear();
|
||||
self.component_mask = 0;
|
||||
self.components.clear();
|
||||
self.component_list.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件数量
|
||||
*/
|
||||
pub fn component_count(&self) -> usize {
|
||||
self.components.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建组件索引映射
|
||||
*/
|
||||
fn rebuild_component_index(&mut self) {
|
||||
self.component_type_to_index.clear();
|
||||
|
||||
let mut new_list = Vec::new();
|
||||
for (_i, component_opt) in self.component_list.iter().enumerate() {
|
||||
if let Some(component) = component_opt {
|
||||
let type_id = component.type_id();
|
||||
self.component_type_to_index.insert(type_id, new_list.len());
|
||||
new_list.push(Some(component.clone_box()));
|
||||
}
|
||||
}
|
||||
self.component_list = new_list;
|
||||
}
|
||||
|
||||
// ========== 层次结构管理 ==========
|
||||
|
||||
/**
|
||||
* 添加子实体ID
|
||||
*/
|
||||
pub fn add_child_id(&mut self, child_id: u32) -> Result<(), String> {
|
||||
if child_id == self.id {
|
||||
return Err("Entity cannot be its own child".to_string());
|
||||
}
|
||||
|
||||
if self.children_ids.contains(&child_id) {
|
||||
return Ok(()); // 已经是子实体
|
||||
}
|
||||
|
||||
self.children_ids.push(child_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除子实体ID
|
||||
*/
|
||||
pub fn remove_child_id(&mut self, child_id: u32) -> bool {
|
||||
if let Some(pos) = self.children_ids.iter().position(|&id| id == child_id) {
|
||||
self.children_ids.remove(pos);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置父实体ID
|
||||
*/
|
||||
pub fn set_parent_id(&mut self, parent_id: Option<u32>) {
|
||||
self.parent_id = parent_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有子实体ID
|
||||
*/
|
||||
pub fn remove_all_children_ids(&mut self) {
|
||||
self.children_ids.clear();
|
||||
}
|
||||
|
||||
// ========== 生命周期方法 ==========
|
||||
|
||||
/**
|
||||
* 激活状态改变时的回调
|
||||
*/
|
||||
fn on_active_changed(&mut self) {
|
||||
// 通知所有组件激活状态改变
|
||||
for component in self.components.values_mut() {
|
||||
component.on_active_changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新实体
|
||||
*/
|
||||
pub fn update(&mut self) {
|
||||
if !self.active || self.is_destroyed {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新所有组件
|
||||
for component in self.components.values_mut() {
|
||||
if component.enabled() {
|
||||
component.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实体
|
||||
*/
|
||||
pub fn destroy(&mut self) {
|
||||
if self.is_destroyed {
|
||||
return;
|
||||
}
|
||||
|
||||
self.is_destroyed = true;
|
||||
|
||||
// 移除所有组件
|
||||
self.remove_all_components();
|
||||
|
||||
// 清空子实体ID(实际的子实体销毁由EntityManager处理)
|
||||
self.children_ids.clear();
|
||||
|
||||
// 清空父实体引用
|
||||
self.parent_id = None;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较实体
|
||||
*/
|
||||
pub fn compare_to(&self, other: &Entity) -> i32 {
|
||||
EntityComparer::compare(self, other)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的字符串表示
|
||||
*/
|
||||
pub fn to_string(&self) -> String {
|
||||
format!("Entity[{}:{}]", self.name, self.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的调试信息结构体
|
||||
*/
|
||||
pub fn get_debug_info_detailed(&self) -> EntityDebugInfo {
|
||||
EntityDebugInfo {
|
||||
name: self.name.clone(),
|
||||
id: self.id,
|
||||
enabled: self.enabled,
|
||||
active: self.active,
|
||||
destroyed: self.is_destroyed,
|
||||
component_count: self.components.len(),
|
||||
component_mask: format!("{:b}", self.component_mask),
|
||||
parent_id: self.parent_id,
|
||||
child_count: self.children_ids.len(),
|
||||
child_ids: self.children_ids.clone(),
|
||||
tag: self.tag,
|
||||
update_order: self.update_order,
|
||||
index_mapping_size: self.component_type_to_index.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体调试信息
|
||||
*/
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct EntityDebugInfo {
|
||||
pub name: String,
|
||||
pub id: u32,
|
||||
pub enabled: bool,
|
||||
pub active: bool,
|
||||
pub destroyed: bool,
|
||||
pub component_count: usize,
|
||||
pub component_mask: String,
|
||||
pub parent_id: Option<u32>,
|
||||
pub child_count: usize,
|
||||
pub child_ids: Vec<u32>,
|
||||
pub tag: u32,
|
||||
pub update_order: i32,
|
||||
pub index_mapping_size: usize,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Entity {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Entity[{}:{}]", self.name, self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Entity {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Entity")
|
||||
.field("name", &self.name)
|
||||
.field("id", &self.id)
|
||||
.field("active", &self.active)
|
||||
.field("enabled", &self.enabled)
|
||||
.field("is_destroyed", &self.is_destroyed)
|
||||
.field("tag", &self.tag)
|
||||
.field("update_order", &self.update_order)
|
||||
.field("parent_id", &self.parent_id)
|
||||
.field("children_count", &self.children_ids.len())
|
||||
.field("component_count", &self.components.len())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
630
packages/core-rust/src/core/entity_batch_operator.rs
Normal file
630
packages/core-rust/src/core/entity_batch_operator.rs
Normal file
@@ -0,0 +1,630 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::core::{Entity, ComponentRegistry};
|
||||
|
||||
/**
|
||||
* 实体批量操作器
|
||||
* 提供对多个实体的批量操作功能
|
||||
*/
|
||||
pub struct EntityBatchOperator {
|
||||
entities: Vec<Entity>,
|
||||
component_registry: ComponentRegistry,
|
||||
}
|
||||
|
||||
impl EntityBatchOperator {
|
||||
/**
|
||||
* 创建批量操作器
|
||||
*/
|
||||
pub fn new(entities: Vec<Entity>) -> Self {
|
||||
Self {
|
||||
entities,
|
||||
component_registry: ComponentRegistry::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从实体ID创建批量操作器
|
||||
*/
|
||||
pub fn from_ids(entity_ids: Vec<u32>) -> Self {
|
||||
let entities: Vec<Entity> = entity_ids
|
||||
.into_iter()
|
||||
.map(|id| {
|
||||
let mut entity = Entity::new(id);
|
||||
entity.set_id(id);
|
||||
entity
|
||||
})
|
||||
.collect();
|
||||
Self::new(entities)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置活跃状态
|
||||
*/
|
||||
pub fn set_enabled(&mut self, enabled: bool) -> &mut Self {
|
||||
for entity in &mut self.entities {
|
||||
entity.set_enabled(enabled);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置名称
|
||||
*/
|
||||
pub fn set_name(&mut self, name: &str) -> &mut Self {
|
||||
for entity in &mut self.entities {
|
||||
entity.set_name(name.to_string());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置标签
|
||||
*/
|
||||
pub fn set_tag(&mut self, tag: u32) -> &mut Self {
|
||||
for entity in &mut self.entities {
|
||||
entity.set_tag(tag);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加标签
|
||||
*/
|
||||
pub fn add_tag(&mut self, tag: u32) -> &mut Self {
|
||||
for entity in &mut self.entities {
|
||||
entity.add_tag(tag);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量移除标签
|
||||
*/
|
||||
pub fn remove_tag(&mut self, tag: u32) -> &mut Self {
|
||||
for entity in &mut self.entities {
|
||||
entity.remove_tag(tag);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量执行操作
|
||||
*/
|
||||
pub fn for_each<F>(&mut self, mut operation: F) -> &mut Self
|
||||
where
|
||||
F: FnMut(&mut Entity, usize),
|
||||
{
|
||||
for (index, entity) in self.entities.iter_mut().enumerate() {
|
||||
operation(entity, index);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量执行只读操作
|
||||
*/
|
||||
pub fn for_each_readonly<F>(&self, mut operation: F) -> &Self
|
||||
where
|
||||
F: FnMut(&Entity, usize),
|
||||
{
|
||||
for (index, entity) in self.entities.iter().enumerate() {
|
||||
operation(entity, index);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤实体
|
||||
*/
|
||||
pub fn filter<F>(self, predicate: F) -> Self
|
||||
where
|
||||
F: Fn(&Entity) -> bool,
|
||||
{
|
||||
let filtered_entities: Vec<Entity> = self.entities
|
||||
.into_iter()
|
||||
.filter(|entity| predicate(entity))
|
||||
.collect();
|
||||
|
||||
Self::new(filtered_entities)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按条件分组
|
||||
*/
|
||||
pub fn group_by<F, K>(self, key_fn: F) -> HashMap<K, EntityBatchOperator>
|
||||
where
|
||||
F: Fn(&Entity) -> K,
|
||||
K: Eq + std::hash::Hash,
|
||||
{
|
||||
let mut groups: HashMap<K, Vec<Entity>> = HashMap::new();
|
||||
|
||||
for entity in self.entities {
|
||||
let key = key_fn(&entity);
|
||||
groups.entry(key).or_insert_with(Vec::new).push(entity);
|
||||
}
|
||||
|
||||
groups.into_iter()
|
||||
.map(|(key, entities)| (key, EntityBatchOperator::new(entities)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体数量
|
||||
*/
|
||||
pub fn count(&self) -> usize {
|
||||
self.entities.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为空
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entities.is_empty()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取第一个实体的只读引用
|
||||
*/
|
||||
pub fn first(&self) -> Option<&Entity> {
|
||||
self.entities.first()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取第一个实体的可变引用
|
||||
*/
|
||||
pub fn first_mut(&mut self) -> Option<&mut Entity> {
|
||||
self.entities.first_mut()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一个实体的只读引用
|
||||
*/
|
||||
pub fn last(&self) -> Option<&Entity> {
|
||||
self.entities.last()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一个实体的可变引用
|
||||
*/
|
||||
pub fn last_mut(&mut self) -> Option<&mut Entity> {
|
||||
self.entities.last_mut()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的实体
|
||||
*/
|
||||
pub fn get(&self, index: usize) -> Option<&Entity> {
|
||||
self.entities.get(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的可变实体
|
||||
*/
|
||||
pub fn get_mut(&mut self, index: usize) -> Option<&mut Entity> {
|
||||
self.entities.get_mut(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有实体
|
||||
*/
|
||||
pub fn clear(&mut self) -> &mut Self {
|
||||
self.entities.clear();
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体
|
||||
*/
|
||||
pub fn add_entity(&mut self, entity: Entity) -> &mut Self {
|
||||
self.entities.push(entity);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加多个实体
|
||||
*/
|
||||
pub fn add_entities(&mut self, mut entities: Vec<Entity>) -> &mut Self {
|
||||
self.entities.append(&mut entities);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定索引的实体
|
||||
*/
|
||||
pub fn remove_at(&mut self, index: usize) -> Option<Entity> {
|
||||
if index < self.entities.len() {
|
||||
Some(self.entities.remove(index))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除满足条件的实体
|
||||
*/
|
||||
pub fn remove_if<F>(&mut self, predicate: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&Entity) -> bool,
|
||||
{
|
||||
self.entities.retain(|entity| !predicate(entity));
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体ID
|
||||
*/
|
||||
pub fn get_entity_ids(&self) -> Vec<u32> {
|
||||
self.entities.iter().map(|entity| entity.id()).collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否包含指定ID的实体
|
||||
*/
|
||||
pub fn contains_entity(&self, entity_id: u32) -> bool {
|
||||
self.entities.iter().any(|entity| entity.id() == entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按ID查找实体
|
||||
*/
|
||||
pub fn find_by_id(&self, entity_id: u32) -> Option<&Entity> {
|
||||
self.entities.iter().find(|entity| entity.id() == entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按ID查找可变实体
|
||||
*/
|
||||
pub fn find_by_id_mut(&mut self, entity_id: u32) -> Option<&mut Entity> {
|
||||
self.entities.iter_mut().find(|entity| entity.id() == entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称查找实体
|
||||
*/
|
||||
pub fn find_by_name(&self, name: &str) -> Vec<&Entity> {
|
||||
self.entities
|
||||
.iter()
|
||||
.filter(|entity| entity.name().as_deref() == Some(name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 按标签查找实体
|
||||
*/
|
||||
pub fn find_by_tag(&self, tag: u32) -> Vec<&Entity> {
|
||||
self.entities
|
||||
.iter()
|
||||
.filter(|entity| entity.has_tag(tag))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的实体
|
||||
*/
|
||||
pub fn get_enabled(&self) -> Vec<&Entity> {
|
||||
self.entities
|
||||
.iter()
|
||||
.filter(|entity| entity.enabled())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取禁用的实体
|
||||
*/
|
||||
pub fn get_disabled(&self) -> Vec<&Entity> {
|
||||
self.entities
|
||||
.iter()
|
||||
.filter(|entity| !entity.enabled())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序实体
|
||||
*/
|
||||
pub fn sort_by<F>(&mut self, compare: F) -> &mut Self
|
||||
where
|
||||
F: FnMut(&Entity, &Entity) -> std::cmp::Ordering,
|
||||
{
|
||||
self.entities.sort_by(compare);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 按ID排序
|
||||
*/
|
||||
pub fn sort_by_id(&mut self) -> &mut Self {
|
||||
self.entities.sort_by(|a, b| a.id().cmp(&b.id()));
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称排序
|
||||
*/
|
||||
pub fn sort_by_name(&mut self) -> &mut Self {
|
||||
self.entities.sort_by(|a, b| a.name().cmp(&b.name()));
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体数组
|
||||
*/
|
||||
pub fn to_vec(self) -> Vec<Entity> {
|
||||
self.entities
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体ID数组
|
||||
*/
|
||||
pub fn to_id_vec(&self) -> Vec<u32> {
|
||||
self.get_entity_ids()
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆实体数组
|
||||
*/
|
||||
pub fn clone_entities(&self) -> Vec<Entity> {
|
||||
self.entities.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量操作统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BatchOperatorStats {
|
||||
pub total_operations: u64,
|
||||
pub entities_processed: u64,
|
||||
pub filters_applied: u64,
|
||||
pub groups_created: u64,
|
||||
pub sorts_performed: u64,
|
||||
}
|
||||
|
||||
impl BatchOperatorStats {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_operations: 0,
|
||||
entities_processed: 0,
|
||||
filters_applied: 0,
|
||||
groups_created: 0,
|
||||
sorts_performed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置统计信息
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.total_operations = 0;
|
||||
self.entities_processed = 0;
|
||||
self.filters_applied = 0;
|
||||
self.groups_created = 0;
|
||||
self.sorts_performed = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录操作
|
||||
*/
|
||||
pub fn record_operation(&mut self, entities_count: usize) {
|
||||
self.total_operations += 1;
|
||||
self.entities_processed += entities_count as u64;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录过滤操作
|
||||
*/
|
||||
pub fn record_filter(&mut self) {
|
||||
self.filters_applied += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录分组操作
|
||||
*/
|
||||
pub fn record_group(&mut self) {
|
||||
self.groups_created += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录排序操作
|
||||
*/
|
||||
pub fn record_sort(&mut self) {
|
||||
self.sorts_performed += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平均处理实体数
|
||||
*/
|
||||
pub fn average_entities_per_operation(&self) -> f64 {
|
||||
if self.total_operations == 0 {
|
||||
0.0
|
||||
} else {
|
||||
self.entities_processed as f64 / self.total_operations as f64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn create_test_entities() -> Vec<Entity> {
|
||||
vec![
|
||||
{
|
||||
let mut e = Entity::new(1);
|
||||
e.set_name("Entity1".to_string());
|
||||
e.set_tag(100);
|
||||
e
|
||||
},
|
||||
{
|
||||
let mut e = Entity::new(2);
|
||||
e.set_name("Entity2".to_string());
|
||||
e.set_tag(200);
|
||||
e.set_enabled(false);
|
||||
e
|
||||
},
|
||||
{
|
||||
let mut e = Entity::new(3);
|
||||
e.set_name("Entity3".to_string());
|
||||
e.set_tag(100);
|
||||
e
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_operator_creation() {
|
||||
let entities = create_test_entities();
|
||||
let operator = EntityBatchOperator::new(entities);
|
||||
assert_eq!(operator.count(), 3);
|
||||
assert!(!operator.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_operator_from_ids() {
|
||||
let ids = vec![1, 2, 3];
|
||||
let operator = EntityBatchOperator::from_ids(ids);
|
||||
assert_eq!(operator.count(), 3);
|
||||
assert_eq!(operator.get_entity_ids(), vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_set_enabled() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
operator.set_enabled(false);
|
||||
assert_eq!(operator.get_enabled().len(), 0);
|
||||
assert_eq!(operator.get_disabled().len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_set_name() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
operator.set_name("NewName");
|
||||
for entity in operator.entities.iter() {
|
||||
assert_eq!(entity.name().as_deref(), Some("NewName"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_tags() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
operator.add_tag(999);
|
||||
for entity in operator.entities.iter() {
|
||||
assert!(entity.has_tag(999));
|
||||
}
|
||||
|
||||
operator.remove_tag(999);
|
||||
for entity in operator.entities.iter() {
|
||||
assert!(!entity.has_tag(999));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_for_each() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
let mut count = 0;
|
||||
operator.for_each(|_, index| {
|
||||
count += index + 1;
|
||||
});
|
||||
assert_eq!(count, 6); // 1 + 2 + 3
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_filter() {
|
||||
let entities = create_test_entities();
|
||||
let operator = EntityBatchOperator::new(entities);
|
||||
|
||||
let filtered = operator.filter(|entity| entity.has_tag(100));
|
||||
assert_eq!(filtered.count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_group_by() {
|
||||
let entities = create_test_entities();
|
||||
let operator = EntityBatchOperator::new(entities);
|
||||
|
||||
let groups = operator.group_by(|entity| entity.enabled());
|
||||
assert_eq!(groups.len(), 2);
|
||||
assert!(groups.contains_key(&true));
|
||||
assert!(groups.contains_key(&false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_first_last() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
assert_eq!(operator.first().unwrap().id(), 1);
|
||||
assert_eq!(operator.last().unwrap().id(), 3);
|
||||
|
||||
operator.first_mut().unwrap().set_name("Modified".to_string());
|
||||
assert_eq!(operator.first().unwrap().name().as_deref(), Some("Modified"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_find_operations() {
|
||||
let entities = create_test_entities();
|
||||
let operator = EntityBatchOperator::new(entities);
|
||||
|
||||
assert!(operator.find_by_id(2).is_some());
|
||||
assert!(operator.find_by_id(999).is_none());
|
||||
|
||||
let found_by_name = operator.find_by_name("Entity2");
|
||||
assert_eq!(found_by_name.len(), 1);
|
||||
|
||||
let found_by_tag = operator.find_by_tag(100);
|
||||
assert_eq!(found_by_tag.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_sort() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
// 按ID降序排序
|
||||
operator.sort_by(|a, b| b.id().cmp(&a.id()));
|
||||
assert_eq!(operator.get(0).unwrap().id(), 3);
|
||||
assert_eq!(operator.get(2).unwrap().id(), 1);
|
||||
|
||||
// 按ID升序排序
|
||||
operator.sort_by_id();
|
||||
assert_eq!(operator.get(0).unwrap().id(), 1);
|
||||
assert_eq!(operator.get(2).unwrap().id(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_stats() {
|
||||
let mut stats = BatchOperatorStats::new();
|
||||
|
||||
stats.record_operation(5);
|
||||
stats.record_filter();
|
||||
stats.record_group();
|
||||
stats.record_sort();
|
||||
|
||||
assert_eq!(stats.total_operations, 1);
|
||||
assert_eq!(stats.entities_processed, 5);
|
||||
assert_eq!(stats.filters_applied, 1);
|
||||
assert_eq!(stats.groups_created, 1);
|
||||
assert_eq!(stats.sorts_performed, 1);
|
||||
assert_eq!(stats.average_entities_per_operation(), 5.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_remove_operations() {
|
||||
let entities = create_test_entities();
|
||||
let mut operator = EntityBatchOperator::new(entities);
|
||||
|
||||
let removed = operator.remove_at(1);
|
||||
assert!(removed.is_some());
|
||||
assert_eq!(removed.unwrap().id(), 2);
|
||||
assert_eq!(operator.count(), 2);
|
||||
|
||||
operator.remove_if(|entity| entity.has_tag(100));
|
||||
assert_eq!(operator.count(), 0);
|
||||
}
|
||||
}
|
||||
405
packages/core-rust/src/core/entity_manager.rs
Normal file
405
packages/core-rust/src/core/entity_manager.rs
Normal file
@@ -0,0 +1,405 @@
|
||||
use crate::core::entity::Entity;
|
||||
use crate::storage::component_storage::ComponentStorageManager;
|
||||
use crate::core::component::Component;
|
||||
use crate::utils::IdentifierPool;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
/**
|
||||
* 实体管理器
|
||||
* 提供统一的实体管理和查询机制,支持高效的实体操作
|
||||
* 使用IdentifierPool进行世代式ID管理,防止悬空引用
|
||||
*/
|
||||
pub struct EntityManager {
|
||||
entities: FxHashMap<u32, Entity>,
|
||||
entities_by_name: FxHashMap<String, Vec<u32>>,
|
||||
entities_by_tag: FxHashMap<u32, Vec<u32>>,
|
||||
id_pool: IdentifierPool,
|
||||
destroyed_entities: std::collections::HashSet<u32>,
|
||||
component_storage_manager: ComponentStorageManager,
|
||||
}
|
||||
|
||||
impl EntityManager {
|
||||
/**
|
||||
* 创建实体管理器实例
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entities: FxHashMap::default(),
|
||||
entities_by_name: FxHashMap::default(),
|
||||
entities_by_tag: FxHashMap::default(),
|
||||
id_pool: IdentifierPool::with_defaults(),
|
||||
destroyed_entities: std::collections::HashSet::new(),
|
||||
component_storage_manager: ComponentStorageManager::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体总数
|
||||
*/
|
||||
pub fn entity_count(&self) -> usize {
|
||||
self.entities.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活状态的实体数量
|
||||
*/
|
||||
pub fn active_entity_count(&self) -> usize {
|
||||
self.entities
|
||||
.values()
|
||||
.filter(|entity| entity.active() && !entity.is_destroyed())
|
||||
.count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新实体
|
||||
* @param name 实体名称,如果未指定则使用实体ID生成默认名称
|
||||
* @returns 创建的实体ID(世代式ID)
|
||||
*/
|
||||
pub fn create_entity(&mut self, name: Option<String>) -> u32 {
|
||||
let id = match self.id_pool.check_out() {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
// ID池已满,记录错误并返回一个无效ID
|
||||
eprintln!("Failed to create entity: {}", e);
|
||||
return u32::MAX; // 返回无效ID作为错误标识
|
||||
}
|
||||
};
|
||||
|
||||
let entity_name = name.unwrap_or_else(|| format!("Entity_{}", id));
|
||||
let mut entity = Entity::new(id);
|
||||
entity.set_name(entity_name.clone());
|
||||
|
||||
self.entities.insert(id, entity);
|
||||
self.update_name_index(id, &entity_name, true);
|
||||
self.update_tag_index(id, 0, true);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建实体
|
||||
* @param count 要创建的实体数量
|
||||
* @param name_prefix 实体名称前缀,默认为 Entity
|
||||
* @returns 创建的实体ID数组
|
||||
*/
|
||||
pub fn create_entities_batch(&mut self, count: u32, name_prefix: Option<String>) -> Vec<u32> {
|
||||
if count == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let prefix = name_prefix.unwrap_or_else(|| "Entity".to_string());
|
||||
let mut entity_ids = Vec::with_capacity(count as usize);
|
||||
|
||||
for _ in 0..count {
|
||||
let id = match self.id_pool.check_out() {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to create entity in batch: {}", e);
|
||||
break; // 停止创建更多实体
|
||||
}
|
||||
};
|
||||
|
||||
let entity_name = format!("{}_{}", prefix, id);
|
||||
let mut entity = Entity::new(id);
|
||||
entity.set_name(entity_name.clone());
|
||||
|
||||
entity_ids.push(id);
|
||||
self.entities.insert(id, entity);
|
||||
}
|
||||
|
||||
for &id in &entity_ids {
|
||||
if let Some(entity) = self.entities.get(&id) {
|
||||
let name = entity.name.clone();
|
||||
let tag = entity.tag();
|
||||
self.update_name_index(id, &name, true);
|
||||
self.update_tag_index(id, tag, true);
|
||||
}
|
||||
}
|
||||
|
||||
entity_ids
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实体
|
||||
* @param entity_id 要销毁的实体ID
|
||||
* @returns 是否成功销毁实体
|
||||
*/
|
||||
pub fn destroy_entity(&mut self, entity_id: u32) -> bool {
|
||||
// 首先验证ID是否有效
|
||||
if !self.id_pool.is_valid(entity_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(mut entity) = self.entities.remove(&entity_id) {
|
||||
self.destroyed_entities.insert(entity_id);
|
||||
self.update_name_index(entity_id, &entity.name, false);
|
||||
self.update_tag_index(entity_id, entity.tag(), false);
|
||||
|
||||
self.component_storage_manager.remove_all_components(entity_id);
|
||||
|
||||
entity.destroy();
|
||||
|
||||
// 回收ID到池中
|
||||
self.id_pool.check_in(entity_id);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体ID
|
||||
*/
|
||||
pub fn get_all_entity_ids(&self) -> Vec<u32> {
|
||||
self.entities.keys().copied().collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取实体
|
||||
* @param id 实体ID
|
||||
* @returns 对应的实体引用,如果不存在则返回None
|
||||
*/
|
||||
pub fn get_entity(&self, id: u32) -> Option<&Entity> {
|
||||
self.entities.get(&id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取可变实体
|
||||
* @param id 实体ID
|
||||
* @returns 对应的可变实体引用,如果不存在则返回None
|
||||
*/
|
||||
pub fn get_entity_mut(&mut self, id: u32) -> Option<&mut Entity> {
|
||||
self.entities.get_mut(&id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取实体
|
||||
* @param name 实体名称
|
||||
* @returns 匹配的实体ID,如果不存在则返回None
|
||||
*/
|
||||
pub fn get_entity_by_name(&self, name: &str) -> Option<u32> {
|
||||
self.entities_by_name
|
||||
.get(name)
|
||||
.and_then(|entities| entities.first())
|
||||
.copied()
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据标签获取实体列表
|
||||
* @param tag 标签值
|
||||
* @returns 具有指定标签的实体ID数组
|
||||
*/
|
||||
pub fn get_entities_by_tag(&self, tag: u32) -> Vec<u32> {
|
||||
self.entities_by_tag
|
||||
.get(&tag)
|
||||
.cloned()
|
||||
.unwrap_or_else(Vec::new)
|
||||
}
|
||||
|
||||
/**
|
||||
* 为实体添加组件
|
||||
* @param entity_id 实体ID
|
||||
* @param component 组件实例
|
||||
*/
|
||||
pub fn add_component<T: Component + Clone + 'static>(&mut self, entity_id: u32, component: T) -> Result<(), String> {
|
||||
if !self.entities.contains_key(&entity_id) {
|
||||
return Err(format!("Entity {} does not exist", entity_id));
|
||||
}
|
||||
|
||||
self.component_storage_manager.add_component(entity_id, component)?;
|
||||
|
||||
if let Some(entity) = self.entities.get_mut(&entity_id) {
|
||||
let mask = self.component_storage_manager.get_component_mask(entity_id);
|
||||
entity.set_component_mask(mask);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的组件位掩码
|
||||
* @param entity_id 实体ID
|
||||
* @returns 组件位掩码
|
||||
*/
|
||||
pub fn get_component_mask(&self, entity_id: u32) -> u64 {
|
||||
self.component_storage_manager.get_component_mask(entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件存储管理器
|
||||
*/
|
||||
pub fn get_component_storage_manager(&self) -> &ComponentStorageManager {
|
||||
&self.component_storage_manager
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变组件存储管理器
|
||||
*/
|
||||
pub fn get_component_storage_manager_mut(&mut self) -> &mut ComponentStorageManager {
|
||||
&mut self.component_storage_manager
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新名称索引
|
||||
* @param entity_id 实体ID
|
||||
* @param name 实体名称
|
||||
* @param is_add true表示添加到索引,false表示从索引中移除
|
||||
*/
|
||||
fn update_name_index(&mut self, entity_id: u32, name: &str, is_add: bool) {
|
||||
if is_add {
|
||||
self.entities_by_name
|
||||
.entry(name.to_string())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(entity_id);
|
||||
} else {
|
||||
if let Some(entities) = self.entities_by_name.get_mut(name) {
|
||||
entities.retain(|&id| id != entity_id);
|
||||
if entities.is_empty() {
|
||||
self.entities_by_name.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新标签索引
|
||||
* @param entity_id 实体ID
|
||||
* @param tag 标签值
|
||||
* @param is_add true表示添加到索引,false表示从索引中移除
|
||||
*/
|
||||
fn update_tag_index(&mut self, entity_id: u32, tag: u32, is_add: bool) {
|
||||
if is_add {
|
||||
self.entities_by_tag
|
||||
.entry(tag)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(entity_id);
|
||||
} else {
|
||||
if let Some(entities) = self.entities_by_tag.get_mut(&tag) {
|
||||
entities.retain(|&id| id != entity_id);
|
||||
if entities.is_empty() {
|
||||
self.entities_by_tag.remove(&tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== IdentifierPool相关方法 ==========
|
||||
|
||||
/**
|
||||
* 验证实体ID是否有效(考虑世代版本)
|
||||
* @param entity_id 要验证的实体ID
|
||||
* @returns 是否为有效的ID
|
||||
*/
|
||||
pub fn is_entity_id_valid(&self, entity_id: u32) -> bool {
|
||||
self.id_pool.is_valid(entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制处理延迟回收的ID
|
||||
* 在某些情况下可能需要立即处理延迟回收队列
|
||||
*/
|
||||
pub fn force_process_delayed_recycle(&mut self) {
|
||||
self.id_pool.force_process_delayed_recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IdentifierPool统计信息
|
||||
* 用于调试和性能监控
|
||||
*/
|
||||
pub fn get_id_pool_stats(&self) -> crate::utils::IdentifierPoolStats {
|
||||
self.id_pool.get_stats()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否存在且有效
|
||||
* 结合ID有效性检查和实际存在性检查
|
||||
*/
|
||||
pub fn entity_exists_and_valid(&self, entity_id: u32) -> bool {
|
||||
self.id_pool.is_valid(entity_id) && self.entities.contains_key(&entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效实体的数量
|
||||
* 只计算ID有效且实际存在的实体
|
||||
*/
|
||||
pub fn valid_entity_count(&self) -> usize {
|
||||
self.entities.iter()
|
||||
.filter(|(&id, _)| self.id_pool.is_valid(id))
|
||||
.count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理所有无效的实体引用
|
||||
* 清理那些ID已经无效的实体记录
|
||||
*/
|
||||
pub fn cleanup_invalid_entities(&mut self) {
|
||||
let invalid_ids: Vec<u32> = self.entities.keys()
|
||||
.filter(|&&id| !self.id_pool.is_valid(id))
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
for id in invalid_ids {
|
||||
if let Some(entity) = self.entities.remove(&id) {
|
||||
// 从索引中清理
|
||||
self.update_name_index(id, &entity.name, false);
|
||||
self.update_tag_index(id, entity.tag(), false);
|
||||
// 从销毁实体集合中清理
|
||||
self.destroyed_entities.remove(&id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试信息(包含ID池统计)
|
||||
*/
|
||||
pub fn get_debug_info(&self) -> String {
|
||||
let id_stats = self.id_pool.get_stats();
|
||||
format!(
|
||||
"{{\"entities\":{},\"active_entities\":{},\"valid_entities\":{},\"destroyed_entities\":{},\"id_pool\":{{\"total_allocated\":{},\"current_active\":{},\"pending_recycle\":{},\"memory_usage\":{}}}}}",
|
||||
self.entity_count(),
|
||||
self.active_entity_count(),
|
||||
self.valid_entity_count(),
|
||||
self.destroyed_entities.len(),
|
||||
id_stats.total_allocated,
|
||||
id_stats.current_active,
|
||||
id_stats.pending_recycle,
|
||||
id_stats.memory_usage
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体到管理器
|
||||
*/
|
||||
pub fn add_entity(&mut self, mut entity: Entity) {
|
||||
let entity_id = if entity.id() == 0 {
|
||||
// 如果实体ID为0,分配新ID
|
||||
let new_id = self.id_pool.check_out().unwrap_or(0);
|
||||
entity.set_id(new_id);
|
||||
new_id
|
||||
} else {
|
||||
entity.id()
|
||||
};
|
||||
|
||||
// 如果实体有名称,添加到名称索引
|
||||
if let Some(name) = entity.name() {
|
||||
self.entities_by_name.entry(name.clone()).or_insert_with(Vec::new).push(entity_id);
|
||||
}
|
||||
|
||||
// 如果实体有标签,添加到标签索引
|
||||
for tag in &entity.tags() {
|
||||
self.entities_by_tag.entry(*tag).or_insert_with(Vec::new).push(entity_id);
|
||||
}
|
||||
|
||||
self.entities.insert(entity_id, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预留容量
|
||||
*/
|
||||
pub fn reserve_capacity(&mut self, capacity: usize) {
|
||||
self.entities.reserve(capacity);
|
||||
self.entities_by_name.reserve(capacity / 10); // 假设10%的实体有名称
|
||||
self.entities_by_tag.reserve(capacity / 5); // 假设20%的实体有标签
|
||||
}
|
||||
}
|
||||
574
packages/core-rust/src/core/events.rs
Normal file
574
packages/core-rust/src/core/events.rs
Normal file
@@ -0,0 +1,574 @@
|
||||
use std::collections::HashMap;
|
||||
use std::any::Any;
|
||||
|
||||
/**
|
||||
* ECS事件类型
|
||||
* 定义实体组件系统中的核心事件类型
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ECSEventType {
|
||||
// 实体相关事件
|
||||
EntityCreated,
|
||||
EntityDestroyed,
|
||||
EntityEnabled,
|
||||
EntityDisabled,
|
||||
EntityTagChanged,
|
||||
EntityNameChanged,
|
||||
|
||||
// 组件相关事件
|
||||
ComponentAdded,
|
||||
ComponentRemoved,
|
||||
ComponentModified,
|
||||
ComponentEnabled,
|
||||
ComponentDisabled,
|
||||
|
||||
// 系统相关事件
|
||||
SystemAdded,
|
||||
SystemRemoved,
|
||||
SystemEnabled,
|
||||
SystemDisabled,
|
||||
SystemProcessingStart,
|
||||
SystemProcessingEnd,
|
||||
SystemError,
|
||||
|
||||
// 场景相关事件
|
||||
SceneCreated,
|
||||
SceneDestroyed,
|
||||
SceneActivated,
|
||||
SceneDeactivated,
|
||||
|
||||
// 性能相关事件
|
||||
PerformanceWarning,
|
||||
PerformanceCritical,
|
||||
MemoryUsageHigh,
|
||||
|
||||
// 查询相关事件
|
||||
QueryExecuted,
|
||||
QueryCacheHit,
|
||||
QueryCacheMiss,
|
||||
}
|
||||
|
||||
impl ECSEventType {
|
||||
/**
|
||||
* 转换为字符串表示
|
||||
*/
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
ECSEventType::EntityCreated => "entity:created",
|
||||
ECSEventType::EntityDestroyed => "entity:destroyed",
|
||||
ECSEventType::EntityEnabled => "entity:enabled",
|
||||
ECSEventType::EntityDisabled => "entity:disabled",
|
||||
ECSEventType::EntityTagChanged => "entity:tag:changed",
|
||||
ECSEventType::EntityNameChanged => "entity:name:changed",
|
||||
ECSEventType::ComponentAdded => "component:added",
|
||||
ECSEventType::ComponentRemoved => "component:removed",
|
||||
ECSEventType::ComponentModified => "component:modified",
|
||||
ECSEventType::ComponentEnabled => "component:enabled",
|
||||
ECSEventType::ComponentDisabled => "component:disabled",
|
||||
ECSEventType::SystemAdded => "system:added",
|
||||
ECSEventType::SystemRemoved => "system:removed",
|
||||
ECSEventType::SystemEnabled => "system:enabled",
|
||||
ECSEventType::SystemDisabled => "system:disabled",
|
||||
ECSEventType::SystemProcessingStart => "system:processing:start",
|
||||
ECSEventType::SystemProcessingEnd => "system:processing:end",
|
||||
ECSEventType::SystemError => "system:error",
|
||||
ECSEventType::SceneCreated => "scene:created",
|
||||
ECSEventType::SceneDestroyed => "scene:destroyed",
|
||||
ECSEventType::SceneActivated => "scene:activated",
|
||||
ECSEventType::SceneDeactivated => "scene:deactivated",
|
||||
ECSEventType::PerformanceWarning => "performance:warning",
|
||||
ECSEventType::PerformanceCritical => "performance:critical",
|
||||
ECSEventType::MemoryUsageHigh => "memory:usage:high",
|
||||
ECSEventType::QueryExecuted => "query:executed",
|
||||
ECSEventType::QueryCacheHit => "query:cache:hit",
|
||||
ECSEventType::QueryCacheMiss => "query:cache:miss",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件优先级
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum EventPriority {
|
||||
Lowest = 0,
|
||||
Low = 25,
|
||||
Normal = 50,
|
||||
High = 75,
|
||||
Highest = 100,
|
||||
Critical = 200,
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件数据
|
||||
* 包含事件的所有信息
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct Event {
|
||||
pub event_type: ECSEventType,
|
||||
pub priority: EventPriority,
|
||||
pub timestamp: u64,
|
||||
pub entity_id: Option<u32>,
|
||||
pub data: Option<Box<dyn Any + Send + Sync>>,
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
/**
|
||||
* 创建新事件
|
||||
*/
|
||||
pub fn new(event_type: ECSEventType, priority: EventPriority) -> Self {
|
||||
Self {
|
||||
event_type,
|
||||
priority,
|
||||
timestamp: current_timestamp(),
|
||||
entity_id: None,
|
||||
data: None,
|
||||
metadata: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体ID
|
||||
*/
|
||||
pub fn with_entity_id(mut self, entity_id: u32) -> Self {
|
||||
self.entity_id = Some(entity_id);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置事件数据
|
||||
*/
|
||||
pub fn with_data<T: Any + Send + Sync>(mut self, data: T) -> Self {
|
||||
self.data = Some(Box::new(data));
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加元数据
|
||||
*/
|
||||
pub fn with_metadata<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
|
||||
self.metadata.insert(key.into(), value.into());
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型化的数据
|
||||
*/
|
||||
pub fn get_data<T: Any>(&self) -> Option<&T> {
|
||||
self.data.as_ref()?.downcast_ref::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元数据
|
||||
*/
|
||||
pub fn get_metadata(&self, key: &str) -> Option<&String> {
|
||||
self.metadata.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件监听器trait
|
||||
*/
|
||||
pub trait EventListener: Send + Sync {
|
||||
/**
|
||||
* 处理事件
|
||||
*/
|
||||
fn handle_event(&mut self, event: &Event);
|
||||
|
||||
/**
|
||||
* 获取监听器感兴趣的事件类型
|
||||
*/
|
||||
fn get_interested_events(&self) -> Vec<ECSEventType>;
|
||||
|
||||
/**
|
||||
* 获取监听器优先级
|
||||
*/
|
||||
fn get_priority(&self) -> EventPriority {
|
||||
EventPriority::Normal
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否应该处理此事件
|
||||
*/
|
||||
fn should_handle(&self, event: &Event) -> bool {
|
||||
self.get_interested_events().contains(&event.event_type)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件回调函数类型
|
||||
*/
|
||||
pub type EventCallback = Box<dyn Fn(&Event) + Send + Sync>;
|
||||
|
||||
/**
|
||||
* 监听器注册信息
|
||||
*/
|
||||
struct ListenerRegistration {
|
||||
callback: EventCallback,
|
||||
id: u32,
|
||||
priority: EventPriority,
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件总线
|
||||
* 负责事件的分发和监听器管理
|
||||
*/
|
||||
pub struct EventBus {
|
||||
listeners: HashMap<ECSEventType, Vec<ListenerRegistration>>,
|
||||
next_listener_id: u32,
|
||||
event_queue: Vec<Event>,
|
||||
stats: EventBusStats,
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件总线统计信息
|
||||
*/
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EventBusStats {
|
||||
pub total_events_fired: u64,
|
||||
pub total_listeners_notified: u64,
|
||||
pub events_by_type: HashMap<ECSEventType, u32>,
|
||||
pub listener_count: u32,
|
||||
pub queue_size: usize,
|
||||
}
|
||||
|
||||
impl EventBus {
|
||||
/**
|
||||
* 创建新的事件总线
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
listeners: HashMap::new(),
|
||||
next_listener_id: 1,
|
||||
event_queue: Vec::new(),
|
||||
stats: EventBusStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册事件回调函数
|
||||
*/
|
||||
pub fn register_callback<F>(&mut self, event_type: ECSEventType, callback: F, priority: EventPriority) -> u32
|
||||
where
|
||||
F: Fn(&Event) + Send + Sync + 'static,
|
||||
{
|
||||
let id = self.next_listener_id;
|
||||
self.next_listener_id += 1;
|
||||
|
||||
let registration = ListenerRegistration {
|
||||
callback: Box::new(callback),
|
||||
id,
|
||||
priority,
|
||||
};
|
||||
|
||||
let listeners = self.listeners.entry(event_type).or_insert_with(Vec::new);
|
||||
listeners.push(registration);
|
||||
|
||||
// 按优先级排序
|
||||
listeners.sort_by(|a, b| b.priority.cmp(&a.priority));
|
||||
|
||||
self.stats.listener_count += 1;
|
||||
id
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册多个事件类型的回调
|
||||
*/
|
||||
pub fn register_callback_multi<F>(&mut self, event_types: Vec<ECSEventType>, callback: F, priority: EventPriority) -> Vec<u32>
|
||||
where
|
||||
F: Fn(&Event) + Send + Sync + Clone + 'static,
|
||||
{
|
||||
let mut ids = Vec::new();
|
||||
for event_type in event_types {
|
||||
let id = self.register_callback(event_type, callback.clone(), priority);
|
||||
ids.push(id);
|
||||
}
|
||||
ids
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销事件监听器
|
||||
*/
|
||||
pub fn unregister_callback(&mut self, listener_id: u32) -> bool {
|
||||
let mut found = false;
|
||||
|
||||
for listeners in self.listeners.values_mut() {
|
||||
listeners.retain(|reg| {
|
||||
if reg.id == listener_id {
|
||||
found = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if found {
|
||||
self.stats.listener_count -= 1;
|
||||
}
|
||||
|
||||
found
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即触发事件
|
||||
*/
|
||||
pub fn fire_event(&mut self, event: Event) {
|
||||
self.stats.total_events_fired += 1;
|
||||
*self.stats.events_by_type.entry(event.event_type).or_insert(0) += 1;
|
||||
|
||||
if let Some(listeners) = self.listeners.get(&event.event_type) {
|
||||
for registration in listeners {
|
||||
(registration.callback)(&event);
|
||||
self.stats.total_listeners_notified += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将事件添加到队列(延迟处理)
|
||||
*/
|
||||
pub fn queue_event(&mut self, event: Event) {
|
||||
self.event_queue.push(event);
|
||||
self.stats.queue_size = self.event_queue.len();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理队列中的所有事件
|
||||
*/
|
||||
pub fn process_queued_events(&mut self) {
|
||||
let events = std::mem::take(&mut self.event_queue);
|
||||
for event in events {
|
||||
self.fire_event(event);
|
||||
}
|
||||
self.stats.queue_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空事件队列
|
||||
*/
|
||||
pub fn clear_queue(&mut self) {
|
||||
self.event_queue.clear();
|
||||
self.stats.queue_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> &EventBusStats {
|
||||
&self.stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有指定类型的监听器
|
||||
*/
|
||||
pub fn has_listeners(&self, event_type: ECSEventType) -> bool {
|
||||
self.listeners.get(&event_type).map_or(false, |listeners| !listeners.is_empty())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定事件类型的监听器数量
|
||||
*/
|
||||
pub fn get_listener_count(&self, event_type: ECSEventType) -> usize {
|
||||
self.listeners.get(&event_type).map_or(0, |listeners| listeners.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EventBus {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单的事件监听器实现
|
||||
*/
|
||||
pub struct SimpleEventListener<F>
|
||||
where
|
||||
F: Fn(&Event) + Send + Sync,
|
||||
{
|
||||
handler: F,
|
||||
interested_events: Vec<ECSEventType>,
|
||||
priority: EventPriority,
|
||||
}
|
||||
|
||||
impl<F> SimpleEventListener<F>
|
||||
where
|
||||
F: Fn(&Event) + Send + Sync,
|
||||
{
|
||||
/**
|
||||
* 创建简单的事件监听器
|
||||
*/
|
||||
pub fn new(handler: F, interested_events: Vec<ECSEventType>) -> Self {
|
||||
Self {
|
||||
handler,
|
||||
interested_events,
|
||||
priority: EventPriority::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置优先级
|
||||
*/
|
||||
pub fn with_priority(mut self, priority: EventPriority) -> Self {
|
||||
self.priority = priority;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> EventListener for SimpleEventListener<F>
|
||||
where
|
||||
F: Fn(&Event) + Send + Sync,
|
||||
{
|
||||
fn handle_event(&mut self, event: &Event) {
|
||||
(self.handler)(event);
|
||||
}
|
||||
|
||||
fn get_interested_events(&self) -> Vec<ECSEventType> {
|
||||
self.interested_events.clone()
|
||||
}
|
||||
|
||||
fn get_priority(&self) -> EventPriority {
|
||||
self.priority
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(毫秒)
|
||||
*/
|
||||
fn current_timestamp() -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[test]
|
||||
fn test_event_creation() {
|
||||
let event = Event::new(ECSEventType::EntityCreated, EventPriority::Normal)
|
||||
.with_entity_id(42)
|
||||
.with_data("test data".to_string())
|
||||
.with_metadata("key", "value");
|
||||
|
||||
assert_eq!(event.event_type, ECSEventType::EntityCreated);
|
||||
assert_eq!(event.priority, EventPriority::Normal);
|
||||
assert_eq!(event.entity_id, Some(42));
|
||||
assert_eq!(event.get_data::<String>(), Some(&"test data".to_string()));
|
||||
assert_eq!(event.get_metadata("key"), Some(&"value".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_event_bus_basic() {
|
||||
let mut event_bus = EventBus::new();
|
||||
let events_received = Arc::new(Mutex::new(Vec::new()));
|
||||
let events_clone = events_received.clone();
|
||||
|
||||
// 注册回调
|
||||
let listener_id = event_bus.register_callback(
|
||||
ECSEventType::EntityCreated,
|
||||
move |event: &Event| {
|
||||
if let Ok(mut events) = events_clone.lock() {
|
||||
events.push(event.event_type);
|
||||
}
|
||||
},
|
||||
EventPriority::Normal,
|
||||
);
|
||||
|
||||
// 触发事件
|
||||
let event = Event::new(ECSEventType::EntityCreated, EventPriority::Normal)
|
||||
.with_entity_id(123);
|
||||
event_bus.fire_event(event);
|
||||
|
||||
// 验证事件被接收
|
||||
let events = events_received.lock().unwrap();
|
||||
assert_eq!(events.len(), 1);
|
||||
assert_eq!(events[0], ECSEventType::EntityCreated);
|
||||
|
||||
// 验证统计信息
|
||||
let stats = event_bus.get_stats();
|
||||
assert_eq!(stats.total_events_fired, 1);
|
||||
assert_eq!(stats.total_listeners_notified, 1);
|
||||
|
||||
// 注销监听器
|
||||
assert!(event_bus.unregister_callback(listener_id));
|
||||
assert!(!event_bus.unregister_callback(listener_id)); // 重复注销应该失败
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_event_queue() {
|
||||
let mut event_bus = EventBus::new();
|
||||
let events_received = Arc::new(Mutex::new(Vec::new()));
|
||||
let events_clone1 = events_received.clone();
|
||||
let events_clone2 = events_received.clone();
|
||||
|
||||
event_bus.register_callback(
|
||||
ECSEventType::EntityCreated,
|
||||
move |event: &Event| {
|
||||
if let Ok(mut events) = events_clone1.lock() {
|
||||
events.push(event.event_type);
|
||||
}
|
||||
},
|
||||
EventPriority::Normal,
|
||||
);
|
||||
|
||||
event_bus.register_callback(
|
||||
ECSEventType::EntityDestroyed,
|
||||
move |event: &Event| {
|
||||
if let Ok(mut events) = events_clone2.lock() {
|
||||
events.push(event.event_type);
|
||||
}
|
||||
},
|
||||
EventPriority::Normal,
|
||||
);
|
||||
|
||||
// 将事件加入队列
|
||||
let event1 = Event::new(ECSEventType::EntityCreated, EventPriority::Normal);
|
||||
let event2 = Event::new(ECSEventType::EntityDestroyed, EventPriority::Normal);
|
||||
|
||||
event_bus.queue_event(event1);
|
||||
event_bus.queue_event(event2);
|
||||
|
||||
// 此时事件还没有被处理
|
||||
let events = events_received.lock().unwrap();
|
||||
assert_eq!(events.len(), 0);
|
||||
drop(events);
|
||||
|
||||
// 处理队列中的事件
|
||||
event_bus.process_queued_events();
|
||||
|
||||
let events = events_received.lock().unwrap();
|
||||
assert_eq!(events.len(), 2);
|
||||
assert_eq!(events[0], ECSEventType::EntityCreated);
|
||||
assert_eq!(events[1], ECSEventType::EntityDestroyed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_event_listener() {
|
||||
let mut event_bus = EventBus::new();
|
||||
let received_events = Arc::new(Mutex::new(Vec::new()));
|
||||
let events_clone = received_events.clone();
|
||||
|
||||
event_bus.register_callback(
|
||||
ECSEventType::ComponentAdded,
|
||||
move |event: &Event| {
|
||||
if let Ok(mut events) = events_clone.lock() {
|
||||
events.push(event.event_type);
|
||||
}
|
||||
},
|
||||
EventPriority::Normal,
|
||||
);
|
||||
|
||||
let event = Event::new(ECSEventType::ComponentAdded, EventPriority::Normal);
|
||||
event_bus.fire_event(event);
|
||||
|
||||
let events = received_events.lock().unwrap();
|
||||
assert_eq!(events.len(), 1);
|
||||
assert_eq!(events[0], ECSEventType::ComponentAdded);
|
||||
}
|
||||
}
|
||||
584
packages/core-rust/src/core/fluent_api.rs
Normal file
584
packages/core-rust/src/core/fluent_api.rs
Normal file
@@ -0,0 +1,584 @@
|
||||
use crate::core::Entity;
|
||||
use crate::utils::ComponentType;
|
||||
|
||||
/**
|
||||
* 实体构建器
|
||||
* 提供流式API创建和配置实体
|
||||
*/
|
||||
pub struct EntityBuilder {
|
||||
entity: Entity,
|
||||
scene_id: Option<u32>,
|
||||
}
|
||||
|
||||
impl EntityBuilder {
|
||||
/**
|
||||
* 创建新的实体构建器
|
||||
*/
|
||||
pub fn new(name: &str, entity_id: u32) -> Self {
|
||||
let mut entity = Entity::new(entity_id);
|
||||
entity.set_name(name.to_string());
|
||||
Self {
|
||||
entity,
|
||||
scene_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体名称
|
||||
*/
|
||||
pub fn named(mut self, name: &str) -> Self {
|
||||
self.entity.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体标签
|
||||
*/
|
||||
pub fn tagged(mut self, tag: u32) -> Self {
|
||||
self.entity.set_tag(tag);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体为启用状态
|
||||
*/
|
||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||
self.entity.set_enabled(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体为活跃状态
|
||||
*/
|
||||
pub fn active(mut self, active: bool) -> Self {
|
||||
self.entity.set_active(active);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置更新顺序
|
||||
*/
|
||||
pub fn with_update_order(mut self, order: i32) -> Self {
|
||||
self.entity.set_update_order(order);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加子实体ID
|
||||
*/
|
||||
pub fn with_child(mut self, child_id: u32) -> Self {
|
||||
let _ = self.entity.add_child_id(child_id);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加子实体ID
|
||||
*/
|
||||
pub fn with_children(mut self, child_ids: Vec<u32>) -> Self {
|
||||
for child_id in child_ids {
|
||||
let _ = self.entity.add_child_id(child_id);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性设置属性
|
||||
*/
|
||||
pub fn with_if<F>(self, condition: bool, func: F) -> Self
|
||||
where
|
||||
F: FnOnce(Self) -> Self,
|
||||
{
|
||||
if condition {
|
||||
func(self)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取构建的实体(消耗builder)
|
||||
*/
|
||||
pub fn build(self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的引用
|
||||
*/
|
||||
pub fn get_entity(&self) -> &Entity {
|
||||
&self.entity
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的可变引用
|
||||
*/
|
||||
pub fn get_entity_mut(&mut self) -> &mut Entity {
|
||||
&mut self.entity
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆构建器
|
||||
*/
|
||||
pub fn clone_builder(&self, new_entity_id: u32) -> Self {
|
||||
// 由于Entity没有实现Clone,我们创建一个新的Entity
|
||||
let mut new_entity = Entity::new(new_entity_id);
|
||||
if let Some(name) = self.entity.name() {
|
||||
new_entity.set_name(name);
|
||||
}
|
||||
new_entity.set_tag(self.entity.tag());
|
||||
new_entity.set_active(self.entity.active());
|
||||
new_entity.set_enabled(self.entity.enabled());
|
||||
new_entity.set_update_order(self.entity.update_order());
|
||||
|
||||
Self {
|
||||
entity: new_entity,
|
||||
scene_id: self.scene_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询构建器
|
||||
* 提供流式API构建复杂查询
|
||||
*/
|
||||
pub struct QueryBuilder {
|
||||
component_types: Vec<ComponentType>,
|
||||
any_component_types: Vec<ComponentType>,
|
||||
none_component_types: Vec<ComponentType>,
|
||||
tag_filter: Option<u32>,
|
||||
name_filter: Option<String>,
|
||||
active_only: bool,
|
||||
enabled_only: bool,
|
||||
}
|
||||
|
||||
impl QueryBuilder {
|
||||
/**
|
||||
* 创建新的查询构建器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
component_types: Vec::new(),
|
||||
any_component_types: Vec::new(),
|
||||
none_component_types: Vec::new(),
|
||||
tag_filter: None,
|
||||
name_filter: None,
|
||||
active_only: false,
|
||||
enabled_only: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加必须包含的组件类型
|
||||
*/
|
||||
pub fn with_component(mut self, component_type: ComponentType) -> Self {
|
||||
self.component_types.push(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加多个必须包含的组件类型
|
||||
*/
|
||||
pub fn with_components(mut self, component_types: Vec<ComponentType>) -> Self {
|
||||
self.component_types.extend(component_types);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加任意一个包含的组件类型
|
||||
*/
|
||||
pub fn with_any_component(mut self, component_type: ComponentType) -> Self {
|
||||
self.any_component_types.push(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加多个任意一个包含的组件类型
|
||||
*/
|
||||
pub fn with_any_components(mut self, component_types: Vec<ComponentType>) -> Self {
|
||||
self.any_component_types.extend(component_types);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加必须不包含的组件类型
|
||||
*/
|
||||
pub fn without_component(mut self, component_type: ComponentType) -> Self {
|
||||
self.none_component_types.push(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加多个必须不包含的组件类型
|
||||
*/
|
||||
pub fn without_components(mut self, component_types: Vec<ComponentType>) -> Self {
|
||||
self.none_component_types.extend(component_types);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 按标签过滤
|
||||
*/
|
||||
pub fn with_tag(mut self, tag: u32) -> Self {
|
||||
self.tag_filter = Some(tag);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称过滤
|
||||
*/
|
||||
pub fn with_name(mut self, name: &str) -> Self {
|
||||
self.name_filter = Some(name.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 只查询活跃实体
|
||||
*/
|
||||
pub fn active_only(mut self) -> Self {
|
||||
self.active_only = true;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 只查询启用实体
|
||||
*/
|
||||
pub fn enabled_only(mut self) -> Self {
|
||||
self.enabled_only = true;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有查询条件
|
||||
*/
|
||||
pub fn get_all_components(&self) -> &Vec<ComponentType> {
|
||||
&self.component_types
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任意查询条件
|
||||
*/
|
||||
pub fn get_any_components(&self) -> &Vec<ComponentType> {
|
||||
&self.any_component_types
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取排除查询条件
|
||||
*/
|
||||
pub fn get_none_components(&self) -> &Vec<ComponentType> {
|
||||
&self.none_component_types
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签过滤器
|
||||
*/
|
||||
pub fn get_tag_filter(&self) -> Option<u32> {
|
||||
self.tag_filter
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取名称过滤器
|
||||
*/
|
||||
pub fn get_name_filter(&self) -> Option<&String> {
|
||||
self.name_filter.as_ref()
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否只查询活跃实体
|
||||
*/
|
||||
pub fn is_active_only(&self) -> bool {
|
||||
self.active_only
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否只查询启用实体
|
||||
*/
|
||||
pub fn is_enabled_only(&self) -> bool {
|
||||
self.enabled_only
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QueryBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 流式API统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FluentAPIStats {
|
||||
/// 创建的实体构建器数量
|
||||
pub entity_builders_created: u32,
|
||||
/// 创建的查询构建器数量
|
||||
pub query_builders_created: u32,
|
||||
/// 执行的批量操作数量
|
||||
pub batch_operations_executed: u32,
|
||||
/// 使用的工厂函数数量
|
||||
pub factory_functions_used: u32,
|
||||
/// 条件操作执行次数
|
||||
pub conditional_operations: u32,
|
||||
}
|
||||
|
||||
impl Default for FluentAPIStats {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
entity_builders_created: 0,
|
||||
query_builders_created: 0,
|
||||
batch_operations_executed: 0,
|
||||
factory_functions_used: 0,
|
||||
conditional_operations: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ECS流式API主入口
|
||||
* 提供统一的流式接口
|
||||
*/
|
||||
pub struct ECSFluentAPI {
|
||||
/// 统计信息
|
||||
stats: FluentAPIStats,
|
||||
}
|
||||
|
||||
impl ECSFluentAPI {
|
||||
/**
|
||||
* 创建新的流式API实例
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stats: FluentAPIStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建实体构建器
|
||||
*/
|
||||
pub fn create_entity(&mut self, name: &str, entity_id: u32) -> EntityBuilder {
|
||||
self.stats.entity_builders_created += 1;
|
||||
EntityBuilder::new(name, entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建查询构建器
|
||||
*/
|
||||
pub fn query(&mut self) -> QueryBuilder {
|
||||
self.stats.query_builders_created += 1;
|
||||
QueryBuilder::new()
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性执行操作
|
||||
*/
|
||||
pub fn when<F, T>(&mut self, condition: bool, operation: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
self.stats.conditional_operations += 1;
|
||||
if condition {
|
||||
Some(operation())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建实体
|
||||
*/
|
||||
pub fn create_entities_batch(
|
||||
&mut self,
|
||||
count: u32,
|
||||
name_prefix: &str,
|
||||
start_id: u32,
|
||||
) -> Vec<EntityBuilder> {
|
||||
self.stats.batch_operations_executed += 1;
|
||||
|
||||
let mut builders = Vec::with_capacity(count as usize);
|
||||
for i in 0..count {
|
||||
let name = format!("{}_{}", name_prefix, i);
|
||||
let builder = EntityBuilder::new(&name, start_id + i);
|
||||
builders.push(builder);
|
||||
}
|
||||
|
||||
self.stats.entity_builders_created += count;
|
||||
builders
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用工厂函数创建实体
|
||||
*/
|
||||
pub fn create_entity_with_factory<F>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
entity_id: u32,
|
||||
factory: F,
|
||||
) -> EntityBuilder
|
||||
where
|
||||
F: FnOnce(EntityBuilder) -> EntityBuilder,
|
||||
{
|
||||
self.stats.factory_functions_used += 1;
|
||||
self.stats.entity_builders_created += 1;
|
||||
|
||||
let builder = EntityBuilder::new(name, entity_id);
|
||||
factory(builder)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> FluentAPIStats {
|
||||
self.stats.clone()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置统计信息
|
||||
*/
|
||||
pub fn reset_stats(&mut self) {
|
||||
self.stats = FluentAPIStats::default();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有状态
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.reset_stats();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ECSFluentAPI {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::TypeId;
|
||||
|
||||
// 测试用的示例组件类型
|
||||
struct TestComponentA;
|
||||
struct TestComponentB;
|
||||
struct TestComponentC;
|
||||
|
||||
#[test]
|
||||
fn test_entity_builder_basic() {
|
||||
let builder = EntityBuilder::new("test_entity", 1);
|
||||
let entity = builder
|
||||
.named("my_entity")
|
||||
.tagged(42)
|
||||
.enabled(true)
|
||||
.active(true)
|
||||
.with_update_order(10)
|
||||
.build();
|
||||
|
||||
assert_eq!(entity.name, "my_entity");
|
||||
assert_eq!(entity.tag(), 42);
|
||||
assert_eq!(entity.enabled(), true);
|
||||
assert_eq!(entity.active(), true);
|
||||
assert_eq!(entity.update_order(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entity_builder_children() {
|
||||
let builder = EntityBuilder::new("parent", 1);
|
||||
let entity = builder
|
||||
.with_child(2)
|
||||
.with_children(vec![3, 4, 5])
|
||||
.build();
|
||||
|
||||
assert_eq!(entity.children_ids().len(), 4);
|
||||
assert_eq!(entity.children_ids(), &[2, 3, 4, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entity_builder_conditional() {
|
||||
let builder = EntityBuilder::new("test", 1);
|
||||
let entity = builder
|
||||
.with_if(true, |b| b.tagged(100))
|
||||
.with_if(false, |b| b.tagged(200))
|
||||
.build();
|
||||
|
||||
assert_eq!(entity.tag(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_builder() {
|
||||
let query = QueryBuilder::new()
|
||||
.with_component(TypeId::of::<TestComponentA>())
|
||||
.with_components(vec![
|
||||
TypeId::of::<TestComponentB>(),
|
||||
TypeId::of::<TestComponentC>(),
|
||||
])
|
||||
.with_any_component(TypeId::of::<TestComponentA>())
|
||||
.without_component(TypeId::of::<TestComponentB>())
|
||||
.with_tag(42)
|
||||
.with_name("test")
|
||||
.active_only()
|
||||
.enabled_only();
|
||||
|
||||
assert_eq!(query.get_all_components().len(), 3);
|
||||
assert_eq!(query.get_any_components().len(), 1);
|
||||
assert_eq!(query.get_none_components().len(), 1);
|
||||
assert_eq!(query.get_tag_filter(), Some(42));
|
||||
assert_eq!(query.get_name_filter(), Some(&"test".to_string()));
|
||||
assert!(query.is_active_only());
|
||||
assert!(query.is_enabled_only());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fluent_api_basic() {
|
||||
let mut api = ECSFluentAPI::new();
|
||||
|
||||
let _builder = api.create_entity("test", 1);
|
||||
let _query = api.query();
|
||||
|
||||
let stats = api.get_stats();
|
||||
assert_eq!(stats.entity_builders_created, 1);
|
||||
assert_eq!(stats.query_builders_created, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fluent_api_batch() {
|
||||
let mut api = ECSFluentAPI::new();
|
||||
|
||||
let builders = api.create_entities_batch(5, "entity", 100);
|
||||
assert_eq!(builders.len(), 5);
|
||||
|
||||
let stats = api.get_stats();
|
||||
assert_eq!(stats.entity_builders_created, 5);
|
||||
assert_eq!(stats.batch_operations_executed, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fluent_api_factory() {
|
||||
let mut api = ECSFluentAPI::new();
|
||||
|
||||
let entity = api
|
||||
.create_entity_with_factory("test", 1, |builder| {
|
||||
builder.tagged(42).enabled(true)
|
||||
})
|
||||
.build();
|
||||
|
||||
assert_eq!(entity.tag(), 42);
|
||||
assert_eq!(entity.enabled(), true);
|
||||
|
||||
let stats = api.get_stats();
|
||||
assert_eq!(stats.factory_functions_used, 1);
|
||||
assert_eq!(stats.entity_builders_created, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fluent_api_conditional() {
|
||||
let mut api = ECSFluentAPI::new();
|
||||
|
||||
let result1 = api.when(true, || "executed");
|
||||
let result2 = api.when(false, || "not executed");
|
||||
|
||||
assert_eq!(result1, Some("executed"));
|
||||
assert_eq!(result2, None);
|
||||
|
||||
let stats = api.get_stats();
|
||||
assert_eq!(stats.conditional_operations, 2);
|
||||
}
|
||||
}
|
||||
27
packages/core-rust/src/core/mod.rs
Normal file
27
packages/core-rust/src/core/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
pub mod entity;
|
||||
pub mod component;
|
||||
pub mod entity_manager;
|
||||
pub mod query_system;
|
||||
pub mod scene;
|
||||
pub mod systems;
|
||||
pub mod events;
|
||||
pub mod archetype_system;
|
||||
pub mod fluent_api;
|
||||
pub mod passive_system;
|
||||
pub mod component_builder;
|
||||
pub mod entity_batch_operator;
|
||||
pub mod scene_builder;
|
||||
|
||||
pub use entity::Entity;
|
||||
pub use component::{Component, ComponentRegistry, BaseComponent};
|
||||
pub use entity_manager::EntityManager;
|
||||
pub use query_system::{QuerySystem, QueryResult};
|
||||
pub use scene::Scene;
|
||||
pub use systems::{System, EntitySystem, ProcessingSystem, IntervalSystem, SystemManager};
|
||||
pub use events::{ECSEventType, EventPriority, Event, EventListener, EventBus, EventBusStats, SimpleEventListener};
|
||||
pub use archetype_system::{ArchetypeSystem, Archetype, ArchetypeId, ArchetypeQueryResult, ArchetypeSystemStats};
|
||||
pub use fluent_api::{EntityBuilder, QueryBuilder, ECSFluentAPI, FluentAPIStats};
|
||||
pub use passive_system::{PassiveSystem, PassiveSystemBuilder};
|
||||
pub use component_builder::{ComponentBuilder, BaseComponentBuilder, ComponentBuilderFactory, ComponentBuilderStats};
|
||||
pub use entity_batch_operator::{EntityBatchOperator, BatchOperatorStats};
|
||||
pub use scene_builder::{SceneBuilder, SceneTemplate, SceneBuilderStats, SceneBuilderFactory, SceneBuilderManager};
|
||||
351
packages/core-rust/src/core/passive_system.rs
Normal file
351
packages/core-rust/src/core/passive_system.rs
Normal file
@@ -0,0 +1,351 @@
|
||||
use crate::core::Entity;
|
||||
use crate::core::systems::{System, SystemContext};
|
||||
use crate::utils::{Matcher, Time};
|
||||
|
||||
/**
|
||||
* 被动实体系统
|
||||
*
|
||||
* 定义一个被动的实体系统,继承自EntitySystem类。
|
||||
* 被动的实体系统不会对实体进行任何修改,只会被动地接收实体的变化事件。
|
||||
* 主要用于监听、记录或收集数据的场景。
|
||||
*/
|
||||
pub struct PassiveSystem {
|
||||
pub matcher: Option<Matcher>,
|
||||
pub priority: i32,
|
||||
pub enabled: bool,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl PassiveSystem {
|
||||
/**
|
||||
* 创建新的被动系统
|
||||
*/
|
||||
pub fn new(name: String, matcher: Option<Matcher>) -> Self {
|
||||
Self {
|
||||
matcher,
|
||||
priority: 0,
|
||||
enabled: true,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统优先级
|
||||
*/
|
||||
pub fn with_priority(mut self, priority: i32) -> Self {
|
||||
self.priority = priority;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统启用状态
|
||||
*/
|
||||
pub fn with_enabled(mut self, enabled: bool) -> Self {
|
||||
self.enabled = enabled;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统名称
|
||||
*/
|
||||
pub fn get_name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取匹配器
|
||||
*/
|
||||
pub fn get_matcher(&self) -> Option<&Matcher> {
|
||||
self.matcher.as_ref()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否启用
|
||||
*/
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置启用状态
|
||||
*/
|
||||
pub fn set_enabled(&mut self, enabled: bool) {
|
||||
self.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优先级
|
||||
*/
|
||||
pub fn get_priority(&self) -> i32 {
|
||||
self.priority
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置优先级
|
||||
*/
|
||||
pub fn set_priority(&mut self, priority: i32) {
|
||||
self.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统初始化
|
||||
* 子类可以重写此方法进行自定义初始化
|
||||
*/
|
||||
pub fn initialize(&mut self) {
|
||||
// 默认空实现,子类可以重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统更新前调用
|
||||
* 子类可以重写此方法进行预处理
|
||||
*/
|
||||
pub fn before_update(&mut self, _time: &Time) {
|
||||
// 默认空实现,子类可以重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统更新后调用
|
||||
* 子类可以重写此方法进行后处理
|
||||
*/
|
||||
pub fn after_update(&mut self, _time: &Time) {
|
||||
// 默认空实现,子类可以重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统清理
|
||||
* 子类可以重写此方法进行清理工作
|
||||
*/
|
||||
pub fn cleanup(&mut self) {
|
||||
// 默认空实现,子类可以重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体添加通知
|
||||
* 当匹配的实体被添加到系统时调用
|
||||
*/
|
||||
pub fn on_entity_added(&mut self, _entity: &Entity) {
|
||||
// 默认空实现,子类可以重写进行处理
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体移除通知
|
||||
* 当匹配的实体从系统中移除时调用
|
||||
*/
|
||||
pub fn on_entity_removed(&mut self, _entity: &Entity) {
|
||||
// 默认空实现,子类可以重写进行处理
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件添加通知
|
||||
* 当实体添加组件时调用
|
||||
*/
|
||||
pub fn on_component_added(&mut self, _entity: &Entity, _component_type: std::any::TypeId) {
|
||||
// 默认空实现,子类可以重写进行处理
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件移除通知
|
||||
* 当实体移除组件时调用
|
||||
*/
|
||||
pub fn on_component_removed(&mut self, _entity: &Entity, _component_type: std::any::TypeId) {
|
||||
// 默认空实现,子类可以重写进行处理
|
||||
}
|
||||
}
|
||||
|
||||
impl System for PassiveSystem {
|
||||
fn update(&mut self, _context: &mut SystemContext) {
|
||||
// 被动系统不进行任何处理
|
||||
// 所有的业务逻辑都应该在事件处理方法中实现
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.enabled = enabled;
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.priority = order;
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 被动系统构建器
|
||||
* 提供链式调用构建被动系统
|
||||
*/
|
||||
pub struct PassiveSystemBuilder {
|
||||
name: String,
|
||||
matcher: Option<Matcher>,
|
||||
priority: i32,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl PassiveSystemBuilder {
|
||||
/**
|
||||
* 创建新的被动系统构建器
|
||||
*/
|
||||
pub fn new(name: String) -> Self {
|
||||
Self {
|
||||
name,
|
||||
matcher: None,
|
||||
priority: 0,
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置匹配器
|
||||
*/
|
||||
pub fn with_matcher(mut self, matcher: Matcher) -> Self {
|
||||
self.matcher = Some(matcher);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置优先级
|
||||
*/
|
||||
pub fn with_priority(mut self, priority: i32) -> Self {
|
||||
self.priority = priority;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置启用状态
|
||||
*/
|
||||
pub fn with_enabled(mut self, enabled: bool) -> Self {
|
||||
self.enabled = enabled;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建被动系统
|
||||
*/
|
||||
pub fn build(self) -> PassiveSystem {
|
||||
PassiveSystem {
|
||||
name: self.name,
|
||||
matcher: self.matcher,
|
||||
priority: self.priority,
|
||||
enabled: self.enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::core::{Entity, ComponentRegistry};
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_creation() {
|
||||
let system = PassiveSystem::new("TestPassive".to_string(), None);
|
||||
|
||||
assert_eq!(system.get_name(), "TestPassive");
|
||||
assert!(system.enabled());
|
||||
assert_eq!(system.get_priority(), 0);
|
||||
assert!(system.get_matcher().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_builder() {
|
||||
let system = PassiveSystemBuilder::new("TestPassive".to_string())
|
||||
.with_priority(10)
|
||||
.with_enabled(false)
|
||||
.build();
|
||||
|
||||
assert_eq!(system.get_name(), "TestPassive");
|
||||
assert!(!system.enabled());
|
||||
assert_eq!(system.get_priority(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_with_matcher() {
|
||||
let matcher = Matcher::new();
|
||||
let system = PassiveSystemBuilder::new("TestPassive".to_string())
|
||||
.with_matcher(matcher)
|
||||
.build();
|
||||
|
||||
assert!(system.get_matcher().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_update_does_nothing() {
|
||||
use crate::core::systems::{System, SystemContext};
|
||||
use crate::core::EntityManager;
|
||||
use crate::storage::ComponentStorageManager;
|
||||
|
||||
let mut system = PassiveSystem::new("TestPassive".to_string(), None);
|
||||
let mut entity_manager = EntityManager::new();
|
||||
let mut component_storage_manager = ComponentStorageManager::new();
|
||||
let mut context = SystemContext {
|
||||
entity_manager: &mut entity_manager,
|
||||
component_storage_manager: &mut component_storage_manager,
|
||||
};
|
||||
|
||||
// update方法不应该做任何事情
|
||||
system.update(&mut context);
|
||||
|
||||
// 如果没有panic,说明update方法正确地什么都没做
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_properties() {
|
||||
let mut system = PassiveSystem::new("TestPassive".to_string(), None);
|
||||
|
||||
// 测试系统属性
|
||||
assert!(system.enabled());
|
||||
|
||||
system.set_enabled(false);
|
||||
assert!(!system.enabled());
|
||||
|
||||
assert_eq!(system.get_name(), "TestPassive");
|
||||
assert_eq!(system.get_priority(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_lifecycle() {
|
||||
let mut system = PassiveSystem::new("TestPassive".to_string(), None);
|
||||
let time = Time::new();
|
||||
|
||||
// 测试生命周期方法(都应该是安全的空操作)
|
||||
system.initialize();
|
||||
system.before_update(&time);
|
||||
system.after_update(&time);
|
||||
system.cleanup();
|
||||
|
||||
// 如果没有panic,说明所有生命周期方法都正确工作
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_entity_events() {
|
||||
let mut system = PassiveSystem::new("TestPassive".to_string(), None);
|
||||
let mut registry = ComponentRegistry::new();
|
||||
let entity = Entity::new("test_entity".to_string(), 1);
|
||||
|
||||
// 测试实体事件方法(都应该是安全的空操作)
|
||||
system.on_entity_added(&entity);
|
||||
system.on_entity_removed(&entity);
|
||||
system.on_component_added(&entity, std::any::TypeId::of::<String>());
|
||||
system.on_component_removed(&entity, std::any::TypeId::of::<String>());
|
||||
|
||||
// 如果没有panic,说明所有事件处理方法都正确工作
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_passive_system_priority_modification() {
|
||||
let mut system = PassiveSystem::new("TestPassive".to_string(), None);
|
||||
|
||||
assert_eq!(system.get_priority(), 0);
|
||||
|
||||
system.set_priority(100);
|
||||
assert_eq!(system.get_priority(), 100);
|
||||
|
||||
system.set_priority(-50);
|
||||
assert_eq!(system.get_priority(), -50);
|
||||
}
|
||||
}
|
||||
577
packages/core-rust/src/core/query_system.rs
Normal file
577
packages/core-rust/src/core/query_system.rs
Normal file
@@ -0,0 +1,577 @@
|
||||
use crate::core::entity_manager::EntityManager;
|
||||
use crate::utils::{Matcher, QueryCondition, ComponentType};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
/**
|
||||
* 查询结果
|
||||
*/
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct QueryResult {
|
||||
pub entities: Vec<u32>,
|
||||
pub count: usize,
|
||||
pub execution_time: f64,
|
||||
pub from_cache: bool,
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询缓存条目
|
||||
*/
|
||||
struct QueryCacheEntry {
|
||||
entities: Vec<u32>,
|
||||
timestamp: f64,
|
||||
hit_count: u32,
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能实体查询系统
|
||||
* 提供快速的实体查询功能,支持按组件类型等多种方式查询实体
|
||||
*/
|
||||
pub struct QuerySystem {
|
||||
entity_index: EntityIndex,
|
||||
#[allow(dead_code)]
|
||||
index_dirty: bool,
|
||||
query_cache: FxHashMap<String, QueryCacheEntry>,
|
||||
cache_max_size: usize,
|
||||
cache_timeout: f64,
|
||||
query_stats: QueryStats,
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体索引结构
|
||||
*/
|
||||
struct EntityIndex {
|
||||
by_mask: FxHashMap<String, std::collections::HashSet<u32>>,
|
||||
by_tag: FxHashMap<u32, std::collections::HashSet<u32>>,
|
||||
by_name: FxHashMap<String, std::collections::HashSet<u32>>,
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能统计
|
||||
*/
|
||||
struct QueryStats {
|
||||
total_queries: u32,
|
||||
cache_hits: u32,
|
||||
index_hits: u32,
|
||||
linear_scans: u32,
|
||||
}
|
||||
|
||||
impl QuerySystem {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entity_index: EntityIndex {
|
||||
by_mask: FxHashMap::default(),
|
||||
by_tag: FxHashMap::default(),
|
||||
by_name: FxHashMap::default(),
|
||||
},
|
||||
index_dirty: true,
|
||||
query_cache: FxHashMap::default(),
|
||||
cache_max_size: 1000,
|
||||
cache_timeout: 5000.0, // 5秒
|
||||
query_stats: QueryStats {
|
||||
total_queries: 0,
|
||||
cache_hits: 0,
|
||||
index_hits: 0,
|
||||
linear_scans: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体到查询系统
|
||||
* @param entity_id 实体ID
|
||||
* @param entity_manager 实体管理器引用
|
||||
*/
|
||||
pub fn add_entity(&mut self, entity_id: u32, entity_manager: &EntityManager) {
|
||||
if let Some(_entity) = entity_manager.get_entity(entity_id) {
|
||||
self.add_entity_to_indexes(entity_id, entity_manager);
|
||||
self.clear_query_cache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从查询系统移除实体
|
||||
* @param entity_id 实体ID
|
||||
* @param entity_manager 实体管理器引用
|
||||
*/
|
||||
pub fn remove_entity(&mut self, entity_id: u32, entity_manager: &EntityManager) {
|
||||
self.remove_entity_from_indexes(entity_id, entity_manager);
|
||||
self.clear_query_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询包含所有指定组件的实体
|
||||
* @param component_mask 组件位掩码
|
||||
* @param entity_manager 实体管理器引用
|
||||
* @returns 查询结果,包含匹配的实体和性能信息
|
||||
*/
|
||||
pub fn query_all(&mut self, component_mask: u64, entity_manager: &EntityManager) -> QueryResult {
|
||||
let start_time = self.get_current_time();
|
||||
self.query_stats.total_queries += 1;
|
||||
|
||||
let cache_key = format!("all:{}", component_mask);
|
||||
|
||||
// 检查缓存
|
||||
if let Some(cached_entities) = self.get_from_cache(&cache_key) {
|
||||
self.query_stats.cache_hits += 1;
|
||||
let entity_count = cached_entities.len();
|
||||
return QueryResult {
|
||||
entities: cached_entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: true,
|
||||
};
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
let entities = self.execute_mask_query(component_mask, entity_manager);
|
||||
|
||||
// 缓存结果
|
||||
self.add_to_cache(cache_key, &entities);
|
||||
|
||||
let entity_count = entities.len();
|
||||
QueryResult {
|
||||
entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按标签查询实体
|
||||
* @param tag 要查询的标签值
|
||||
* @param entity_manager 实体管理器引用
|
||||
* @returns 查询结果
|
||||
*/
|
||||
pub fn query_by_tag(&mut self, tag: u32, entity_manager: &EntityManager) -> QueryResult {
|
||||
let start_time = self.get_current_time();
|
||||
self.query_stats.total_queries += 1;
|
||||
|
||||
let cache_key = format!("tag:{}", tag);
|
||||
|
||||
if let Some(cached_entities) = self.get_from_cache(&cache_key) {
|
||||
self.query_stats.cache_hits += 1;
|
||||
let entity_count = cached_entities.len();
|
||||
return QueryResult {
|
||||
entities: cached_entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: true,
|
||||
};
|
||||
}
|
||||
|
||||
let entities = entity_manager.get_entities_by_tag(tag);
|
||||
self.add_to_cache(cache_key, &entities);
|
||||
|
||||
let entity_count = entities.len();
|
||||
QueryResult {
|
||||
entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称查询实体
|
||||
* @param name 要查询的实体名称
|
||||
* @param entity_manager 实体管理器引用
|
||||
* @returns 查询结果
|
||||
*/
|
||||
pub fn query_by_name(&mut self, name: &str, entity_manager: &EntityManager) -> QueryResult {
|
||||
let start_time = self.get_current_time();
|
||||
self.query_stats.total_queries += 1;
|
||||
|
||||
let cache_key = format!("name:{}", name);
|
||||
|
||||
if let Some(cached_entities) = self.get_from_cache(&cache_key) {
|
||||
self.query_stats.cache_hits += 1;
|
||||
let entity_count = cached_entities.len();
|
||||
return QueryResult {
|
||||
entities: cached_entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: true,
|
||||
};
|
||||
}
|
||||
|
||||
let entities = if let Some(entity_id) = entity_manager.get_entity_by_name(name) {
|
||||
vec![entity_id]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
self.add_to_cache(cache_key, &entities);
|
||||
|
||||
let entity_count = entities.len();
|
||||
QueryResult {
|
||||
entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行掩码查询
|
||||
*/
|
||||
fn execute_mask_query(&mut self, component_mask: u64, entity_manager: &EntityManager) -> Vec<u32> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for &entity_id in entity_manager.get_all_entity_ids().iter() {
|
||||
let entity_mask = entity_manager.get_component_mask(entity_id);
|
||||
if (entity_mask & component_mask) == component_mask {
|
||||
result.push(entity_id);
|
||||
}
|
||||
}
|
||||
|
||||
self.query_stats.linear_scans += 1;
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 将实体添加到各种索引中
|
||||
*/
|
||||
fn add_entity_to_indexes(&mut self, entity_id: u32, entity_manager: &EntityManager) {
|
||||
if let Some(entity) = entity_manager.get_entity(entity_id) {
|
||||
let mask = entity_manager.get_component_mask(entity_id);
|
||||
let mask_key = mask.to_string();
|
||||
|
||||
self.entity_index
|
||||
.by_mask
|
||||
.entry(mask_key)
|
||||
.or_insert_with(std::collections::HashSet::new)
|
||||
.insert(entity_id);
|
||||
|
||||
self.entity_index
|
||||
.by_tag
|
||||
.entry(entity.tag())
|
||||
.or_insert_with(std::collections::HashSet::new)
|
||||
.insert(entity_id);
|
||||
|
||||
self.entity_index
|
||||
.by_name
|
||||
.entry(entity.name.clone())
|
||||
.or_insert_with(std::collections::HashSet::new)
|
||||
.insert(entity_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从各种索引中移除实体
|
||||
*/
|
||||
fn remove_entity_from_indexes(&mut self, entity_id: u32, entity_manager: &EntityManager) {
|
||||
if let Some(entity) = entity_manager.get_entity(entity_id) {
|
||||
let mask = entity_manager.get_component_mask(entity_id);
|
||||
let mask_key = mask.to_string();
|
||||
|
||||
if let Some(mask_set) = self.entity_index.by_mask.get_mut(&mask_key) {
|
||||
mask_set.remove(&entity_id);
|
||||
if mask_set.is_empty() {
|
||||
self.entity_index.by_mask.remove(&mask_key);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(tag_set) = self.entity_index.by_tag.get_mut(&entity.tag()) {
|
||||
tag_set.remove(&entity_id);
|
||||
if tag_set.is_empty() {
|
||||
self.entity_index.by_tag.remove(&entity.tag());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(name_set) = self.entity_index.by_name.get_mut(&entity.name) {
|
||||
name_set.remove(&entity_id);
|
||||
if name_set.is_empty() {
|
||||
self.entity_index.by_name.remove(&entity.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存获取查询结果
|
||||
*/
|
||||
fn get_from_cache(&mut self, cache_key: &str) -> Option<Vec<u32>> {
|
||||
let current_time = self.get_current_time();
|
||||
|
||||
if let Some(entry) = self.query_cache.get_mut(cache_key) {
|
||||
if current_time - entry.timestamp <= self.cache_timeout {
|
||||
entry.hit_count += 1;
|
||||
return Some(entry.entities.clone());
|
||||
} else {
|
||||
self.query_cache.remove(cache_key);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加查询结果到缓存
|
||||
*/
|
||||
fn add_to_cache(&mut self, cache_key: String, entities: &[u32]) {
|
||||
if self.query_cache.len() >= self.cache_max_size {
|
||||
self.cleanup_cache();
|
||||
}
|
||||
|
||||
self.query_cache.insert(cache_key, QueryCacheEntry {
|
||||
entities: entities.to_vec(),
|
||||
timestamp: self.get_current_time(),
|
||||
hit_count: 0,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理缓存
|
||||
*/
|
||||
fn cleanup_cache(&mut self) {
|
||||
let current_time = self.get_current_time();
|
||||
|
||||
// 移除过期的缓存条目
|
||||
self.query_cache.retain(|_, entry| {
|
||||
current_time - entry.timestamp <= self.cache_timeout
|
||||
});
|
||||
|
||||
// 如果还是太满,移除最少使用的条目
|
||||
if self.query_cache.len() >= self.cache_max_size {
|
||||
let entries: Vec<_> = self.query_cache.iter().map(|(k, v)| (k.clone(), v.hit_count)).collect();
|
||||
let mut sorted_entries = entries;
|
||||
sorted_entries.sort_by_key(|(_, hit_count)| *hit_count);
|
||||
|
||||
let to_remove = (self.cache_max_size as f32 * 0.2) as usize;
|
||||
for (key, _) in sorted_entries.into_iter().take(to_remove) {
|
||||
self.query_cache.remove(&key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有查询缓存
|
||||
*/
|
||||
fn clear_query_cache(&mut self) {
|
||||
self.query_cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(毫秒)
|
||||
*/
|
||||
fn get_current_time(&self) -> f64 {
|
||||
// 在WASM环境中,这将使用js-sys获取时间
|
||||
// 这里使用简化实现,转换为f64毫秒
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as f64
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统统计信息
|
||||
*/
|
||||
/**
|
||||
* 清空查询缓存
|
||||
*/
|
||||
pub fn clear_cache(&mut self) {
|
||||
self.query_cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于Matcher的高级查询
|
||||
*
|
||||
* 使用Matcher描述复杂查询条件,支持all/any/none组合查询
|
||||
*/
|
||||
pub fn query_with_matcher(&mut self, matcher: &Matcher, entity_manager: &EntityManager) -> QueryResult {
|
||||
let start_time = self.get_current_time();
|
||||
|
||||
// 生成查询缓存键
|
||||
let cache_key = self.generate_matcher_cache_key(matcher);
|
||||
|
||||
// 检查缓存
|
||||
if let Some(cached_result) = self.get_from_cache(&cache_key) {
|
||||
let count = cached_result.len();
|
||||
return QueryResult {
|
||||
entities: cached_result,
|
||||
count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: true,
|
||||
};
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
let entities = self.execute_matcher_query(matcher, entity_manager);
|
||||
|
||||
// 添加到缓存
|
||||
self.add_to_cache(cache_key, &entities);
|
||||
|
||||
let entity_count = entities.len();
|
||||
QueryResult {
|
||||
entities,
|
||||
count: entity_count,
|
||||
execution_time: self.get_current_time() - start_time,
|
||||
from_cache: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Matcher查询的核心逻辑
|
||||
*/
|
||||
fn execute_matcher_query(&mut self, matcher: &Matcher, entity_manager: &EntityManager) -> Vec<u32> {
|
||||
let condition = matcher.get_condition();
|
||||
let all_entity_ids = entity_manager.get_all_entity_ids();
|
||||
let mut matching_entities = Vec::new();
|
||||
|
||||
// 遍历所有实体进行匹配
|
||||
for &entity_id in &all_entity_ids {
|
||||
if self.entity_matches_condition(entity_id, condition, entity_manager) {
|
||||
matching_entities.push(entity_id);
|
||||
}
|
||||
}
|
||||
|
||||
self.query_stats.linear_scans += 1;
|
||||
matching_entities
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否匹配查询条件
|
||||
*/
|
||||
fn entity_matches_condition(&self, entity_id: u32, condition: &QueryCondition, entity_manager: &EntityManager) -> bool {
|
||||
let entity = match entity_manager.get_entity(entity_id) {
|
||||
Some(entity) => entity,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// 检查名称条件
|
||||
if let Some(ref name) = condition.name {
|
||||
if &entity.name != name {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查标签条件
|
||||
if let Some(tag) = condition.tag {
|
||||
if entity.tag() != tag {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查单组件条件
|
||||
if let Some(component_type) = condition.component {
|
||||
if !self.entity_has_component_type(entity_id, component_type, entity_manager) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查all条件(必须包含所有指定组件)
|
||||
if !condition.all.is_empty() {
|
||||
for &component_type in &condition.all {
|
||||
if !self.entity_has_component_type(entity_id, component_type, entity_manager) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查any条件(必须包含至少一个指定组件)
|
||||
if !condition.any.is_empty() {
|
||||
let has_any = condition.any.iter()
|
||||
.any(|&component_type| self.entity_has_component_type(entity_id, component_type, entity_manager));
|
||||
if !has_any {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查none条件(不能包含任何指定组件)
|
||||
if !condition.none.is_empty() {
|
||||
for &component_type in &condition.none {
|
||||
if self.entity_has_component_type(entity_id, component_type, entity_manager) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否有指定类型的组件
|
||||
* 这里需要EntityManager提供按TypeId查询组件的功能
|
||||
*/
|
||||
fn entity_has_component_type(&self, entity_id: u32, component_type: ComponentType, _entity_manager: &EntityManager) -> bool {
|
||||
// TODO: 这里需要EntityManager支持按TypeId查询组件
|
||||
// 目前先返回false作为占位实现
|
||||
// 实际实现需要EntityManager提供get_component_by_type_id方法
|
||||
let _ = (entity_id, component_type);
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* 为Matcher生成缓存键
|
||||
*/
|
||||
fn generate_matcher_cache_key(&self, matcher: &Matcher) -> String {
|
||||
let condition = matcher.get_condition();
|
||||
let mut key_parts = Vec::new();
|
||||
|
||||
// 添加各种条件到键中
|
||||
if !condition.all.is_empty() {
|
||||
let type_ids: Vec<String> = condition.all.iter()
|
||||
.map(|t| format!("{:?}", t))
|
||||
.collect();
|
||||
key_parts.push(format!("all:{}", type_ids.join(",")));
|
||||
}
|
||||
|
||||
if !condition.any.is_empty() {
|
||||
let type_ids: Vec<String> = condition.any.iter()
|
||||
.map(|t| format!("{:?}", t))
|
||||
.collect();
|
||||
key_parts.push(format!("any:{}", type_ids.join(",")));
|
||||
}
|
||||
|
||||
if !condition.none.is_empty() {
|
||||
let type_ids: Vec<String> = condition.none.iter()
|
||||
.map(|t| format!("{:?}", t))
|
||||
.collect();
|
||||
key_parts.push(format!("none:{}", type_ids.join(",")));
|
||||
}
|
||||
|
||||
if let Some(tag) = condition.tag {
|
||||
key_parts.push(format!("tag:{}", tag));
|
||||
}
|
||||
|
||||
if let Some(ref name) = condition.name {
|
||||
key_parts.push(format!("name:{}", name));
|
||||
}
|
||||
|
||||
if let Some(component) = condition.component {
|
||||
key_parts.push(format!("comp:{:?}", component));
|
||||
}
|
||||
|
||||
format!("matcher:{}", key_parts.join("|"))
|
||||
}
|
||||
|
||||
pub fn get_stats(&self) -> QuerySystemStats {
|
||||
let cache_hit_rate = if self.query_stats.total_queries > 0 {
|
||||
(self.query_stats.cache_hits as f32 / self.query_stats.total_queries as f32) * 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
QuerySystemStats {
|
||||
total_queries: self.query_stats.total_queries,
|
||||
cache_hits: self.query_stats.cache_hits,
|
||||
index_hits: self.query_stats.index_hits,
|
||||
linear_scans: self.query_stats.linear_scans,
|
||||
cache_hit_rate,
|
||||
cache_size: self.query_cache.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询系统统计信息
|
||||
*/
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct QuerySystemStats {
|
||||
pub total_queries: u32,
|
||||
pub cache_hits: u32,
|
||||
pub index_hits: u32,
|
||||
pub linear_scans: u32,
|
||||
pub cache_hit_rate: f32,
|
||||
pub cache_size: usize,
|
||||
}
|
||||
403
packages/core-rust/src/core/scene.rs
Normal file
403
packages/core-rust/src/core/scene.rs
Normal file
@@ -0,0 +1,403 @@
|
||||
use crate::core::entity_manager::EntityManager;
|
||||
use crate::core::query_system::QuerySystem;
|
||||
use crate::core::systems::{System, SystemManager, SystemContext};
|
||||
use crate::storage::component_storage::ComponentStorageManager;
|
||||
use crate::utils::time::Time;
|
||||
|
||||
/**
|
||||
* 场景管理器
|
||||
*
|
||||
* Scene是ECS系统中的顶层容器,管理所有实体、组件和系统
|
||||
* 提供统一的实体管理、组件存储和查询功能
|
||||
*/
|
||||
pub struct Scene {
|
||||
/// 场景名称
|
||||
name: String,
|
||||
|
||||
/// 是否激活状态
|
||||
active: bool,
|
||||
|
||||
/// 实体管理器
|
||||
entity_manager: EntityManager,
|
||||
|
||||
/// 组件存储管理器
|
||||
component_storage_manager: ComponentStorageManager,
|
||||
|
||||
/// 查询系统
|
||||
query_system: QuerySystem,
|
||||
|
||||
/// 系统管理器
|
||||
system_manager: SystemManager,
|
||||
|
||||
/// 场景统计信息
|
||||
stats: SceneStats,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
/**
|
||||
* 创建新场景
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: String::new(),
|
||||
active: true,
|
||||
entity_manager: EntityManager::new(),
|
||||
component_storage_manager: ComponentStorageManager::new(),
|
||||
query_system: QuerySystem::new(),
|
||||
system_manager: SystemManager::new(),
|
||||
stats: SceneStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带名称的新场景
|
||||
*/
|
||||
pub fn new_with_name(name: String) -> Self {
|
||||
Self {
|
||||
name,
|
||||
active: true,
|
||||
entity_manager: EntityManager::new(),
|
||||
component_storage_manager: ComponentStorageManager::new(),
|
||||
query_system: QuerySystem::new(),
|
||||
system_manager: SystemManager::new(),
|
||||
stats: SceneStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 场景属性 ==========
|
||||
|
||||
/**
|
||||
* 获取场景名称
|
||||
*/
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置场景名称
|
||||
*/
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活状态
|
||||
*/
|
||||
pub fn active(&self) -> bool {
|
||||
self.active
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置激活状态
|
||||
*/
|
||||
pub fn set_active(&mut self, active: bool) {
|
||||
self.active = active;
|
||||
}
|
||||
|
||||
// ========== 实体管理 ==========
|
||||
|
||||
/**
|
||||
* 创建实体
|
||||
*/
|
||||
pub fn create_entity(&mut self, name: Option<String>) -> u32 {
|
||||
let entity_id = self.entity_manager.create_entity(name);
|
||||
self.stats.total_entities_created += 1;
|
||||
entity_id
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建实体
|
||||
*/
|
||||
pub fn create_entities_batch(&mut self, count: u32, name_prefix: Option<String>) -> Vec<u32> {
|
||||
let entities = self.entity_manager.create_entities_batch(count, name_prefix);
|
||||
self.stats.total_entities_created += count as u64;
|
||||
entities
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实体
|
||||
*/
|
||||
pub fn destroy_entity(&mut self, entity_id: u32) -> bool {
|
||||
if self.entity_manager.destroy_entity(entity_id) {
|
||||
// 清理组件存储
|
||||
self.component_storage_manager.remove_all_components(entity_id);
|
||||
self.stats.total_entities_destroyed += 1;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体管理器引用
|
||||
*/
|
||||
pub fn entity_manager(&self) -> &EntityManager {
|
||||
&self.entity_manager
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体管理器可变引用
|
||||
*/
|
||||
pub fn entity_manager_mut(&mut self) -> &mut EntityManager {
|
||||
&mut self.entity_manager
|
||||
}
|
||||
|
||||
// ========== 组件管理 ==========
|
||||
|
||||
/**
|
||||
* 获取组件存储管理器引用
|
||||
*/
|
||||
pub fn component_storage_manager(&self) -> &ComponentStorageManager {
|
||||
&self.component_storage_manager
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件存储管理器可变引用
|
||||
*/
|
||||
pub fn component_storage_manager_mut(&mut self) -> &mut ComponentStorageManager {
|
||||
&mut self.component_storage_manager
|
||||
}
|
||||
|
||||
// ========== 查询系统 ==========
|
||||
|
||||
/**
|
||||
* 获取查询系统引用
|
||||
*/
|
||||
pub fn query_system(&self) -> &QuerySystem {
|
||||
&self.query_system
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询系统可变引用
|
||||
*/
|
||||
pub fn query_system_mut(&mut self) -> &mut QuerySystem {
|
||||
&mut self.query_system
|
||||
}
|
||||
|
||||
// ========== 系统管理 ==========
|
||||
|
||||
/**
|
||||
* 添加系统
|
||||
*/
|
||||
pub fn add_system<T: System + 'static>(&mut self, system: T) {
|
||||
self.system_manager.add_system(system);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除系统
|
||||
*/
|
||||
pub fn remove_system<T: System + 'static>(&mut self) -> bool {
|
||||
self.system_manager.remove_system::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统
|
||||
*/
|
||||
pub fn get_system<T: System + 'static>(&self) -> Option<&T> {
|
||||
self.system_manager.get_system::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变系统
|
||||
*/
|
||||
pub fn get_system_mut<T: System + 'static>(&mut self) -> Option<&mut T> {
|
||||
self.system_manager.get_system_mut::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统管理器引用
|
||||
*/
|
||||
pub fn system_manager(&self) -> &SystemManager {
|
||||
&self.system_manager
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统管理器可变引用
|
||||
*/
|
||||
pub fn system_manager_mut(&mut self) -> &mut SystemManager {
|
||||
&mut self.system_manager
|
||||
}
|
||||
|
||||
// ========== 场景生命周期 ==========
|
||||
|
||||
/**
|
||||
* 初始化场景
|
||||
*/
|
||||
pub fn initialize(&mut self) {
|
||||
// 创建系统上下文并初始化系统管理器
|
||||
let mut context = SystemContext {
|
||||
entity_manager: &mut self.entity_manager,
|
||||
component_storage_manager: &mut self.component_storage_manager,
|
||||
};
|
||||
self.system_manager.initialize(&mut context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新场景
|
||||
*/
|
||||
pub fn update(&mut self, delta_time: f64) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新时间
|
||||
Time::update(delta_time);
|
||||
|
||||
// 创建系统上下文
|
||||
let mut context = SystemContext {
|
||||
entity_manager: &mut self.entity_manager,
|
||||
component_storage_manager: &mut self.component_storage_manager,
|
||||
};
|
||||
|
||||
// 更新所有系统
|
||||
self.system_manager.update(&mut context);
|
||||
|
||||
// 重新创建系统上下文(避免借用检查问题)
|
||||
let mut context = SystemContext {
|
||||
entity_manager: &mut self.entity_manager,
|
||||
component_storage_manager: &mut self.component_storage_manager,
|
||||
};
|
||||
|
||||
// 后更新系统
|
||||
self.system_manager.late_update(&mut context);
|
||||
|
||||
// 更新所有激活的实体(在系统更新完成后)
|
||||
let active_entities = self.entity_manager.get_all_entity_ids();
|
||||
for entity_id in active_entities {
|
||||
if let Some(entity) = self.entity_manager.get_entity_mut(entity_id) {
|
||||
entity.update();
|
||||
}
|
||||
}
|
||||
|
||||
self.stats.total_updates += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空场景
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
// 创建系统上下文并清理系统
|
||||
let mut context = SystemContext {
|
||||
entity_manager: &mut self.entity_manager,
|
||||
component_storage_manager: &mut self.component_storage_manager,
|
||||
};
|
||||
self.system_manager.cleanup(&mut context);
|
||||
|
||||
self.entity_manager = EntityManager::new();
|
||||
self.component_storage_manager.clear();
|
||||
self.query_system.clear_cache();
|
||||
self.system_manager = SystemManager::new();
|
||||
self.stats = SceneStats::default();
|
||||
}
|
||||
|
||||
// ========== 统计信息 ==========
|
||||
|
||||
/**
|
||||
* 获取场景统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> &SceneStats {
|
||||
&self.stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体数量
|
||||
*/
|
||||
pub fn entity_count(&self) -> usize {
|
||||
self.entity_manager.entity_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活实体数量
|
||||
*/
|
||||
pub fn active_entity_count(&self) -> usize {
|
||||
self.entity_manager.active_entity_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试信息
|
||||
*/
|
||||
pub fn get_debug_info(&self) -> String {
|
||||
format!(
|
||||
"{{\"name\":\"{}\",\"active\":{},\"entity_count\":{},\"active_entity_count\":{},\"total_entities_created\":{},\"total_entities_destroyed\":{},\"total_updates\":{}}}",
|
||||
self.name,
|
||||
self.active,
|
||||
self.entity_count(),
|
||||
self.active_entity_count(),
|
||||
self.stats.total_entities_created,
|
||||
self.stats.total_entities_destroyed,
|
||||
self.stats.total_updates
|
||||
)
|
||||
}
|
||||
|
||||
// ========== SceneBuilder支持方法 ==========
|
||||
|
||||
/**
|
||||
* 添加实体到场景
|
||||
*/
|
||||
pub fn add_entity(&mut self, entity: crate::core::Entity) {
|
||||
self.entity_manager.add_entity(entity);
|
||||
self.stats.total_entities_created += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加系统到场景(Box版本)
|
||||
*/
|
||||
pub fn add_system_boxed(&mut self, system: Box<dyn System>) {
|
||||
self.system_manager.add_system_boxed(system);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统数量
|
||||
*/
|
||||
pub fn system_count(&self) -> usize {
|
||||
self.system_manager.system_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置启用状态
|
||||
*/
|
||||
pub fn set_enabled(&mut self, enabled: bool) {
|
||||
self.active = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否启用
|
||||
*/
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.active
|
||||
}
|
||||
|
||||
/**
|
||||
* 预留容量
|
||||
*/
|
||||
pub fn reserve_capacity(&mut self, entity_capacity: usize, system_capacity: usize) {
|
||||
self.entity_manager.reserve_capacity(entity_capacity);
|
||||
self.system_manager.reserve_capacity(system_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景统计信息
|
||||
*/
|
||||
#[derive(Default)]
|
||||
pub struct SceneStats {
|
||||
/// 创建的实体总数
|
||||
pub total_entities_created: u64,
|
||||
|
||||
/// 销毁的实体总数
|
||||
pub total_entities_destroyed: u64,
|
||||
|
||||
/// 更新总次数
|
||||
pub total_updates: u64,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Scene {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Scene")
|
||||
.field("name", &self.name)
|
||||
.field("active", &self.active)
|
||||
.field("entity_count", &self.entity_count())
|
||||
.field("active_entity_count", &self.active_entity_count())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
598
packages/core-rust/src/core/scene_builder.rs
Normal file
598
packages/core-rust/src/core/scene_builder.rs
Normal file
@@ -0,0 +1,598 @@
|
||||
use crate::core::{Scene, Entity, System};
|
||||
use crate::core::fluent_api::EntityBuilder;
|
||||
|
||||
/**
|
||||
* 场景构建器
|
||||
* 提供流式API创建和配置场景
|
||||
*/
|
||||
pub struct SceneBuilder {
|
||||
scene: Scene,
|
||||
}
|
||||
|
||||
impl SceneBuilder {
|
||||
/**
|
||||
* 创建场景构建器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scene: Scene::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置场景名称
|
||||
*/
|
||||
pub fn named(mut self, name: &str) -> Self {
|
||||
self.scene.set_name(name.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置场景是否启用
|
||||
*/
|
||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||
self.scene.set_enabled(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体
|
||||
*/
|
||||
pub fn with_entity(mut self, entity: Entity) -> Self {
|
||||
self.scene.add_entity(entity);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加实体
|
||||
*/
|
||||
pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {
|
||||
for entity in entities {
|
||||
self.scene.add_entity(entity);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用实体构建器添加实体
|
||||
*/
|
||||
pub fn with_entity_builder<F>(mut self, builder_fn: F) -> Self
|
||||
where
|
||||
F: FnOnce(EntityBuilder) -> EntityBuilder,
|
||||
{
|
||||
let builder = EntityBuilder::new("", 0);
|
||||
let configured_builder = builder_fn(builder);
|
||||
let entity = configured_builder.build();
|
||||
self.scene.add_entity(entity);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量使用实体构建器添加实体
|
||||
*/
|
||||
pub fn with_entity_builders<F>(mut self, count: usize, builder_fn: F) -> Self
|
||||
where
|
||||
F: Fn(usize, EntityBuilder) -> EntityBuilder,
|
||||
{
|
||||
for i in 0..count {
|
||||
let builder = EntityBuilder::new("", 0);
|
||||
let configured_builder = builder_fn(i, builder);
|
||||
let entity = configured_builder.build();
|
||||
self.scene.add_entity(entity);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加系统
|
||||
*/
|
||||
pub fn with_system(mut self, system: Box<dyn System>) -> Self {
|
||||
self.scene.add_system_boxed(system);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加系统
|
||||
*/
|
||||
pub fn with_systems(mut self, systems: Vec<Box<dyn System>>) -> Self {
|
||||
for system in systems {
|
||||
self.scene.add_system_boxed(system);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性添加实体
|
||||
*/
|
||||
pub fn with_entity_if(mut self, condition: bool, entity: Entity) -> Self {
|
||||
if condition {
|
||||
self.scene.add_entity(entity);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性添加系统
|
||||
*/
|
||||
pub fn with_system_if(mut self, condition: bool, system: Box<dyn System>) -> Self {
|
||||
if condition {
|
||||
self.scene.add_system_boxed(system);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置函数配置场景
|
||||
*/
|
||||
pub fn configure<F>(mut self, configurator: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut Scene),
|
||||
{
|
||||
configurator(&mut self.scene);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件性配置场景
|
||||
*/
|
||||
pub fn configure_if<F>(mut self, condition: bool, configurator: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut Scene),
|
||||
{
|
||||
if condition {
|
||||
configurator(&mut self.scene);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建简单实体
|
||||
*/
|
||||
pub fn with_simple_entities(mut self, count: usize, name_prefix: &str) -> Self {
|
||||
for i in 0..count {
|
||||
let mut entity = Entity::new(0); // ID将由EntityManager分配
|
||||
entity.set_name(format!("{}{}", name_prefix, i));
|
||||
self.scene.add_entity(entity);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用预定义场景模板
|
||||
*/
|
||||
pub fn from_template(self, template: SceneTemplate) -> Self {
|
||||
match template {
|
||||
SceneTemplate::Empty => self,
|
||||
SceneTemplate::Basic => {
|
||||
self.named("Basic Scene")
|
||||
.enabled(true)
|
||||
.with_simple_entities(10, "Entity_")
|
||||
},
|
||||
SceneTemplate::Testing => {
|
||||
self.named("Test Scene")
|
||||
.enabled(true)
|
||||
.with_simple_entities(5, "TestEntity_")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置场景容量预估
|
||||
*/
|
||||
pub fn with_capacity(mut self, entity_capacity: usize, system_capacity: usize) -> Self {
|
||||
self.scene.reserve_capacity(entity_capacity, system_capacity);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证场景配置
|
||||
*/
|
||||
pub fn validate(self) -> Result<Self, String> {
|
||||
// 基本验证
|
||||
if self.scene.name().is_empty() {
|
||||
return Err("Scene name cannot be empty".to_string());
|
||||
}
|
||||
|
||||
if self.scene.entity_count() == 0 {
|
||||
return Err("Scene must have at least one entity".to_string());
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建并返回场景
|
||||
*/
|
||||
pub fn build(self) -> Scene {
|
||||
self.scene
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并构建场景
|
||||
*/
|
||||
pub fn validate_and_build(self) -> Result<Scene, String> {
|
||||
self.validate().map(|builder| builder.build())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前场景的统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> SceneBuilderStats {
|
||||
SceneBuilderStats {
|
||||
entity_count: self.scene.entity_count(),
|
||||
system_count: self.scene.system_count(),
|
||||
is_enabled: self.scene.is_enabled(),
|
||||
name_length: self.scene.name().len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景模板枚举
|
||||
* 提供预定义的场景配置
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SceneTemplate {
|
||||
Empty,
|
||||
Basic,
|
||||
Testing,
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景构建器统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SceneBuilderStats {
|
||||
pub entity_count: usize,
|
||||
pub system_count: usize,
|
||||
pub is_enabled: bool,
|
||||
pub name_length: usize,
|
||||
}
|
||||
|
||||
impl SceneBuilderStats {
|
||||
/**
|
||||
* 检查场景是否为空
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.entity_count == 0 && self.system_count == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查场景是否已配置
|
||||
*/
|
||||
pub fn is_configured(&self) -> bool {
|
||||
self.entity_count > 0 || self.system_count > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景复杂度评分
|
||||
*/
|
||||
pub fn complexity_score(&self) -> f64 {
|
||||
(self.entity_count as f64 * 1.0) + (self.system_count as f64 * 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景构建器工厂
|
||||
* 提供创建各种场景构建器的便捷方法
|
||||
*/
|
||||
pub struct SceneBuilderFactory;
|
||||
|
||||
impl SceneBuilderFactory {
|
||||
/**
|
||||
* 创建空场景构建器
|
||||
*/
|
||||
pub fn empty() -> SceneBuilder {
|
||||
SceneBuilder::new()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建基础场景构建器
|
||||
*/
|
||||
pub fn basic(name: &str) -> SceneBuilder {
|
||||
SceneBuilder::new()
|
||||
.named(name)
|
||||
.enabled(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建测试场景构建器
|
||||
*/
|
||||
pub fn for_testing() -> SceneBuilder {
|
||||
SceneBuilder::new()
|
||||
.from_template(SceneTemplate::Testing)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定容量的场景构建器
|
||||
*/
|
||||
pub fn with_capacity(entity_capacity: usize, system_capacity: usize) -> SceneBuilder {
|
||||
SceneBuilder::new()
|
||||
.with_capacity(entity_capacity, system_capacity)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从模板创建场景构建器
|
||||
*/
|
||||
pub fn from_template(template: SceneTemplate) -> SceneBuilder {
|
||||
SceneBuilder::new().from_template(template)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景构建器管理器
|
||||
* 管理多个场景构建器的全局统计
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct SceneBuilderManager {
|
||||
total_scenes_built: u64,
|
||||
total_entities_created: u64,
|
||||
total_systems_added: u64,
|
||||
validation_failures: u64,
|
||||
}
|
||||
|
||||
impl SceneBuilderManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_scenes_built: 0,
|
||||
total_entities_created: 0,
|
||||
total_systems_added: 0,
|
||||
validation_failures: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录场景构建
|
||||
*/
|
||||
pub fn record_scene_built(&mut self, stats: &SceneBuilderStats) {
|
||||
self.total_scenes_built += 1;
|
||||
self.total_entities_created += stats.entity_count as u64;
|
||||
self.total_systems_added += stats.system_count as u64;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录验证失败
|
||||
*/
|
||||
pub fn record_validation_failure(&mut self) {
|
||||
self.validation_failures += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置统计信息
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.total_scenes_built = 0;
|
||||
self.total_entities_created = 0;
|
||||
self.total_systems_added = 0;
|
||||
self.validation_failures = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平均每个场景的实体数
|
||||
*/
|
||||
pub fn average_entities_per_scene(&self) -> f64 {
|
||||
if self.total_scenes_built == 0 {
|
||||
0.0
|
||||
} else {
|
||||
self.total_entities_created as f64 / self.total_scenes_built as f64
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平均每个场景的系统数
|
||||
*/
|
||||
pub fn average_systems_per_scene(&self) -> f64 {
|
||||
if self.total_scenes_built == 0 {
|
||||
0.0
|
||||
} else {
|
||||
self.total_systems_added as f64 / self.total_scenes_built as f64
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取构建成功率
|
||||
*/
|
||||
pub fn success_rate(&self) -> f64 {
|
||||
let total_attempts = self.total_scenes_built + self.validation_failures;
|
||||
if total_attempts == 0 {
|
||||
1.0
|
||||
} else {
|
||||
self.total_scenes_built as f64 / total_attempts as f64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::Any;
|
||||
use crate::core::systems::SystemContext;
|
||||
|
||||
// 测试用的简单系统
|
||||
struct TestSystem {
|
||||
enabled: bool,
|
||||
update_order: i32,
|
||||
}
|
||||
|
||||
impl TestSystem {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl System for TestSystem {
|
||||
fn initialize(&mut self, _context: &mut SystemContext) {}
|
||||
fn update(&mut self, _context: &mut SystemContext) {}
|
||||
fn late_update(&mut self, _context: &mut SystemContext) {}
|
||||
fn cleanup(&mut self, _context: &mut SystemContext) {}
|
||||
fn enabled(&self) -> bool { self.enabled }
|
||||
fn set_enabled(&mut self, enabled: bool) { self.enabled = enabled; }
|
||||
fn name(&self) -> &str { "TestSystem" }
|
||||
fn update_order(&self) -> i32 { self.update_order }
|
||||
fn set_update_order(&mut self, order: i32) { self.update_order = order; }
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_basic() {
|
||||
let scene = SceneBuilder::new()
|
||||
.named("Test Scene")
|
||||
.enabled(true)
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.name(), "Test Scene");
|
||||
assert!(scene.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_with_entities() {
|
||||
let entity1 = Entity::new(1);
|
||||
let entity2 = Entity::new(2);
|
||||
|
||||
let scene = SceneBuilder::new()
|
||||
.with_entity(entity1)
|
||||
.with_entity(entity2)
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.entity_count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_with_simple_entities() {
|
||||
let scene = SceneBuilder::new()
|
||||
.with_simple_entities(5, "Entity_")
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.entity_count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_with_systems() {
|
||||
let system = Box::new(TestSystem::new());
|
||||
|
||||
let scene = SceneBuilder::new()
|
||||
.with_system(system)
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.system_count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_conditional() {
|
||||
let entity = Entity::new(1);
|
||||
let system = Box::new(TestSystem::new());
|
||||
|
||||
let scene = SceneBuilder::new()
|
||||
.with_entity_if(true, entity)
|
||||
.with_system_if(false, system)
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.entity_count(), 1);
|
||||
assert_eq!(scene.system_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_configure() {
|
||||
let scene = SceneBuilder::new()
|
||||
.configure(|scene| {
|
||||
scene.set_name("Configured Scene".to_string());
|
||||
})
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.name(), "Configured Scene");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_from_template() {
|
||||
let scene = SceneBuilder::new()
|
||||
.from_template(SceneTemplate::Basic)
|
||||
.build();
|
||||
|
||||
assert_eq!(scene.name(), "Basic Scene");
|
||||
assert_eq!(scene.entity_count(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_validation() {
|
||||
// 验证失败 - 空名称
|
||||
let result1 = SceneBuilder::new()
|
||||
.validate_and_build();
|
||||
assert!(result1.is_err());
|
||||
|
||||
// 验证失败 - 无实体
|
||||
let result2 = SceneBuilder::new()
|
||||
.named("Test")
|
||||
.validate_and_build();
|
||||
assert!(result2.is_err());
|
||||
|
||||
// 验证成功
|
||||
let result3 = SceneBuilder::new()
|
||||
.named("Test")
|
||||
.with_simple_entities(1, "Entity_")
|
||||
.validate_and_build();
|
||||
assert!(result3.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_stats() {
|
||||
let builder = SceneBuilder::new()
|
||||
.named("Test Scene")
|
||||
.with_simple_entities(3, "Entity_")
|
||||
.with_system(Box::new(TestSystem::new()));
|
||||
|
||||
let stats = builder.get_stats();
|
||||
assert_eq!(stats.entity_count, 3);
|
||||
assert_eq!(stats.system_count, 1);
|
||||
assert!(!stats.is_empty());
|
||||
assert!(stats.is_configured());
|
||||
assert_eq!(stats.complexity_score(), 5.0); // 3*1 + 1*2
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_factory() {
|
||||
let empty_scene = SceneBuilderFactory::empty().build();
|
||||
assert_eq!(empty_scene.entity_count(), 0);
|
||||
|
||||
let basic_scene = SceneBuilderFactory::basic("Test").build();
|
||||
assert_eq!(basic_scene.name(), "Test");
|
||||
|
||||
let test_scene = SceneBuilderFactory::for_testing().build();
|
||||
assert_eq!(test_scene.name(), "Test Scene");
|
||||
assert_eq!(test_scene.entity_count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_builder_manager() {
|
||||
let mut manager = SceneBuilderManager::new();
|
||||
|
||||
let stats1 = SceneBuilderStats {
|
||||
entity_count: 5,
|
||||
system_count: 2,
|
||||
is_enabled: true,
|
||||
name_length: 10,
|
||||
};
|
||||
|
||||
let stats2 = SceneBuilderStats {
|
||||
entity_count: 3,
|
||||
system_count: 1,
|
||||
is_enabled: true,
|
||||
name_length: 8,
|
||||
};
|
||||
|
||||
manager.record_scene_built(&stats1);
|
||||
manager.record_scene_built(&stats2);
|
||||
manager.record_validation_failure();
|
||||
|
||||
assert_eq!(manager.total_scenes_built, 2);
|
||||
assert_eq!(manager.total_entities_created, 8);
|
||||
assert_eq!(manager.total_systems_added, 3);
|
||||
assert_eq!(manager.validation_failures, 1);
|
||||
assert_eq!(manager.average_entities_per_scene(), 4.0);
|
||||
assert_eq!(manager.average_systems_per_scene(), 1.5);
|
||||
assert!((manager.success_rate() - 0.6666666666666666).abs() < 0.0001);
|
||||
}
|
||||
}
|
||||
521
packages/core-rust/src/core/systems.rs
Normal file
521
packages/core-rust/src/core/systems.rs
Normal file
@@ -0,0 +1,521 @@
|
||||
use crate::core::entity::Entity;
|
||||
use crate::core::entity_manager::EntityManager;
|
||||
use crate::storage::component_storage::ComponentStorageManager;
|
||||
use crate::utils::time::Time;
|
||||
use std::any::Any;
|
||||
|
||||
/**
|
||||
* 系统上下文
|
||||
* 提供系统执行时需要的各种管理器引用
|
||||
*/
|
||||
pub struct SystemContext<'a> {
|
||||
pub entity_manager: &'a mut EntityManager,
|
||||
pub component_storage_manager: &'a mut ComponentStorageManager,
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统基础trait
|
||||
* 定义ECS系统的基本接口
|
||||
*/
|
||||
pub trait System: Send + Sync {
|
||||
/**
|
||||
* 系统初始化
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
fn initialize(&mut self, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统更新
|
||||
*/
|
||||
fn update(&mut self, context: &mut SystemContext);
|
||||
|
||||
/**
|
||||
* 系统后更新(在所有update完成后调用)
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
fn late_update(&mut self, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统销毁清理
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
fn cleanup(&mut self, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统更新顺序
|
||||
*/
|
||||
fn update_order(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统更新顺序
|
||||
*/
|
||||
fn set_update_order(&mut self, order: i32);
|
||||
|
||||
/**
|
||||
* 获取系统启用状态
|
||||
*/
|
||||
fn enabled(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统启用状态
|
||||
*/
|
||||
fn set_enabled(&mut self, enabled: bool);
|
||||
|
||||
/**
|
||||
* 获取系统名称
|
||||
*/
|
||||
fn name(&self) -> &str {
|
||||
"System"
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Any以支持动态转换
|
||||
*/
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/**
|
||||
* 转换为可变Any以支持动态转换
|
||||
*/
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体系统基类
|
||||
* 用于处理一组符合特定条件的实体
|
||||
*/
|
||||
pub struct EntitySystem {
|
||||
update_order: i32,
|
||||
enabled: bool,
|
||||
name: String,
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl EntitySystem {
|
||||
pub fn new(name: String) -> Self {
|
||||
Self {
|
||||
update_order: 0,
|
||||
enabled: true,
|
||||
name,
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否需要处理
|
||||
*/
|
||||
pub fn check_processing(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理实体列表
|
||||
*/
|
||||
pub fn process(&mut self, entities: &[&Entity], context: &mut SystemContext) {
|
||||
if !self.check_processing() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.process_entities(entities, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理实体的具体实现(由子类重写)
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn process_entities(&mut self, entities: &[&Entity], context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体ID列表处理实体
|
||||
* 子类可以重写这个方法实现自定义的实体处理逻辑
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn process_entity_ids(&mut self, entity_ids: &[u32], context: &mut SystemContext) {
|
||||
// 默认空实现,由子类根据需要重写
|
||||
// 这样避免了借用检查问题,因为子类可以自己决定如何访问实体
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个实体(由子类重写)
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn process_single_entity(&mut self, entity: &Entity, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统初始化回调
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn on_initialize(&mut self, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体添加到系统时的回调
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn on_entity_added(&mut self, entity: &Entity, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体从系统移除时的回调
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn on_entity_removed(&mut self, entity: &Entity, context: &mut SystemContext) {
|
||||
// 默认空实现
|
||||
}
|
||||
}
|
||||
|
||||
impl System for EntitySystem {
|
||||
fn initialize(&mut self, context: &mut SystemContext) {
|
||||
if !self.initialized {
|
||||
self.on_initialize(context);
|
||||
self.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, context: &mut SystemContext) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先获取所有实体ID
|
||||
let entity_ids = context.entity_manager.get_all_entity_ids();
|
||||
|
||||
// 然后直接处理,避免同时持有不可变和可变引用
|
||||
self.process_entity_ids(&entity_ids, context);
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.update_order = order;
|
||||
}
|
||||
|
||||
fn update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.enabled = enabled;
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理系统
|
||||
* 每帧调用processSystem方法
|
||||
*/
|
||||
pub struct ProcessingSystem {
|
||||
base: EntitySystem,
|
||||
}
|
||||
|
||||
impl ProcessingSystem {
|
||||
pub fn new(name: String) -> Self {
|
||||
Self {
|
||||
base: EntitySystem::new(name),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理系统的具体方法,由子类实现
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn process_system(&mut self, context: &mut SystemContext) {
|
||||
// 默认空实现,由子类重写
|
||||
}
|
||||
}
|
||||
|
||||
impl System for ProcessingSystem {
|
||||
fn initialize(&mut self, context: &mut SystemContext) {
|
||||
self.base.initialize(context);
|
||||
}
|
||||
|
||||
fn update(&mut self, context: &mut SystemContext) {
|
||||
if self.base.enabled() {
|
||||
self.process_system(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.base.set_update_order(order);
|
||||
}
|
||||
|
||||
fn update_order(&self) -> i32 {
|
||||
self.base.update_order()
|
||||
}
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
self.base.enabled()
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.base.set_enabled(enabled);
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
self.base.name()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 间隔系统
|
||||
* 按指定时间间隔执行处理
|
||||
*/
|
||||
pub struct IntervalSystem {
|
||||
base: EntitySystem,
|
||||
interval: f64,
|
||||
accumulator: f64,
|
||||
}
|
||||
|
||||
impl IntervalSystem {
|
||||
pub fn new(name: String, interval: f64) -> Self {
|
||||
Self {
|
||||
base: EntitySystem::new(name),
|
||||
interval,
|
||||
accumulator: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否应该处理
|
||||
*/
|
||||
fn should_process(&mut self) -> bool {
|
||||
if !self.base.enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.accumulator += Time::delta_time();
|
||||
|
||||
if self.accumulator >= self.interval {
|
||||
self.accumulator -= self.interval;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 间隔处理方法,由子类实现
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn process_interval(&mut self, context: &mut SystemContext) {
|
||||
// 默认空实现,由子类重写
|
||||
}
|
||||
}
|
||||
|
||||
impl System for IntervalSystem {
|
||||
fn initialize(&mut self, context: &mut SystemContext) {
|
||||
self.base.initialize(context);
|
||||
}
|
||||
|
||||
fn update(&mut self, context: &mut SystemContext) {
|
||||
if self.should_process() {
|
||||
self.process_interval(context);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.base.set_update_order(order);
|
||||
}
|
||||
|
||||
fn update_order(&self) -> i32 {
|
||||
self.base.update_order()
|
||||
}
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
self.base.enabled()
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.base.set_enabled(enabled);
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
self.base.name()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统管理器
|
||||
* 管理所有系统的注册、更新和生命周期
|
||||
*/
|
||||
pub struct SystemManager {
|
||||
systems: Vec<Box<dyn System>>,
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl SystemManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
systems: Vec::new(),
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加系统
|
||||
*/
|
||||
pub fn add_system<T: System + 'static>(&mut self, system: T) {
|
||||
self.systems.push(Box::new(system));
|
||||
// 按更新顺序排序
|
||||
self.systems.sort_by_key(|s| s.update_order());
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加系统(Box版本)
|
||||
*/
|
||||
pub fn add_system_boxed(&mut self, system: Box<dyn System>) {
|
||||
self.systems.push(system);
|
||||
// 按更新顺序排序
|
||||
self.systems.sort_by_key(|s| s.update_order());
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除系统
|
||||
*/
|
||||
pub fn remove_system<T: System + 'static>(&mut self) -> bool {
|
||||
let initial_len = self.systems.len();
|
||||
self.systems.retain(|system| {
|
||||
!system.as_any().is::<T>()
|
||||
});
|
||||
initial_len != self.systems.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统
|
||||
*/
|
||||
pub fn get_system<T: System + 'static>(&self) -> Option<&T> {
|
||||
for system in &self.systems {
|
||||
if let Some(s) = system.as_any().downcast_ref::<T>() {
|
||||
return Some(s);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变系统
|
||||
*/
|
||||
pub fn get_system_mut<T: System + 'static>(&mut self) -> Option<&mut T> {
|
||||
for system in &mut self.systems {
|
||||
if let Some(s) = system.as_any_mut().downcast_mut::<T>() {
|
||||
return Some(s);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化所有系统
|
||||
*/
|
||||
pub fn initialize(&mut self, context: &mut SystemContext) {
|
||||
if !self.initialized {
|
||||
for system in &mut self.systems {
|
||||
system.initialize(context);
|
||||
}
|
||||
self.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有系统
|
||||
*/
|
||||
pub fn update(&mut self, context: &mut SystemContext) {
|
||||
for system in &mut self.systems {
|
||||
if system.enabled() {
|
||||
system.update(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 后更新所有系统
|
||||
*/
|
||||
pub fn late_update(&mut self, context: &mut SystemContext) {
|
||||
for system in &mut self.systems {
|
||||
if system.enabled() {
|
||||
system.late_update(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理所有系统
|
||||
*/
|
||||
pub fn cleanup(&mut self, context: &mut SystemContext) {
|
||||
for system in &mut self.systems {
|
||||
system.cleanup(context);
|
||||
}
|
||||
self.systems.clear();
|
||||
self.initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统数量
|
||||
*/
|
||||
pub fn system_count(&self) -> usize {
|
||||
self.systems.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的系统数量
|
||||
*/
|
||||
pub fn enabled_system_count(&self) -> usize {
|
||||
self.systems.iter().filter(|s| s.enabled()).count()
|
||||
}
|
||||
/**
|
||||
* 预留系统容量
|
||||
*/
|
||||
pub fn reserve_capacity(&mut self, capacity: usize) {
|
||||
self.systems.reserve(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SystemManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
33
packages/core-rust/src/lib.rs
Normal file
33
packages/core-rust/src/lib.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
// ECS Framework Rust Core - WASM Entry Point
|
||||
// 只暴露用户需要操作的核心API,内部实现保持私有
|
||||
|
||||
mod core;
|
||||
mod storage;
|
||||
mod utils;
|
||||
mod wasm;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
|
||||
macro_rules! console_log {
|
||||
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
|
||||
}
|
||||
|
||||
// 只导出WASM包装器,隐藏内部实现
|
||||
pub use wasm::{EntityWrapper, EntityManagerWrapper, QuerySystemWrapper, SceneWrapper, ComponentWrapper, ComponentRegistryWrapper};
|
||||
|
||||
// 导出核心类型供内部使用(不暴露给JavaScript)
|
||||
pub use core::{Entity, Component, ComponentRegistry, BaseComponent, EntityManager, QuerySystem, QueryResult, Scene, System, EntitySystem, ProcessingSystem, IntervalSystem, SystemManager, ECSEventType, EventPriority, Event, EventListener, EventBus, EventBusStats, SimpleEventListener, ArchetypeSystem, Archetype, ArchetypeId, ArchetypeQueryResult, ArchetypeSystemStats, EntityBuilder, QueryBuilder, ECSFluentAPI, FluentAPIStats, PassiveSystem, PassiveSystemBuilder, ComponentBuilder, BaseComponentBuilder, ComponentBuilderFactory, ComponentBuilderStats, EntityBatchOperator, BatchOperatorStats, SceneBuilder, SceneTemplate, SceneBuilderStats, SceneBuilderFactory, SceneBuilderManager};
|
||||
pub use storage::{ComponentStorage, ComponentStorageManager, SoAStorage, SoAFieldType, SoAFieldMetadata, SoAStorageStats, SoAFieldStats};
|
||||
pub use utils::{SparseSet, Time, Matcher, QueryCondition, ComponentType, IdentifierPool, IdentifierPoolStats, ComponentPool, ComponentPoolManager, ComponentPoolStats, ComponentPoolManagerStats, PoolStatsSummary, DirtyTrackingSystem, DirtyFlag, DirtyData, DirtyTrackingStats, DirtyListener, DirtyListenerConfig, PerformanceMonitor, PerformanceData, PerformanceStats, PerformanceWarning, PerformanceWarningType, WarningSeverity, PerformanceThresholds, ThresholdPair, Timer, TimerManager, ITimer, TimerContext, TimerCallback, EmptyContext, Pool, PoolManager, Poolable, PoolStats, DebugManager, EntityDataCollector, SystemDataCollector, ComponentDataCollector, PerformanceDataCollector, DebugEntityData, DebugComponentInfo, DebugSystemInfo, DebugArchetypeInfo, DebugPerformanceInfo, DebugWarning, WarningLevel, DebugStats, DebugData, IUpdatable, IUpdatableComparer, SceneComponent, SceneComponentTrait, UpdatableManager, SceneComponentManager, is_updatable, NumberExtension, TypeUtils, StringExtension, CollectionExtension};
|
||||
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn main() {
|
||||
utils::set_panic_hook();
|
||||
console_log!("ECS Core Rust initialized - WASM API ready");
|
||||
}
|
||||
301
packages/core-rust/src/storage/component_storage.rs
Normal file
301
packages/core-rust/src/storage/component_storage.rs
Normal file
@@ -0,0 +1,301 @@
|
||||
use crate::core::component::{Component, ComponentRegistry};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::any::TypeId;
|
||||
|
||||
/**
|
||||
* 高性能组件存储器
|
||||
*/
|
||||
pub struct ComponentStorage<T: Component + 'static> {
|
||||
components: Vec<Option<T>>,
|
||||
entity_to_index: FxHashMap<u32, usize>,
|
||||
index_to_entity: Vec<u32>,
|
||||
free_indices: Vec<usize>,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl<T: Component + 'static> ComponentStorage<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
components: Vec::new(),
|
||||
entity_to_index: FxHashMap::default(),
|
||||
index_to_entity: Vec::new(),
|
||||
free_indices: Vec::new(),
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组件
|
||||
* @param entity_id 实体ID
|
||||
* @param component 组件实例
|
||||
*/
|
||||
pub fn add_component(&mut self, entity_id: u32, component: T) -> Result<(), String> {
|
||||
if self.entity_to_index.contains_key(&entity_id) {
|
||||
return Err(format!("Entity {} already has this component", entity_id));
|
||||
}
|
||||
|
||||
let index = if let Some(free_index) = self.free_indices.pop() {
|
||||
self.components[free_index] = Some(component);
|
||||
self.index_to_entity[free_index] = entity_id;
|
||||
free_index
|
||||
} else {
|
||||
let index = self.components.len();
|
||||
self.components.push(Some(component));
|
||||
self.index_to_entity.push(entity_id);
|
||||
index
|
||||
};
|
||||
|
||||
self.entity_to_index.insert(entity_id, index);
|
||||
self.size += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件
|
||||
* @param entity_id 实体ID
|
||||
* @returns 组件引用或None
|
||||
*/
|
||||
pub fn get_component(&self, entity_id: u32) -> Option<&T> {
|
||||
self.entity_to_index
|
||||
.get(&entity_id)
|
||||
.and_then(|&index| self.components.get(index))
|
||||
.and_then(|component| component.as_ref())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变组件
|
||||
* @param entity_id 实体ID
|
||||
* @returns 可变组件引用或None
|
||||
*/
|
||||
pub fn get_component_mut(&mut self, entity_id: u32) -> Option<&mut T> {
|
||||
self.entity_to_index
|
||||
.get(&entity_id)
|
||||
.and_then(|&index| self.components.get_mut(index))
|
||||
.and_then(|component| component.as_mut())
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否有此组件
|
||||
* @param entity_id 实体ID
|
||||
* @returns 是否有组件
|
||||
*/
|
||||
pub fn has_component(&self, entity_id: u32) -> bool {
|
||||
self.entity_to_index.contains_key(&entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除组件
|
||||
* @param entity_id 实体ID
|
||||
* @returns 被移除的组件或None
|
||||
*/
|
||||
pub fn remove_component(&mut self, entity_id: u32) -> Option<T> {
|
||||
let index = self.entity_to_index.remove(&entity_id)?;
|
||||
let component = self.components[index].take()?;
|
||||
self.free_indices.push(index);
|
||||
self.size -= 1;
|
||||
Some(component)
|
||||
}
|
||||
|
||||
/**
|
||||
* 高效遍历所有组件
|
||||
* @param callback 回调函数
|
||||
*/
|
||||
pub fn for_each<F>(&self, mut callback: F)
|
||||
where
|
||||
F: FnMut(&T, u32, usize),
|
||||
{
|
||||
for (index, component) in self.components.iter().enumerate() {
|
||||
if let Some(comp) = component {
|
||||
let entity_id = self.index_to_entity[index];
|
||||
callback(comp, entity_id, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有组件(密集数组)
|
||||
*/
|
||||
pub fn get_dense_array(&self) -> (Vec<&T>, Vec<u32>) {
|
||||
let mut components = Vec::new();
|
||||
let mut entity_ids = Vec::new();
|
||||
|
||||
for (index, component) in self.components.iter().enumerate() {
|
||||
if let Some(comp) = component {
|
||||
components.push(comp);
|
||||
entity_ids.push(self.index_to_entity[index]);
|
||||
}
|
||||
}
|
||||
|
||||
(components, entity_ids)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有组件
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.components.clear();
|
||||
self.entity_to_index.clear();
|
||||
self.index_to_entity.clear();
|
||||
self.free_indices.clear();
|
||||
self.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件数量
|
||||
*/
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> ComponentStorageStats {
|
||||
let total_slots = self.components.len();
|
||||
let used_slots = self.size;
|
||||
let free_slots = self.free_indices.len();
|
||||
let fragmentation = if total_slots > 0 {
|
||||
free_slots as f32 / total_slots as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
ComponentStorageStats {
|
||||
total_slots,
|
||||
used_slots,
|
||||
free_slots,
|
||||
fragmentation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件存储统计信息
|
||||
*/
|
||||
pub struct ComponentStorageStats {
|
||||
pub total_slots: usize,
|
||||
pub used_slots: usize,
|
||||
pub free_slots: usize,
|
||||
pub fragmentation: f32,
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件存储管理器
|
||||
* 管理所有组件类型的存储器
|
||||
*/
|
||||
pub struct ComponentStorageManager {
|
||||
storages: FxHashMap<TypeId, Box<dyn ComponentStorageInterface>>,
|
||||
registry: ComponentRegistry,
|
||||
}
|
||||
|
||||
impl ComponentStorageManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
storages: FxHashMap::default(),
|
||||
registry: ComponentRegistry::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件注册表
|
||||
*/
|
||||
pub fn get_registry(&self) -> &ComponentRegistry {
|
||||
&self.registry
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变组件注册表
|
||||
*/
|
||||
pub fn get_registry_mut(&mut self) -> &mut ComponentRegistry {
|
||||
&mut self.registry
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组件
|
||||
* @param entity_id 实体ID
|
||||
* @param component 组件实例
|
||||
*/
|
||||
pub fn add_component<T: Component + Clone + 'static>(&mut self, entity_id: u32, component: T) -> Result<(), String> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
if !self.storages.contains_key(&type_id) {
|
||||
let storage = Box::new(ComponentStorage::<T>::new());
|
||||
self.storages.insert(type_id, storage);
|
||||
}
|
||||
|
||||
if let Some(storage) = self.storages.get_mut(&type_id) {
|
||||
storage.add_component_boxed(entity_id, Box::new(component))
|
||||
} else {
|
||||
Err("Failed to get storage".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除实体的所有组件
|
||||
* @param entity_id 实体ID
|
||||
*/
|
||||
pub fn remove_all_components(&mut self, entity_id: u32) {
|
||||
for storage in self.storages.values_mut() {
|
||||
storage.remove_component_by_entity(entity_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的组件位掩码
|
||||
* @param entity_id 实体ID
|
||||
* @returns 组件位掩码
|
||||
*/
|
||||
pub fn get_component_mask(&self, entity_id: u32) -> u64 {
|
||||
let mut mask = 0u64;
|
||||
for (&type_id, storage) in &self.storages {
|
||||
if storage.has_component(entity_id) {
|
||||
if let Some(bit_mask) = self.registry.get_bit_mask(&type_id) {
|
||||
mask |= bit_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
mask
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有存储器
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
for storage in self.storages.values_mut() {
|
||||
storage.clear();
|
||||
}
|
||||
self.storages.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件存储接口
|
||||
*/
|
||||
trait ComponentStorageInterface: Send + Sync {
|
||||
fn add_component_boxed(&mut self, entity_id: u32, component: Box<dyn Component>) -> Result<(), String>;
|
||||
fn remove_component_by_entity(&mut self, entity_id: u32) -> bool;
|
||||
fn has_component(&self, entity_id: u32) -> bool;
|
||||
fn clear(&mut self);
|
||||
}
|
||||
|
||||
impl<T: Component + Clone + 'static> ComponentStorageInterface for ComponentStorage<T> {
|
||||
fn add_component_boxed(&mut self, entity_id: u32, component: Box<dyn Component>) -> Result<(), String> {
|
||||
if let Some(downcasted) = component.as_any().downcast_ref::<T>() {
|
||||
self.add_component(entity_id, downcasted.clone())
|
||||
} else {
|
||||
Err("Failed to downcast component".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_component_by_entity(&mut self, entity_id: u32) -> bool {
|
||||
self.remove_component(entity_id).is_some()
|
||||
}
|
||||
|
||||
fn has_component(&self, entity_id: u32) -> bool {
|
||||
ComponentStorage::has_component(self, entity_id)
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
ComponentStorage::clear(self)
|
||||
}
|
||||
}
|
||||
5
packages/core-rust/src/storage/mod.rs
Normal file
5
packages/core-rust/src/storage/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub mod component_storage;
|
||||
pub mod soa_storage;
|
||||
|
||||
pub use component_storage::{ComponentStorage, ComponentStorageManager};
|
||||
pub use soa_storage::{SoAStorage, SoAFieldType, SoAFieldMetadata, SoAStorageStats, SoAFieldStats};
|
||||
999
packages/core-rust/src/storage/soa_storage.rs
Normal file
999
packages/core-rust/src/storage/soa_storage.rs
Normal file
@@ -0,0 +1,999 @@
|
||||
use crate::core::Component;
|
||||
use crate::utils::ComponentType;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::any::Any;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/**
|
||||
* SoA字段类型枚举
|
||||
* 定义TypedArray字段的存储类型
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SoAFieldType {
|
||||
Float32,
|
||||
Float64,
|
||||
Int32,
|
||||
Boolean,
|
||||
String,
|
||||
Serialized,
|
||||
Complex,
|
||||
}
|
||||
|
||||
/**
|
||||
* SoA字段元数据
|
||||
* 记录字段的配置信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SoAFieldMetadata {
|
||||
pub field_type: SoAFieldType,
|
||||
pub high_precision: bool,
|
||||
pub serialize_map: bool,
|
||||
pub serialize_set: bool,
|
||||
pub serialize_array: bool,
|
||||
pub deep_copy: bool,
|
||||
}
|
||||
|
||||
impl Default for SoAFieldMetadata {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
field_type: SoAFieldType::Float32,
|
||||
high_precision: false,
|
||||
serialize_map: false,
|
||||
serialize_set: false,
|
||||
serialize_array: false,
|
||||
deep_copy: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SoA存储统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SoAStorageStats {
|
||||
pub size: usize,
|
||||
pub capacity: usize,
|
||||
pub used_slots: usize,
|
||||
pub fragmentation: f64,
|
||||
pub memory_usage: usize,
|
||||
pub field_stats: FxHashMap<String, SoAFieldStats>,
|
||||
}
|
||||
|
||||
/**
|
||||
* SoA字段统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SoAFieldStats {
|
||||
pub size: usize,
|
||||
pub capacity: usize,
|
||||
pub field_type: String,
|
||||
pub memory: usize,
|
||||
}
|
||||
|
||||
/**
|
||||
* SoA存储器
|
||||
* 使用Structure of Arrays存储模式,在大规模批量操作时提供优异性能
|
||||
*/
|
||||
pub struct SoAStorage<T: Component> {
|
||||
/// Float32数值字段
|
||||
float32_fields: FxHashMap<String, Vec<f32>>,
|
||||
/// Float64数值字段
|
||||
float64_fields: FxHashMap<String, Vec<f64>>,
|
||||
/// Int32数值字段
|
||||
int32_fields: FxHashMap<String, Vec<i32>>,
|
||||
/// 字符串字段
|
||||
string_fields: FxHashMap<String, Vec<Option<String>>>,
|
||||
/// 序列化字段(用于复杂对象)
|
||||
serialized_fields: FxHashMap<String, Vec<Option<String>>>,
|
||||
/// 复杂对象字段(高精度或非序列化对象)
|
||||
complex_fields: FxHashMap<u32, FxHashMap<String, Box<dyn Any + Send>>>,
|
||||
/// 实体ID到索引的映射
|
||||
entity_to_index: FxHashMap<u32, usize>,
|
||||
/// 索引到实体ID的映射
|
||||
index_to_entity: Vec<Option<u32>>,
|
||||
/// 空闲索引列表
|
||||
free_indices: Vec<usize>,
|
||||
/// 当前大小
|
||||
size: usize,
|
||||
/// 当前容量
|
||||
capacity: usize,
|
||||
/// 组件类型
|
||||
component_type: ComponentType,
|
||||
/// 字段元数据
|
||||
field_metadata: FxHashMap<String, SoAFieldMetadata>,
|
||||
/// 类型标记
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Component> SoAStorage<T> {
|
||||
/**
|
||||
* 创建新的SoA存储器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
let initial_capacity = 1000;
|
||||
|
||||
Self {
|
||||
float32_fields: FxHashMap::default(),
|
||||
float64_fields: FxHashMap::default(),
|
||||
int32_fields: FxHashMap::default(),
|
||||
string_fields: FxHashMap::default(),
|
||||
serialized_fields: FxHashMap::default(),
|
||||
complex_fields: FxHashMap::default(),
|
||||
entity_to_index: FxHashMap::default(),
|
||||
index_to_entity: vec![None; initial_capacity],
|
||||
free_indices: Vec::new(),
|
||||
size: 0,
|
||||
capacity: initial_capacity,
|
||||
component_type: std::any::TypeId::of::<T>(),
|
||||
field_metadata: FxHashMap::default(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定容量创建SoA存储器
|
||||
*/
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
float32_fields: FxHashMap::default(),
|
||||
float64_fields: FxHashMap::default(),
|
||||
int32_fields: FxHashMap::default(),
|
||||
string_fields: FxHashMap::default(),
|
||||
serialized_fields: FxHashMap::default(),
|
||||
complex_fields: FxHashMap::default(),
|
||||
entity_to_index: FxHashMap::default(),
|
||||
index_to_entity: vec![None; capacity],
|
||||
free_indices: Vec::new(),
|
||||
size: 0,
|
||||
capacity,
|
||||
component_type: std::any::TypeId::of::<T>(),
|
||||
field_metadata: FxHashMap::default(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化字段结构
|
||||
* 根据组件类型的特征来设置字段存储类型
|
||||
*/
|
||||
pub fn initialize_fields(&mut self) {
|
||||
// 在Rust中,我们需要手动注册字段类型
|
||||
// 这里提供一个基础的初始化,具体的字段配置需要通过register_field方法添加
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册字段
|
||||
*/
|
||||
pub fn register_field(&mut self, field_name: &str, metadata: SoAFieldMetadata) {
|
||||
self.field_metadata.insert(field_name.to_string(), metadata.clone());
|
||||
|
||||
match metadata.field_type {
|
||||
SoAFieldType::Float32 => {
|
||||
self.float32_fields.insert(field_name.to_string(), vec![0.0; self.capacity]);
|
||||
},
|
||||
SoAFieldType::Float64 => {
|
||||
self.float64_fields.insert(field_name.to_string(), vec![0.0; self.capacity]);
|
||||
},
|
||||
SoAFieldType::Int32 => {
|
||||
self.int32_fields.insert(field_name.to_string(), vec![0; self.capacity]);
|
||||
},
|
||||
SoAFieldType::Boolean => {
|
||||
// 布尔值使用Float32存储为0/1
|
||||
self.float32_fields.insert(field_name.to_string(), vec![0.0; self.capacity]);
|
||||
},
|
||||
SoAFieldType::String => {
|
||||
self.string_fields.insert(field_name.to_string(), vec![None; self.capacity]);
|
||||
},
|
||||
SoAFieldType::Serialized => {
|
||||
self.serialized_fields.insert(field_name.to_string(), vec![None; self.capacity]);
|
||||
},
|
||||
SoAFieldType::Complex => {
|
||||
// 复杂字段在运行时按需添加到complex_fields中
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组件
|
||||
*/
|
||||
pub fn add_component(&mut self, entity_id: u32, component: T) {
|
||||
if let Some(index) = self.entity_to_index.get(&entity_id) {
|
||||
// 更新现有组件
|
||||
self.update_component_at_index(*index, entity_id, component);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取可用索引
|
||||
let index = if let Some(free_index) = self.free_indices.pop() {
|
||||
free_index
|
||||
} else {
|
||||
if self.size >= self.capacity {
|
||||
self.resize(self.capacity * 2);
|
||||
}
|
||||
self.size
|
||||
};
|
||||
|
||||
// 设置映射关系
|
||||
self.entity_to_index.insert(entity_id, index);
|
||||
self.index_to_entity[index] = Some(entity_id);
|
||||
|
||||
// 更新组件数据
|
||||
self.update_component_at_index(index, entity_id, component);
|
||||
|
||||
if index == self.size {
|
||||
self.size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定索引处更新组件数据
|
||||
*/
|
||||
fn update_component_at_index(&mut self, index: usize, entity_id: u32, component: T) {
|
||||
// 在Rust中,我们无法像TypeScript那样动态遍历对象属性
|
||||
// 需要使用trait或者其他方式来序列化组件数据
|
||||
// 这里提供一个基础实现,具体的字段设置需要在具体使用时实现
|
||||
|
||||
// 将组件转换为Any trait对象存储在complex_fields中
|
||||
let mut entity_complex_fields = FxHashMap::default();
|
||||
entity_complex_fields.insert("component".to_string(), Box::new(component) as Box<dyn Any + Send>);
|
||||
self.complex_fields.insert(entity_id, entity_complex_fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件
|
||||
*/
|
||||
pub fn get_component(&self, entity_id: u32) -> Option<&T> {
|
||||
if let Some(index) = self.entity_to_index.get(&entity_id) {
|
||||
if let Some(complex_fields) = self.complex_fields.get(&entity_id) {
|
||||
if let Some(component_any) = complex_fields.get("component") {
|
||||
if let Some(component) = component_any.downcast_ref::<T>() {
|
||||
return Some(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变组件引用
|
||||
*/
|
||||
pub fn get_component_mut(&mut self, entity_id: u32) -> Option<&mut T> {
|
||||
if let Some(_index) = self.entity_to_index.get(&entity_id) {
|
||||
if let Some(complex_fields) = self.complex_fields.get_mut(&entity_id) {
|
||||
if let Some(component_any) = complex_fields.get_mut("component") {
|
||||
if let Some(component) = component_any.downcast_mut::<T>() {
|
||||
return Some(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否包含指定实体的组件
|
||||
*/
|
||||
pub fn has_component(&self, entity_id: u32) -> bool {
|
||||
self.entity_to_index.contains_key(&entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除组件
|
||||
*/
|
||||
pub fn remove_component(&mut self, entity_id: u32) -> bool {
|
||||
if let Some(index) = self.entity_to_index.remove(&entity_id) {
|
||||
// 清理复杂字段
|
||||
self.complex_fields.remove(&entity_id);
|
||||
|
||||
// 清理索引映射
|
||||
self.index_to_entity[index] = None;
|
||||
self.free_indices.push(index);
|
||||
|
||||
// 清理各类型字段的数据(设为默认值)
|
||||
for array in self.float32_fields.values_mut() {
|
||||
if index < array.len() {
|
||||
array[index] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for array in self.float64_fields.values_mut() {
|
||||
if index < array.len() {
|
||||
array[index] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for array in self.int32_fields.values_mut() {
|
||||
if index < array.len() {
|
||||
array[index] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for array in self.string_fields.values_mut() {
|
||||
if index < array.len() {
|
||||
array[index] = None;
|
||||
}
|
||||
}
|
||||
|
||||
for array in self.serialized_fields.values_mut() {
|
||||
if index < array.len() {
|
||||
array[index] = None;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整存储容量
|
||||
*/
|
||||
fn resize(&mut self, new_capacity: usize) {
|
||||
// 调整数值字段
|
||||
for array in self.float32_fields.values_mut() {
|
||||
array.resize(new_capacity, 0.0);
|
||||
}
|
||||
|
||||
for array in self.float64_fields.values_mut() {
|
||||
array.resize(new_capacity, 0.0);
|
||||
}
|
||||
|
||||
for array in self.int32_fields.values_mut() {
|
||||
array.resize(new_capacity, 0);
|
||||
}
|
||||
|
||||
for array in self.string_fields.values_mut() {
|
||||
array.resize(new_capacity, None);
|
||||
}
|
||||
|
||||
for array in self.serialized_fields.values_mut() {
|
||||
array.resize(new_capacity, None);
|
||||
}
|
||||
|
||||
// 调整索引映射
|
||||
self.index_to_entity.resize(new_capacity, None);
|
||||
|
||||
self.capacity = new_capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活跃索引列表
|
||||
*/
|
||||
pub fn get_active_indices(&self) -> Vec<usize> {
|
||||
self.entity_to_index.values().cloned().collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Float32字段数组
|
||||
*/
|
||||
pub fn get_float32_field(&self, field_name: &str) -> Option<&[f32]> {
|
||||
self.float32_fields.get(field_name).map(|v| v.as_slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变Float32字段数组
|
||||
*/
|
||||
pub fn get_float32_field_mut(&mut self, field_name: &str) -> Option<&mut [f32]> {
|
||||
self.float32_fields.get_mut(field_name).map(|v| v.as_mut_slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Float64字段数组
|
||||
*/
|
||||
pub fn get_float64_field(&self, field_name: &str) -> Option<&[f64]> {
|
||||
self.float64_fields.get(field_name).map(|v| v.as_slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变Float64字段数组
|
||||
*/
|
||||
pub fn get_float64_field_mut(&mut self, field_name: &str) -> Option<&mut [f64]> {
|
||||
self.float64_fields.get_mut(field_name).map(|v| v.as_mut_slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Int32字段数组
|
||||
*/
|
||||
pub fn get_int32_field(&self, field_name: &str) -> Option<&[i32]> {
|
||||
self.int32_fields.get(field_name).map(|v| v.as_slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可变Int32字段数组
|
||||
*/
|
||||
pub fn get_int32_field_mut(&mut self, field_name: &str) -> Option<&mut [i32]> {
|
||||
self.int32_fields.get_mut(field_name).map(|v| v.as_mut_slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体索引
|
||||
*/
|
||||
pub fn get_entity_index(&self, entity_id: u32) -> Option<usize> {
|
||||
self.entity_to_index.get(&entity_id).copied()
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引获取实体ID
|
||||
*/
|
||||
pub fn get_entity_id_by_index(&self, index: usize) -> Option<u32> {
|
||||
if index < self.index_to_entity.len() {
|
||||
self.index_to_entity[index]
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前大小
|
||||
*/
|
||||
pub fn size(&self) -> usize {
|
||||
self.size - self.free_indices.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取容量
|
||||
*/
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.capacity
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有数据
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.entity_to_index.clear();
|
||||
self.complex_fields.clear();
|
||||
self.free_indices.clear();
|
||||
self.size = 0;
|
||||
|
||||
// 重置所有字段数组
|
||||
for array in self.float32_fields.values_mut() {
|
||||
array.fill(0.0);
|
||||
}
|
||||
|
||||
for array in self.float64_fields.values_mut() {
|
||||
array.fill(0.0);
|
||||
}
|
||||
|
||||
for array in self.int32_fields.values_mut() {
|
||||
array.fill(0);
|
||||
}
|
||||
|
||||
for array in self.string_fields.values_mut() {
|
||||
array.fill(None);
|
||||
}
|
||||
|
||||
for array in self.serialized_fields.values_mut() {
|
||||
array.fill(None);
|
||||
}
|
||||
|
||||
for i in 0..self.index_to_entity.len() {
|
||||
self.index_to_entity[i] = None;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩存储(移除空洞)
|
||||
*/
|
||||
pub fn compact(&mut self) {
|
||||
if self.free_indices.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 收集所有活跃的实体并按索引排序
|
||||
let mut active_entries: Vec<(u32, usize)> = self.entity_to_index.iter()
|
||||
.map(|(&entity_id, &index)| (entity_id, index))
|
||||
.collect();
|
||||
active_entries.sort_by_key(|(_, index)| *index);
|
||||
|
||||
// 重新映射索引
|
||||
let mut new_entity_to_index = FxHashMap::default();
|
||||
let mut new_index_to_entity = vec![None; self.capacity];
|
||||
|
||||
for (new_index, (entity_id, old_index)) in active_entries.iter().enumerate() {
|
||||
new_entity_to_index.insert(*entity_id, new_index);
|
||||
new_index_to_entity[new_index] = Some(*entity_id);
|
||||
|
||||
if new_index != *old_index {
|
||||
// 移动数据
|
||||
self.move_data_between_indices(*old_index, new_index);
|
||||
}
|
||||
}
|
||||
|
||||
self.entity_to_index = new_entity_to_index;
|
||||
self.index_to_entity = new_index_to_entity;
|
||||
self.free_indices.clear();
|
||||
self.size = active_entries.len();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在索引间移动数据
|
||||
*/
|
||||
fn move_data_between_indices(&mut self, from: usize, to: usize) {
|
||||
// 移动Float32字段
|
||||
for array in self.float32_fields.values_mut() {
|
||||
if from < array.len() && to < array.len() {
|
||||
array[to] = array[from];
|
||||
}
|
||||
}
|
||||
|
||||
// 移动Float64字段
|
||||
for array in self.float64_fields.values_mut() {
|
||||
if from < array.len() && to < array.len() {
|
||||
array[to] = array[from];
|
||||
}
|
||||
}
|
||||
|
||||
// 移动Int32字段
|
||||
for array in self.int32_fields.values_mut() {
|
||||
if from < array.len() && to < array.len() {
|
||||
array[to] = array[from];
|
||||
}
|
||||
}
|
||||
|
||||
// 移动String字段
|
||||
for array in self.string_fields.values_mut() {
|
||||
if from < array.len() && to < array.len() {
|
||||
array[to] = array[from].take();
|
||||
}
|
||||
}
|
||||
|
||||
// 移动序列化字段
|
||||
for array in self.serialized_fields.values_mut() {
|
||||
if from < array.len() && to < array.len() {
|
||||
array[to] = array[from].take();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> SoAStorageStats {
|
||||
let mut total_memory = 0usize;
|
||||
let mut field_stats = FxHashMap::default();
|
||||
|
||||
// 计算Float32字段统计
|
||||
for (field_name, array) in &self.float32_fields {
|
||||
let memory = array.len() * std::mem::size_of::<f32>();
|
||||
total_memory += memory;
|
||||
field_stats.insert(field_name.clone(), SoAFieldStats {
|
||||
size: self.size(),
|
||||
capacity: array.len(),
|
||||
field_type: "float32".to_string(),
|
||||
memory,
|
||||
});
|
||||
}
|
||||
|
||||
// 计算Float64字段统计
|
||||
for (field_name, array) in &self.float64_fields {
|
||||
let memory = array.len() * std::mem::size_of::<f64>();
|
||||
total_memory += memory;
|
||||
field_stats.insert(field_name.clone(), SoAFieldStats {
|
||||
size: self.size(),
|
||||
capacity: array.len(),
|
||||
field_type: "float64".to_string(),
|
||||
memory,
|
||||
});
|
||||
}
|
||||
|
||||
// 计算Int32字段统计
|
||||
for (field_name, array) in &self.int32_fields {
|
||||
let memory = array.len() * std::mem::size_of::<i32>();
|
||||
total_memory += memory;
|
||||
field_stats.insert(field_name.clone(), SoAFieldStats {
|
||||
size: self.size(),
|
||||
capacity: array.len(),
|
||||
field_type: "int32".to_string(),
|
||||
memory,
|
||||
});
|
||||
}
|
||||
|
||||
// 估算字符串和序列化字段内存(简单估算)
|
||||
for (field_name, array) in &self.string_fields {
|
||||
let estimated_memory = array.len() * 64; // 假设平均64字节每个字符串
|
||||
total_memory += estimated_memory;
|
||||
field_stats.insert(field_name.clone(), SoAFieldStats {
|
||||
size: self.size(),
|
||||
capacity: array.len(),
|
||||
field_type: "string".to_string(),
|
||||
memory: estimated_memory,
|
||||
});
|
||||
}
|
||||
|
||||
SoAStorageStats {
|
||||
size: self.size(),
|
||||
capacity: self.capacity,
|
||||
used_slots: self.size(),
|
||||
fragmentation: self.free_indices.len() as f64 / self.capacity as f64,
|
||||
memory_usage: total_memory,
|
||||
field_stats,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行向量化批量操作
|
||||
*/
|
||||
pub fn perform_vectorized_operation<F>(&mut self, operation: F)
|
||||
where
|
||||
F: FnOnce(&mut SoAStorage<T>),
|
||||
{
|
||||
operation(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> Default for SoAStorage<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::Any;
|
||||
|
||||
// 测试组件
|
||||
#[derive(Debug, Clone)]
|
||||
struct TestComponent {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub name: String,
|
||||
pub active: bool,
|
||||
pub id: u32,
|
||||
pub enabled: bool,
|
||||
pub update_order: i32,
|
||||
}
|
||||
|
||||
impl TestComponent {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
name: String::new(),
|
||||
active: false,
|
||||
id: 0,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for TestComponent {
|
||||
fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.enabled = enabled;
|
||||
}
|
||||
|
||||
fn update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
fn set_update_order(&mut self, order: i32) {
|
||||
self.update_order = order;
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn Component> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_soa_storage_creation() {
|
||||
let storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
assert_eq!(storage.size(), 0);
|
||||
assert_eq!(storage.capacity(), 1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_soa_storage_with_capacity() {
|
||||
let storage: SoAStorage<TestComponent> = SoAStorage::with_capacity(500);
|
||||
assert_eq!(storage.size(), 0);
|
||||
assert_eq!(storage.capacity(), 500);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_field_registration() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
storage.register_field("x", SoAFieldMetadata {
|
||||
field_type: SoAFieldType::Float32,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
storage.register_field("name", SoAFieldMetadata {
|
||||
field_type: SoAFieldType::String,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
assert!(storage.get_float32_field("x").is_some());
|
||||
assert_eq!(storage.get_float32_field("x").unwrap().len(), 1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_add_remove() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
let component = TestComponent {
|
||||
x: 1.0,
|
||||
y: 2.0,
|
||||
name: "test".to_string(),
|
||||
active: true,
|
||||
id: 1,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
|
||||
let entity_id = 1;
|
||||
|
||||
// 添加组件
|
||||
storage.add_component(entity_id, component.clone());
|
||||
assert_eq!(storage.size(), 1);
|
||||
assert!(storage.has_component(entity_id));
|
||||
|
||||
// 获取组件
|
||||
let retrieved = storage.get_component(entity_id);
|
||||
assert!(retrieved.is_some());
|
||||
|
||||
// 移除组件
|
||||
assert!(storage.remove_component(entity_id));
|
||||
assert_eq!(storage.size(), 0);
|
||||
assert!(!storage.has_component(entity_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_components() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
for i in 1..=10 {
|
||||
let component = TestComponent {
|
||||
x: i as f32,
|
||||
y: i as f32 * 2.0,
|
||||
name: format!("test{}", i),
|
||||
active: i % 2 == 0,
|
||||
id: i,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
storage.add_component(i, component);
|
||||
}
|
||||
|
||||
assert_eq!(storage.size(), 10);
|
||||
|
||||
// 验证所有组件都存在
|
||||
for i in 1..=10 {
|
||||
assert!(storage.has_component(i));
|
||||
}
|
||||
|
||||
// 移除一半组件
|
||||
for i in (1..=10).step_by(2) {
|
||||
storage.remove_component(i);
|
||||
}
|
||||
|
||||
assert_eq!(storage.size(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_storage_resize() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::with_capacity(5);
|
||||
|
||||
// 添加超过初始容量的组件
|
||||
for i in 1..=10 {
|
||||
let component = TestComponent {
|
||||
x: i as f32,
|
||||
y: i as f32,
|
||||
name: format!("test{}", i),
|
||||
active: true,
|
||||
id: i,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
storage.add_component(i, component);
|
||||
}
|
||||
|
||||
assert_eq!(storage.size(), 10);
|
||||
assert!(storage.capacity() >= 10); // 应该已经扩容
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_storage_clear() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
// 添加一些组件
|
||||
for i in 1..=5 {
|
||||
let component = TestComponent {
|
||||
x: i as f32,
|
||||
y: i as f32,
|
||||
name: format!("test{}", i),
|
||||
active: true,
|
||||
id: i,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
storage.add_component(i, component);
|
||||
}
|
||||
|
||||
assert_eq!(storage.size(), 5);
|
||||
|
||||
storage.clear();
|
||||
|
||||
assert_eq!(storage.size(), 0);
|
||||
for i in 1..=5 {
|
||||
assert!(!storage.has_component(i));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_storage_compact() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
// 添加组件
|
||||
for i in 1..=10 {
|
||||
let component = TestComponent {
|
||||
x: i as f32,
|
||||
y: i as f32,
|
||||
name: format!("test{}", i),
|
||||
active: true,
|
||||
id: i,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
storage.add_component(i, component);
|
||||
}
|
||||
|
||||
// 移除一些组件制造空洞
|
||||
storage.remove_component(2);
|
||||
storage.remove_component(4);
|
||||
storage.remove_component(6);
|
||||
|
||||
assert_eq!(storage.size(), 7);
|
||||
assert_eq!(storage.free_indices.len(), 3);
|
||||
|
||||
storage.compact();
|
||||
|
||||
assert_eq!(storage.size(), 7);
|
||||
assert!(storage.free_indices.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_storage_stats() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
storage.register_field("x", SoAFieldMetadata {
|
||||
field_type: SoAFieldType::Float32,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
storage.register_field("y", SoAFieldMetadata {
|
||||
field_type: SoAFieldType::Float64,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let component = TestComponent {
|
||||
x: 1.0,
|
||||
y: 2.0,
|
||||
name: "test".to_string(),
|
||||
active: true,
|
||||
id: 1,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
|
||||
storage.add_component(1, component);
|
||||
|
||||
let stats = storage.get_stats();
|
||||
assert_eq!(stats.size, 1);
|
||||
assert_eq!(stats.capacity, 1000);
|
||||
assert!(stats.memory_usage > 0);
|
||||
assert!(!stats.field_stats.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vectorized_operation() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
storage.register_field("x", SoAFieldMetadata {
|
||||
field_type: SoAFieldType::Float32,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// 设置初始数据到Float32字段中
|
||||
if let Some(x_field) = storage.get_float32_field_mut("x") {
|
||||
for i in 0..5 {
|
||||
x_field[i] = (i + 1) as f32;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行向量化操作
|
||||
storage.perform_vectorized_operation(|storage| {
|
||||
if let Some(x_field) = storage.get_float32_field_mut("x") {
|
||||
// 将所有x值乘以2
|
||||
for i in 0..5 {
|
||||
x_field[i] *= 2.0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 验证操作结果
|
||||
if let Some(x_field) = storage.get_float32_field("x") {
|
||||
assert_eq!(x_field[0], 2.0); // 第一个元素应该是2
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entity_index_mapping() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
let component = TestComponent {
|
||||
x: 1.0,
|
||||
y: 2.0,
|
||||
name: "test".to_string(),
|
||||
active: true,
|
||||
id: 1,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
|
||||
storage.add_component(100, component);
|
||||
|
||||
let index = storage.get_entity_index(100);
|
||||
assert!(index.is_some());
|
||||
|
||||
let entity_id = storage.get_entity_id_by_index(index.unwrap());
|
||||
assert_eq!(entity_id, Some(100));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_active_indices() {
|
||||
let mut storage: SoAStorage<TestComponent> = SoAStorage::new();
|
||||
|
||||
let component1 = TestComponent {
|
||||
x: 1.0,
|
||||
y: 1.0,
|
||||
name: "test1".to_string(),
|
||||
active: true,
|
||||
id: 1,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
|
||||
let component2 = TestComponent {
|
||||
x: 2.0,
|
||||
y: 2.0,
|
||||
name: "test2".to_string(),
|
||||
active: true,
|
||||
id: 2,
|
||||
enabled: true,
|
||||
update_order: 0,
|
||||
};
|
||||
|
||||
storage.add_component(1, component1);
|
||||
storage.add_component(2, component2);
|
||||
|
||||
let active_indices = storage.get_active_indices();
|
||||
assert_eq!(active_indices.len(), 2);
|
||||
|
||||
storage.remove_component(1);
|
||||
|
||||
let active_indices = storage.get_active_indices();
|
||||
assert_eq!(active_indices.len(), 1);
|
||||
}
|
||||
}
|
||||
766
packages/core-rust/src/utils/component_pool.rs
Normal file
766
packages/core-rust/src/utils/component_pool.rs
Normal file
@@ -0,0 +1,766 @@
|
||||
use crate::core::Component;
|
||||
use crate::utils::ComponentType;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::any::Any;
|
||||
|
||||
/**
|
||||
* 组件对象池,用于复用组件实例以减少内存分配
|
||||
*/
|
||||
pub struct ComponentPool<T>
|
||||
where
|
||||
T: Component + Clone + Default,
|
||||
{
|
||||
/// 池中存储的组件实例
|
||||
pool: Vec<T>,
|
||||
/// 创建新组件实例的函数
|
||||
create_fn: Box<dyn Fn() -> T + Send + Sync>,
|
||||
/// 重置组件状态的函数(可选)
|
||||
reset_fn: Option<Box<dyn Fn(&mut T) + Send + Sync>>,
|
||||
/// 池的最大容量
|
||||
max_size: usize,
|
||||
/// 统计信息
|
||||
stats: ComponentPoolStats,
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件池统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ComponentPoolStats {
|
||||
/// 总共创建的组件数量
|
||||
pub total_created: u32,
|
||||
/// 总共获取的次数
|
||||
pub total_acquires: u32,
|
||||
/// 总共释放的次数
|
||||
pub total_releases: u32,
|
||||
/// 池命中次数(从池中获取而不是创建新的)
|
||||
pub pool_hits: u32,
|
||||
/// 池未命中次数(需要创建新实例)
|
||||
pub pool_misses: u32,
|
||||
}
|
||||
|
||||
impl Default for ComponentPoolStats {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
total_created: 0,
|
||||
total_acquires: 0,
|
||||
total_releases: 0,
|
||||
pool_hits: 0,
|
||||
pool_misses: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ComponentPool<T>
|
||||
where
|
||||
T: Component + Clone + Default,
|
||||
{
|
||||
/**
|
||||
* 创建新的组件池
|
||||
*/
|
||||
pub fn new<F, R>(create_fn: F, reset_fn: Option<R>, max_size: usize) -> Self
|
||||
where
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
R: Fn(&mut T) + Send + Sync + 'static,
|
||||
{
|
||||
Self {
|
||||
pool: Vec::with_capacity(max_size.min(100)), // 预分配一些空间
|
||||
create_fn: Box::new(create_fn),
|
||||
reset_fn: reset_fn.map(|f| Box::new(f) as Box<dyn Fn(&mut T) + Send + Sync>),
|
||||
max_size,
|
||||
stats: ComponentPoolStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建默认的组件池(使用Default trait)
|
||||
*/
|
||||
pub fn with_default(max_size: usize) -> Self {
|
||||
Self::new(T::default, None::<fn(&mut T)>, max_size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带重置函数的默认组件池
|
||||
*/
|
||||
pub fn with_default_and_reset<R>(reset_fn: R, max_size: usize) -> Self
|
||||
where
|
||||
R: Fn(&mut T) + Send + Sync + 'static,
|
||||
{
|
||||
Self::new(T::default, Some(reset_fn), max_size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个组件实例
|
||||
*/
|
||||
pub fn acquire(&mut self) -> T {
|
||||
self.stats.total_acquires += 1;
|
||||
|
||||
if let Some(component) = self.pool.pop() {
|
||||
self.stats.pool_hits += 1;
|
||||
component
|
||||
} else {
|
||||
self.stats.pool_misses += 1;
|
||||
self.stats.total_created += 1;
|
||||
(self.create_fn)()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放一个组件实例回池中
|
||||
*/
|
||||
pub fn release(&mut self, mut component: T) {
|
||||
self.stats.total_releases += 1;
|
||||
|
||||
if self.pool.len() < self.max_size {
|
||||
// 调用重置函数(如果有)
|
||||
if let Some(ref reset_fn) = self.reset_fn {
|
||||
reset_fn(&mut component);
|
||||
}
|
||||
|
||||
self.pool.push(component);
|
||||
}
|
||||
// 如果池已满,组件会被丢弃(由Rust自动清理)
|
||||
}
|
||||
|
||||
/**
|
||||
* 预填充对象池
|
||||
*/
|
||||
pub fn prewarm(&mut self, count: usize) {
|
||||
let needed = (self.max_size - self.pool.len()).min(count);
|
||||
|
||||
for _ in 0..needed {
|
||||
let component = (self.create_fn)();
|
||||
self.pool.push(component);
|
||||
self.stats.total_created += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空对象池
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.pool.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池中可用对象数量
|
||||
*/
|
||||
pub fn available_count(&self) -> usize {
|
||||
self.pool.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池的最大容量
|
||||
*/
|
||||
pub fn max_size(&self) -> usize {
|
||||
self.max_size
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取使用中的对象数量估算
|
||||
*/
|
||||
pub fn used_count(&self) -> u32 {
|
||||
// 基于统计信息估算(总创建 - 池中可用)
|
||||
if self.stats.total_created as usize >= self.pool.len() {
|
||||
self.stats.total_created - self.pool.len() as u32
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池利用率(百分比)
|
||||
*/
|
||||
pub fn utilization_rate(&self) -> f32 {
|
||||
if self.max_size == 0 {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
let used = self.used_count() as f32;
|
||||
let total = self.max_size as f32;
|
||||
(used / total) * 100.0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池命中率(百分比)
|
||||
*/
|
||||
pub fn hit_rate(&self) -> f32 {
|
||||
if self.stats.total_acquires == 0 {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
(self.stats.pool_hits as f32 / self.stats.total_acquires as f32) * 100.0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> ComponentPoolStats {
|
||||
self.stats.clone()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置统计信息
|
||||
*/
|
||||
pub fn reset_stats(&mut self) {
|
||||
self.stats = ComponentPoolStats::default();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内存使用估算(字节)
|
||||
*/
|
||||
pub fn estimated_memory_usage(&self) -> usize {
|
||||
let component_size = std::mem::size_of::<T>();
|
||||
let pool_size = self.pool.len() * component_size;
|
||||
let vec_overhead = self.pool.capacity() * std::mem::size_of::<T>();
|
||||
|
||||
pool_size + vec_overhead
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型擦除的组件池特征
|
||||
* 用于在ComponentPoolManager中统一管理不同类型的池
|
||||
*/
|
||||
trait AnyComponentPool {
|
||||
fn clear(&mut self);
|
||||
fn available_count(&self) -> usize;
|
||||
fn max_size(&self) -> usize;
|
||||
fn used_count(&self) -> u32;
|
||||
fn utilization_rate(&self) -> f32;
|
||||
fn hit_rate(&self) -> f32;
|
||||
fn estimated_memory_usage(&self) -> usize;
|
||||
fn prewarm(&mut self, count: usize);
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl<T> AnyComponentPool for ComponentPool<T>
|
||||
where
|
||||
T: Component + Clone + Default,
|
||||
{
|
||||
fn clear(&mut self) {
|
||||
self.clear();
|
||||
}
|
||||
|
||||
fn available_count(&self) -> usize {
|
||||
self.available_count()
|
||||
}
|
||||
|
||||
fn max_size(&self) -> usize {
|
||||
self.max_size()
|
||||
}
|
||||
|
||||
fn used_count(&self) -> u32 {
|
||||
self.used_count()
|
||||
}
|
||||
|
||||
fn utilization_rate(&self) -> f32 {
|
||||
self.utilization_rate()
|
||||
}
|
||||
|
||||
fn hit_rate(&self) -> f32 {
|
||||
self.hit_rate()
|
||||
}
|
||||
|
||||
fn estimated_memory_usage(&self) -> usize {
|
||||
self.estimated_memory_usage()
|
||||
}
|
||||
|
||||
fn prewarm(&mut self, count: usize) {
|
||||
self.prewarm(count);
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 池统计信息摘要
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PoolStatsSummary {
|
||||
pub available: usize,
|
||||
pub max_size: usize,
|
||||
pub used: u32,
|
||||
pub utilization_rate: f32,
|
||||
pub hit_rate: f32,
|
||||
pub memory_usage: usize,
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局组件池管理器
|
||||
* 使用单例模式管理所有组件类型的对象池
|
||||
*/
|
||||
pub struct ComponentPoolManager {
|
||||
/// 存储各种组件类型的池
|
||||
pools: FxHashMap<ComponentType, Box<dyn AnyComponentPool>>,
|
||||
/// 管理器统计信息
|
||||
stats: ComponentPoolManagerStats,
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件池管理器统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ComponentPoolManagerStats {
|
||||
pub registered_pools: u32,
|
||||
pub total_memory_usage: usize,
|
||||
pub total_components_managed: u32,
|
||||
}
|
||||
|
||||
impl Default for ComponentPoolManagerStats {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
registered_pools: 0,
|
||||
total_memory_usage: 0,
|
||||
total_components_managed: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentPoolManager {
|
||||
/**
|
||||
* 创建新的组件池管理器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pools: FxHashMap::default(),
|
||||
stats: ComponentPoolManagerStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册组件池
|
||||
*/
|
||||
pub fn register_pool<T, F, R>(
|
||||
&mut self,
|
||||
component_type: ComponentType,
|
||||
create_fn: F,
|
||||
reset_fn: Option<R>,
|
||||
max_size: Option<usize>,
|
||||
) where
|
||||
T: Component + Clone + Default + 'static,
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
R: Fn(&mut T) + Send + Sync + 'static,
|
||||
{
|
||||
let max_size = max_size.unwrap_or(1000);
|
||||
let pool = ComponentPool::new(create_fn, reset_fn, max_size);
|
||||
|
||||
self.pools.insert(component_type, Box::new(pool));
|
||||
self.update_stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册使用Default的组件池
|
||||
*/
|
||||
pub fn register_pool_default<T>(&mut self, component_type: ComponentType, max_size: Option<usize>)
|
||||
where
|
||||
T: Component + Clone + Default + 'static,
|
||||
{
|
||||
let max_size = max_size.unwrap_or(1000);
|
||||
let pool = ComponentPool::<T>::with_default(max_size);
|
||||
|
||||
self.pools.insert(component_type, Box::new(pool));
|
||||
self.update_stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件实例
|
||||
*/
|
||||
pub fn acquire_component<T>(&mut self, component_type: ComponentType) -> Option<T>
|
||||
where
|
||||
T: Component + Clone + Default + 'static,
|
||||
{
|
||||
if let Some(pool) = self.pools.get_mut(&component_type) {
|
||||
if let Some(typed_pool) = pool.as_any_mut().downcast_mut::<ComponentPool<T>>() {
|
||||
return Some(typed_pool.acquire());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放组件实例
|
||||
*/
|
||||
pub fn release_component<T>(&mut self, component_type: ComponentType, component: T)
|
||||
where
|
||||
T: Component + Clone + Default + 'static,
|
||||
{
|
||||
if let Some(pool) = self.pools.get_mut(&component_type) {
|
||||
if let Some(typed_pool) = pool.as_any_mut().downcast_mut::<ComponentPool<T>>() {
|
||||
typed_pool.release(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预热所有池
|
||||
*/
|
||||
pub fn prewarm_all(&mut self, count: usize) {
|
||||
for pool in self.pools.values_mut() {
|
||||
pool.prewarm(count);
|
||||
}
|
||||
self.update_stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预热指定池
|
||||
*/
|
||||
pub fn prewarm_pool(&mut self, component_type: ComponentType, count: usize) {
|
||||
if let Some(pool) = self.pools.get_mut(&component_type) {
|
||||
pool.prewarm(count);
|
||||
self.update_stats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有池
|
||||
*/
|
||||
pub fn clear_all(&mut self) {
|
||||
for pool in self.pools.values_mut() {
|
||||
pool.clear();
|
||||
}
|
||||
self.update_stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空指定池
|
||||
*/
|
||||
pub fn clear_pool(&mut self, component_type: ComponentType) {
|
||||
if let Some(pool) = self.pools.get_mut(&component_type) {
|
||||
pool.clear();
|
||||
self.update_stats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有注册的池
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.pools.clear();
|
||||
self.stats = ComponentPoolManagerStats::default();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池统计信息
|
||||
*/
|
||||
pub fn get_pool_stats(&self) -> FxHashMap<ComponentType, PoolStatsSummary> {
|
||||
let mut stats = FxHashMap::default();
|
||||
|
||||
for (&component_type, pool) in &self.pools {
|
||||
let summary = PoolStatsSummary {
|
||||
available: pool.available_count(),
|
||||
max_size: pool.max_size(),
|
||||
used: pool.used_count(),
|
||||
utilization_rate: pool.utilization_rate(),
|
||||
hit_rate: pool.hit_rate(),
|
||||
memory_usage: pool.estimated_memory_usage(),
|
||||
};
|
||||
stats.insert(component_type, summary);
|
||||
}
|
||||
|
||||
stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定组件的池利用率
|
||||
*/
|
||||
pub fn get_component_utilization(&self, component_type: ComponentType) -> f32 {
|
||||
self.pools.get(&component_type)
|
||||
.map(|pool| pool.utilization_rate())
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定组件的池命中率
|
||||
*/
|
||||
pub fn get_component_hit_rate(&self, component_type: ComponentType) -> f32 {
|
||||
self.pools.get(&component_type)
|
||||
.map(|pool| pool.hit_rate())
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取管理器统计信息
|
||||
*/
|
||||
pub fn get_manager_stats(&self) -> ComponentPoolManagerStats {
|
||||
self.stats.clone()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有池的总内存使用量
|
||||
*/
|
||||
pub fn get_total_memory_usage(&self) -> usize {
|
||||
self.pools.values()
|
||||
.map(|pool| pool.estimated_memory_usage())
|
||||
.sum()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否注册了指定组件类型的池
|
||||
*/
|
||||
pub fn has_pool(&self, component_type: ComponentType) -> bool {
|
||||
self.pools.contains_key(&component_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注册的池数量
|
||||
*/
|
||||
pub fn pool_count(&self) -> usize {
|
||||
self.pools.len()
|
||||
}
|
||||
|
||||
// 私有方法
|
||||
|
||||
/**
|
||||
* 更新管理器统计信息
|
||||
*/
|
||||
fn update_stats(&mut self) {
|
||||
self.stats.registered_pools = self.pools.len() as u32;
|
||||
self.stats.total_memory_usage = self.get_total_memory_usage();
|
||||
self.stats.total_components_managed = self.pools.values()
|
||||
.map(|pool| pool.used_count() + pool.available_count() as u32)
|
||||
.sum();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ComponentPoolManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::TypeId;
|
||||
|
||||
// 测试用的示例组件
|
||||
#[derive(Clone, Default, Debug, PartialEq)]
|
||||
struct TestComponent {
|
||||
pub value: i32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl Component for TestComponent {
|
||||
fn id(&self) -> u32 { 0 }
|
||||
fn set_enabled(&mut self, _enabled: bool) {}
|
||||
fn set_update_order(&mut self, _order: i32) {}
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
fn clone_box(&self) -> Box<dyn Component> { Box::new(self.clone()) }
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct AnotherTestComponent {
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
impl Component for AnotherTestComponent {
|
||||
fn id(&self) -> u32 { 0 }
|
||||
fn set_enabled(&mut self, _enabled: bool) {}
|
||||
fn set_update_order(&mut self, _order: i32) {}
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
fn clone_box(&self) -> Box<dyn Component> { Box::new(self.clone()) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_basic() {
|
||||
let pool = ComponentPool::<TestComponent>::with_default(10);
|
||||
|
||||
// 测试基本属性
|
||||
assert_eq!(pool.available_count(), 0);
|
||||
assert_eq!(pool.max_size(), 10);
|
||||
assert_eq!(pool.utilization_rate(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_acquire_release() {
|
||||
let mut pool = ComponentPool::<TestComponent>::with_default(5);
|
||||
|
||||
// 第一次获取应该创建新实例
|
||||
let mut component1 = pool.acquire();
|
||||
component1.value = 42;
|
||||
component1.name = "test".to_string();
|
||||
|
||||
assert_eq!(pool.available_count(), 0);
|
||||
assert_eq!(pool.get_stats().pool_misses, 1);
|
||||
|
||||
// 释放组件
|
||||
pool.release(component1);
|
||||
assert_eq!(pool.available_count(), 1);
|
||||
|
||||
// 再次获取应该从池中获取
|
||||
let component2 = pool.acquire();
|
||||
assert_eq!(pool.available_count(), 0);
|
||||
assert_eq!(pool.get_stats().pool_hits, 1);
|
||||
|
||||
// 验证是同一个实例(虽然值可能不同)
|
||||
assert_eq!(component2.value, 42); // 没有重置函数,值保持不变
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_with_reset() {
|
||||
let reset_fn = |comp: &mut TestComponent| {
|
||||
comp.value = 0;
|
||||
comp.name.clear();
|
||||
};
|
||||
|
||||
let mut pool = ComponentPool::with_default_and_reset(reset_fn, 5);
|
||||
|
||||
let mut component = pool.acquire();
|
||||
component.value = 42;
|
||||
component.name = "test".to_string();
|
||||
|
||||
pool.release(component);
|
||||
|
||||
let component2 = pool.acquire();
|
||||
assert_eq!(component2.value, 0);
|
||||
assert_eq!(component2.name, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_max_capacity() {
|
||||
let mut pool = ComponentPool::<TestComponent>::with_default(2);
|
||||
|
||||
// 获取3个组件
|
||||
let comp1 = pool.acquire();
|
||||
let comp2 = pool.acquire();
|
||||
let comp3 = pool.acquire();
|
||||
|
||||
// 释放所有组件
|
||||
pool.release(comp1);
|
||||
pool.release(comp2);
|
||||
pool.release(comp3);
|
||||
|
||||
// 只有2个组件被存储在池中(最大容量限制)
|
||||
assert_eq!(pool.available_count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_prewarm() {
|
||||
let mut pool = ComponentPool::<TestComponent>::with_default(10);
|
||||
|
||||
pool.prewarm(5);
|
||||
assert_eq!(pool.available_count(), 5);
|
||||
|
||||
// 预热不应该超过最大容量
|
||||
pool.prewarm(10);
|
||||
assert_eq!(pool.available_count(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_stats() {
|
||||
let mut pool = ComponentPool::<TestComponent>::with_default(5);
|
||||
|
||||
// 获取一些组件
|
||||
let _comp1 = pool.acquire();
|
||||
let _comp2 = pool.acquire();
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_acquires, 2);
|
||||
assert_eq!(stats.pool_misses, 2);
|
||||
assert_eq!(stats.pool_hits, 0);
|
||||
assert_eq!(stats.total_created, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_manager_basic() {
|
||||
let mut manager = ComponentPoolManager::new();
|
||||
|
||||
// 注册池
|
||||
manager.register_pool_default::<TestComponent>(TypeId::of::<TestComponent>(), Some(20));
|
||||
|
||||
assert!(manager.has_pool(TypeId::of::<TestComponent>()));
|
||||
assert_eq!(manager.pool_count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_manager_acquire_release() {
|
||||
let mut manager = ComponentPoolManager::new();
|
||||
|
||||
manager.register_pool_default::<TestComponent>(TypeId::of::<TestComponent>(), Some(10));
|
||||
|
||||
// 获取组件
|
||||
let mut component = manager.acquire_component::<TestComponent>(TypeId::of::<TestComponent>()).unwrap();
|
||||
component.value = 42;
|
||||
|
||||
// 释放组件
|
||||
manager.release_component(TypeId::of::<TestComponent>(), component);
|
||||
|
||||
// 再次获取应该从池中获取
|
||||
let reused_component = manager.acquire_component::<TestComponent>(TypeId::of::<TestComponent>()).unwrap();
|
||||
assert_eq!(reused_component.value, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_manager_multiple_types() {
|
||||
let mut manager = ComponentPoolManager::new();
|
||||
|
||||
manager.register_pool_default::<TestComponent>(TypeId::of::<TestComponent>(), Some(10));
|
||||
manager.register_pool_default::<AnotherTestComponent>(TypeId::of::<AnotherTestComponent>(), Some(15));
|
||||
|
||||
assert_eq!(manager.pool_count(), 2);
|
||||
|
||||
// 测试不同类型的组件
|
||||
let _test_comp = manager.acquire_component::<TestComponent>(TypeId::of::<TestComponent>()).unwrap();
|
||||
let _another_comp = manager.acquire_component::<AnotherTestComponent>(TypeId::of::<AnotherTestComponent>()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_manager_stats() {
|
||||
let mut manager = ComponentPoolManager::new();
|
||||
|
||||
manager.register_pool_default::<TestComponent>(TypeId::of::<TestComponent>(), Some(10));
|
||||
manager.prewarm_pool(TypeId::of::<TestComponent>(), 5);
|
||||
|
||||
let stats = manager.get_pool_stats();
|
||||
let test_comp_stats = stats.get(&TypeId::of::<TestComponent>()).unwrap();
|
||||
|
||||
assert_eq!(test_comp_stats.available, 5);
|
||||
assert_eq!(test_comp_stats.max_size, 10);
|
||||
assert!(test_comp_stats.memory_usage > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_manager_prewarm_and_clear() {
|
||||
let mut manager = ComponentPoolManager::new();
|
||||
|
||||
manager.register_pool_default::<TestComponent>(TypeId::of::<TestComponent>(), Some(10));
|
||||
manager.register_pool_default::<AnotherTestComponent>(TypeId::of::<AnotherTestComponent>(), Some(10));
|
||||
|
||||
// 预热所有池
|
||||
manager.prewarm_all(5);
|
||||
|
||||
let stats = manager.get_pool_stats();
|
||||
assert_eq!(stats.get(&TypeId::of::<TestComponent>()).unwrap().available, 5);
|
||||
assert_eq!(stats.get(&TypeId::of::<AnotherTestComponent>()).unwrap().available, 5);
|
||||
|
||||
// 清空所有池
|
||||
manager.clear_all();
|
||||
|
||||
let stats = manager.get_pool_stats();
|
||||
assert_eq!(stats.get(&TypeId::of::<TestComponent>()).unwrap().available, 0);
|
||||
assert_eq!(stats.get(&TypeId::of::<AnotherTestComponent>()).unwrap().available, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_pool_manager_unknown_type() {
|
||||
let mut manager = ComponentPoolManager::new();
|
||||
|
||||
// 尝试获取未注册类型的组件
|
||||
let result = manager.acquire_component::<TestComponent>(TypeId::of::<TestComponent>());
|
||||
assert!(result.is_none());
|
||||
|
||||
// 释放到未注册的池应该安全处理
|
||||
let component = TestComponent::default();
|
||||
manager.release_component(TypeId::of::<TestComponent>(), component); // 不应该panic
|
||||
}
|
||||
}
|
||||
1060
packages/core-rust/src/utils/debug.rs
Normal file
1060
packages/core-rust/src/utils/debug.rs
Normal file
File diff suppressed because it is too large
Load Diff
896
packages/core-rust/src/utils/dirty_tracking.rs
Normal file
896
packages/core-rust/src/utils/dirty_tracking.rs
Normal file
@@ -0,0 +1,896 @@
|
||||
use crate::utils::ComponentType;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/**
|
||||
* 脏标记类型
|
||||
* 使用位标记来表示不同类型的变更
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DirtyFlag(pub u32);
|
||||
|
||||
impl DirtyFlag {
|
||||
/// 组件数据已修改
|
||||
pub const COMPONENT_MODIFIED: DirtyFlag = DirtyFlag(1 << 0);
|
||||
/// 组件已添加
|
||||
pub const COMPONENT_ADDED: DirtyFlag = DirtyFlag(1 << 1);
|
||||
/// 组件已移除
|
||||
pub const COMPONENT_REMOVED: DirtyFlag = DirtyFlag(1 << 2);
|
||||
/// 实体位置已改变
|
||||
pub const TRANSFORM_CHANGED: DirtyFlag = DirtyFlag(1 << 3);
|
||||
/// 实体状态已改变
|
||||
pub const STATE_CHANGED: DirtyFlag = DirtyFlag(1 << 4);
|
||||
/// 实体层次结构已改变
|
||||
pub const HIERARCHY_CHANGED: DirtyFlag = DirtyFlag(1 << 5);
|
||||
/// 实体可见性已改变
|
||||
pub const VISIBILITY_CHANGED: DirtyFlag = DirtyFlag(1 << 6);
|
||||
/// 实体启用状态已改变
|
||||
pub const ENABLED_CHANGED: DirtyFlag = DirtyFlag(1 << 7);
|
||||
/// 自定义标记1
|
||||
pub const CUSTOM_1: DirtyFlag = DirtyFlag(1 << 8);
|
||||
/// 自定义标记2
|
||||
pub const CUSTOM_2: DirtyFlag = DirtyFlag(1 << 9);
|
||||
/// 自定义标记3
|
||||
pub const CUSTOM_3: DirtyFlag = DirtyFlag(1 << 10);
|
||||
/// 自定义标记4
|
||||
pub const CUSTOM_4: DirtyFlag = DirtyFlag(1 << 11);
|
||||
/// 所有标记
|
||||
pub const ALL: DirtyFlag = DirtyFlag(0xFFFFFFFF);
|
||||
|
||||
/**
|
||||
* 检查是否包含指定标记
|
||||
*/
|
||||
pub fn contains(self, other: DirtyFlag) -> bool {
|
||||
(self.0 & other.0) != 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加标记
|
||||
*/
|
||||
pub fn add(&mut self, other: DirtyFlag) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除标记
|
||||
*/
|
||||
pub fn remove(&mut self, other: DirtyFlag) {
|
||||
self.0 &= !other.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有标记
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.0 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为空
|
||||
*/
|
||||
pub fn is_empty(self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 与操作
|
||||
*/
|
||||
pub fn and(self, other: DirtyFlag) -> DirtyFlag {
|
||||
DirtyFlag(self.0 & other.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 或操作
|
||||
*/
|
||||
pub fn or(self, other: DirtyFlag) -> DirtyFlag {
|
||||
DirtyFlag(self.0 | other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for DirtyFlag {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
DirtyFlag(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAnd for DirtyFlag {
|
||||
type Output = Self;
|
||||
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
DirtyFlag(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOrAssign for DirtyFlag {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAndAssign for DirtyFlag {
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
self.0 &= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脏标记数据
|
||||
* 记录实体的变更信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DirtyData {
|
||||
/// 实体ID
|
||||
pub entity_id: u32,
|
||||
/// 脏标记位
|
||||
pub flags: DirtyFlag,
|
||||
/// 修改的组件类型列表
|
||||
pub modified_components: HashSet<ComponentType>,
|
||||
/// 标记时间戳(毫秒)
|
||||
pub timestamp: u64,
|
||||
/// 帧编号
|
||||
pub frame_number: u64,
|
||||
}
|
||||
|
||||
impl DirtyData {
|
||||
/**
|
||||
* 创建新的脏标记数据
|
||||
*/
|
||||
pub fn new(entity_id: u32, flags: DirtyFlag, frame_number: u64) -> Self {
|
||||
Self {
|
||||
entity_id,
|
||||
flags,
|
||||
modified_components: HashSet::new(),
|
||||
timestamp: current_timestamp(),
|
||||
frame_number,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加修改的组件类型
|
||||
*/
|
||||
pub fn add_modified_component(&mut self, component_type: ComponentType) {
|
||||
self.modified_components.insert(component_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否包含指定的脏标记
|
||||
*/
|
||||
pub fn has_flags(&self, flags: DirtyFlag) -> bool {
|
||||
self.flags.contains(flags)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新时间戳
|
||||
*/
|
||||
pub fn update_timestamp(&mut self) {
|
||||
self.timestamp = current_timestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取年龄(当前时间与标记时间的差值,毫秒)
|
||||
*/
|
||||
pub fn age(&self) -> u64 {
|
||||
current_timestamp().saturating_sub(self.timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脏标记监听器类型
|
||||
*/
|
||||
pub type DirtyListener = Box<dyn Fn(&DirtyData) + Send + Sync>;
|
||||
|
||||
/**
|
||||
* 脏标记监听器配置
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct DirtyListenerConfig {
|
||||
/// 感兴趣的标记类型
|
||||
pub flags: DirtyFlag,
|
||||
/// 监听器优先级(数字越小优先级越高)
|
||||
pub priority: i32,
|
||||
/// 监听器ID(用于移除)
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
/**
|
||||
* 脏标记监听器条目
|
||||
*/
|
||||
pub struct DirtyListenerEntry {
|
||||
pub config: DirtyListenerConfig,
|
||||
pub callback: DirtyListener,
|
||||
}
|
||||
|
||||
/**
|
||||
* 脏标记统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DirtyTrackingStats {
|
||||
/// 当前脏实体数量
|
||||
pub dirty_entity_count: usize,
|
||||
/// 总标记次数
|
||||
pub total_markings: u64,
|
||||
/// 总清理次数
|
||||
pub total_cleanups: u64,
|
||||
/// 监听器数量
|
||||
pub listener_count: usize,
|
||||
/// 当前帧编号
|
||||
pub current_frame: u64,
|
||||
/// 平均每帧脏实体数量
|
||||
pub avg_dirty_per_frame: f64,
|
||||
/// 处理的实体总数
|
||||
pub total_processed_entities: u64,
|
||||
/// 内存使用量估算(字节)
|
||||
pub estimated_memory_usage: usize,
|
||||
/// 最大处理时间(毫秒)
|
||||
pub max_processing_time: f64,
|
||||
/// 平均处理时间(毫秒)
|
||||
pub avg_processing_time: f64,
|
||||
}
|
||||
|
||||
impl Default for DirtyTrackingStats {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dirty_entity_count: 0,
|
||||
total_markings: 0,
|
||||
total_cleanups: 0,
|
||||
listener_count: 0,
|
||||
current_frame: 0,
|
||||
avg_dirty_per_frame: 0.0,
|
||||
total_processed_entities: 0,
|
||||
estimated_memory_usage: 0,
|
||||
max_processing_time: 0.0,
|
||||
avg_processing_time: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脏标记追踪系统
|
||||
*
|
||||
* 提供高效的组件和实体变更追踪,避免不必要的计算和更新。
|
||||
* 支持细粒度的脏标记和批量处理机制。
|
||||
*/
|
||||
pub struct DirtyTrackingSystem {
|
||||
/// 脏实体映射表
|
||||
dirty_entities: FxHashMap<u32, DirtyData>,
|
||||
/// 脏标记监听器
|
||||
listeners: Vec<DirtyListenerEntry>,
|
||||
/// 下一个监听器ID
|
||||
next_listener_id: u64,
|
||||
/// 当前帧编号
|
||||
current_frame: u64,
|
||||
/// 批处理配置
|
||||
batch_size: usize,
|
||||
max_processing_time_ms: f64,
|
||||
/// 处理队列
|
||||
processing_queue: Vec<DirtyData>,
|
||||
is_processing: bool,
|
||||
/// 统计信息
|
||||
stats: DirtyTrackingStats,
|
||||
/// 帧统计累积
|
||||
frame_stats: FrameStats,
|
||||
/// 处理时间记录
|
||||
processing_times: Vec<f64>,
|
||||
max_processing_time_history: usize,
|
||||
}
|
||||
|
||||
/**
|
||||
* 帧统计信息累积
|
||||
*/
|
||||
#[derive(Debug, Default)]
|
||||
struct FrameStats {
|
||||
total_dirty_entities: u64,
|
||||
frame_count: u64,
|
||||
total_processing_time: f64,
|
||||
}
|
||||
|
||||
impl DirtyTrackingSystem {
|
||||
/**
|
||||
* 创建新的脏标记追踪系统
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
dirty_entities: FxHashMap::default(),
|
||||
listeners: Vec::new(),
|
||||
next_listener_id: 1,
|
||||
current_frame: 0,
|
||||
batch_size: 100,
|
||||
max_processing_time_ms: 16.0,
|
||||
processing_queue: Vec::new(),
|
||||
is_processing: false,
|
||||
stats: DirtyTrackingStats::default(),
|
||||
frame_stats: FrameStats::default(),
|
||||
processing_times: Vec::new(),
|
||||
max_processing_time_history: 100,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记实体为脏状态
|
||||
*/
|
||||
pub fn mark_dirty(
|
||||
&mut self,
|
||||
entity_id: u32,
|
||||
flags: DirtyFlag,
|
||||
modified_components: Option<Vec<ComponentType>>
|
||||
) {
|
||||
self.stats.total_markings += 1;
|
||||
|
||||
let dirty_data = self.dirty_entities.entry(entity_id).or_insert_with(|| {
|
||||
DirtyData::new(entity_id, DirtyFlag(0), self.current_frame)
|
||||
});
|
||||
|
||||
dirty_data.flags |= flags;
|
||||
dirty_data.update_timestamp();
|
||||
dirty_data.frame_number = self.current_frame;
|
||||
|
||||
if let Some(components) = modified_components {
|
||||
for component_type in components {
|
||||
dirty_data.add_modified_component(component_type);
|
||||
}
|
||||
}
|
||||
|
||||
// 克隆dirty_data以避免借用冲突
|
||||
let dirty_data_for_notify = dirty_data.clone();
|
||||
|
||||
// 立即通知监听器
|
||||
self.notify_listeners(&dirty_data_for_notify, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否有指定的脏标记
|
||||
*/
|
||||
pub fn is_dirty(&self, entity_id: u32, flags: DirtyFlag) -> bool {
|
||||
self.dirty_entities
|
||||
.get(&entity_id)
|
||||
.map(|data| data.has_flags(flags))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除实体的脏标记
|
||||
*/
|
||||
pub fn clear_dirty(&mut self, entity_id: u32, flags: DirtyFlag) {
|
||||
if let Some(dirty_data) = self.dirty_entities.get_mut(&entity_id) {
|
||||
dirty_data.flags.remove(flags);
|
||||
|
||||
if dirty_data.flags.is_empty() {
|
||||
self.dirty_entities.remove(&entity_id);
|
||||
}
|
||||
|
||||
self.stats.total_cleanups += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有脏标记
|
||||
*/
|
||||
pub fn clear_all_dirty(&mut self) {
|
||||
let count = self.dirty_entities.len();
|
||||
self.dirty_entities.clear();
|
||||
self.stats.total_cleanups += count as u64;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有脏实体
|
||||
*/
|
||||
pub fn get_dirty_entities(&self, flags: DirtyFlag) -> Vec<&DirtyData> {
|
||||
self.dirty_entities
|
||||
.values()
|
||||
.filter(|data| data.has_flags(flags))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取脏实体数量
|
||||
*/
|
||||
pub fn dirty_entity_count(&self) -> usize {
|
||||
self.dirty_entities.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定标记的脏实体数量
|
||||
*/
|
||||
pub fn dirty_entity_count_with_flags(&self, flags: DirtyFlag) -> usize {
|
||||
self.dirty_entities
|
||||
.values()
|
||||
.filter(|data| data.has_flags(flags))
|
||||
.count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量处理脏实体
|
||||
*/
|
||||
pub fn process_dirty_entities(&mut self) {
|
||||
if self.is_processing {
|
||||
return;
|
||||
}
|
||||
|
||||
self.is_processing = true;
|
||||
let start_time = current_timestamp_f64();
|
||||
|
||||
// 填充处理队列
|
||||
if self.processing_queue.is_empty() {
|
||||
self.processing_queue.extend(
|
||||
self.dirty_entities.values().cloned()
|
||||
);
|
||||
}
|
||||
|
||||
let mut processed = 0;
|
||||
while !self.processing_queue.is_empty() && processed < self.batch_size {
|
||||
let elapsed = current_timestamp_f64() - start_time;
|
||||
if elapsed > self.max_processing_time_ms {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(dirty_data) = self.processing_queue.pop() {
|
||||
self.process_entity(&dirty_data);
|
||||
processed += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果处理完成,更新统计信息
|
||||
if self.processing_queue.is_empty() {
|
||||
self.is_processing = false;
|
||||
|
||||
let processing_time = current_timestamp_f64() - start_time;
|
||||
self.record_processing_time(processing_time);
|
||||
self.stats.total_processed_entities += processed as u64;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加脏标记监听器
|
||||
*/
|
||||
pub fn add_listener<F>(&mut self, flags: DirtyFlag, priority: i32, callback: F) -> u64
|
||||
where
|
||||
F: Fn(&DirtyData) + Send + Sync + 'static,
|
||||
{
|
||||
let listener_id = self.next_listener_id;
|
||||
self.next_listener_id += 1;
|
||||
|
||||
let config = DirtyListenerConfig {
|
||||
flags,
|
||||
priority,
|
||||
id: listener_id,
|
||||
};
|
||||
|
||||
let entry = DirtyListenerEntry {
|
||||
config,
|
||||
callback: Box::new(callback),
|
||||
};
|
||||
|
||||
self.listeners.push(entry);
|
||||
|
||||
// 按优先级排序
|
||||
self.listeners.sort_by_key(|entry| entry.config.priority);
|
||||
|
||||
listener_id
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除脏标记监听器
|
||||
*/
|
||||
pub fn remove_listener(&mut self, listener_id: u64) -> bool {
|
||||
if let Some(pos) = self.listeners.iter().position(|entry| entry.config.id == listener_id) {
|
||||
self.listeners.remove(pos);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始新的帧
|
||||
*/
|
||||
pub fn begin_frame(&mut self) {
|
||||
self.current_frame += 1;
|
||||
self.stats.current_frame = self.current_frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束当前帧
|
||||
*/
|
||||
pub fn end_frame(&mut self) {
|
||||
if !self.is_processing {
|
||||
self.process_dirty_entities();
|
||||
}
|
||||
|
||||
// 更新帧统计
|
||||
self.frame_stats.total_dirty_entities += self.dirty_entities.len() as u64;
|
||||
self.frame_stats.frame_count += 1;
|
||||
|
||||
// 更新平均值
|
||||
if self.frame_stats.frame_count > 0 {
|
||||
self.stats.avg_dirty_per_frame =
|
||||
self.frame_stats.total_dirty_entities as f64 / self.frame_stats.frame_count as f64;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> DirtyTrackingStats {
|
||||
let mut stats = self.stats.clone();
|
||||
stats.dirty_entity_count = self.dirty_entities.len();
|
||||
stats.listener_count = self.listeners.len();
|
||||
stats.estimated_memory_usage = self.estimate_memory_usage();
|
||||
|
||||
// 计算平均处理时间
|
||||
if !self.processing_times.is_empty() {
|
||||
let total_time: f64 = self.processing_times.iter().sum();
|
||||
stats.avg_processing_time = total_time / self.processing_times.len() as f64;
|
||||
}
|
||||
|
||||
stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置批量处理参数
|
||||
*/
|
||||
pub fn configure_batch_processing(&mut self, batch_size: usize, max_processing_time_ms: f64) {
|
||||
self.batch_size = batch_size;
|
||||
self.max_processing_time_ms = max_processing_time_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有数据
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.dirty_entities.clear();
|
||||
self.processing_queue.clear();
|
||||
self.is_processing = false;
|
||||
self.stats = DirtyTrackingStats::default();
|
||||
self.frame_stats = FrameStats::default();
|
||||
self.processing_times.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取老旧的脏标记(超过指定时间未更新)
|
||||
*/
|
||||
pub fn get_stale_dirty_entities(&self, max_age_ms: u64) -> Vec<&DirtyData> {
|
||||
self.dirty_entities
|
||||
.values()
|
||||
.filter(|data| data.age() > max_age_ms)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理老旧的脏标记
|
||||
*/
|
||||
pub fn cleanup_stale_dirty_entities(&mut self, max_age_ms: u64) -> usize {
|
||||
let initial_count = self.dirty_entities.len();
|
||||
|
||||
self.dirty_entities.retain(|_, data| data.age() <= max_age_ms);
|
||||
|
||||
let removed_count = initial_count - self.dirty_entities.len();
|
||||
self.stats.total_cleanups += removed_count as u64;
|
||||
|
||||
removed_count
|
||||
}
|
||||
|
||||
// 私有方法
|
||||
|
||||
/**
|
||||
* 处理单个脏实体
|
||||
*/
|
||||
fn process_entity(&mut self, dirty_data: &DirtyData) {
|
||||
for entry in &self.listeners {
|
||||
if dirty_data.has_flags(entry.config.flags) {
|
||||
(entry.callback)(dirty_data);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理后清理
|
||||
self.clear_dirty(dirty_data.entity_id, DirtyFlag::ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知监听器
|
||||
*/
|
||||
fn notify_listeners(&self, dirty_data: &DirtyData, new_flags: DirtyFlag) {
|
||||
for entry in &self.listeners {
|
||||
if new_flags.contains(entry.config.flags) {
|
||||
(entry.callback)(dirty_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录处理时间
|
||||
*/
|
||||
fn record_processing_time(&mut self, time: f64) {
|
||||
self.processing_times.push(time);
|
||||
|
||||
// 保持历史记录长度限制
|
||||
if self.processing_times.len() > self.max_processing_time_history {
|
||||
self.processing_times.remove(0);
|
||||
}
|
||||
|
||||
// 更新最大处理时间
|
||||
if time > self.stats.max_processing_time {
|
||||
self.stats.max_processing_time = time;
|
||||
}
|
||||
|
||||
self.frame_stats.total_processing_time += time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 估算内存使用量
|
||||
*/
|
||||
fn estimate_memory_usage(&self) -> usize {
|
||||
let dirty_entities_size = self.dirty_entities.len() *
|
||||
(std::mem::size_of::<u32>() + std::mem::size_of::<DirtyData>());
|
||||
|
||||
let listeners_size = self.listeners.len() * std::mem::size_of::<DirtyListenerEntry>();
|
||||
|
||||
let processing_queue_size = self.processing_queue.len() * std::mem::size_of::<DirtyData>();
|
||||
|
||||
let processing_times_size = self.processing_times.len() * std::mem::size_of::<f64>();
|
||||
|
||||
dirty_entities_size + listeners_size + processing_queue_size + processing_times_size
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DirtyTrackingSystem {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(毫秒)
|
||||
*/
|
||||
fn current_timestamp() -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(浮点毫秒,用于精确计时)
|
||||
*/
|
||||
fn current_timestamp_f64() -> f64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs_f64() * 1000.0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::TypeId;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[test]
|
||||
fn test_dirty_flag_operations() {
|
||||
let mut flags = DirtyFlag::COMPONENT_MODIFIED;
|
||||
|
||||
assert!(flags.contains(DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(!flags.contains(DirtyFlag::COMPONENT_ADDED));
|
||||
|
||||
flags.add(DirtyFlag::COMPONENT_ADDED);
|
||||
assert!(flags.contains(DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(flags.contains(DirtyFlag::COMPONENT_ADDED));
|
||||
|
||||
flags.remove(DirtyFlag::COMPONENT_MODIFIED);
|
||||
assert!(!flags.contains(DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(flags.contains(DirtyFlag::COMPONENT_ADDED));
|
||||
|
||||
flags.clear();
|
||||
assert!(flags.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_flag_bitwise_operations() {
|
||||
let flag1 = DirtyFlag::COMPONENT_MODIFIED;
|
||||
let flag2 = DirtyFlag::COMPONENT_ADDED;
|
||||
|
||||
let combined = flag1 | flag2;
|
||||
assert!(combined.contains(DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(combined.contains(DirtyFlag::COMPONENT_ADDED));
|
||||
|
||||
let intersection = combined & DirtyFlag::COMPONENT_MODIFIED;
|
||||
assert!(intersection.contains(DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(!intersection.contains(DirtyFlag::COMPONENT_ADDED));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_data_creation() {
|
||||
let entity_id = 123;
|
||||
let flags = DirtyFlag::TRANSFORM_CHANGED;
|
||||
let frame_number = 42;
|
||||
|
||||
let dirty_data = DirtyData::new(entity_id, flags, frame_number);
|
||||
|
||||
assert_eq!(dirty_data.entity_id, entity_id);
|
||||
assert!(dirty_data.has_flags(flags));
|
||||
assert_eq!(dirty_data.frame_number, frame_number);
|
||||
assert!(dirty_data.modified_components.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_data_component_tracking() {
|
||||
let mut dirty_data = DirtyData::new(1, DirtyFlag::COMPONENT_MODIFIED, 0);
|
||||
let component_type = TypeId::of::<String>();
|
||||
|
||||
dirty_data.add_modified_component(component_type);
|
||||
assert!(dirty_data.modified_components.contains(&component_type));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_basic() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
let entity_id = 1;
|
||||
let flags = DirtyFlag::COMPONENT_MODIFIED;
|
||||
|
||||
// 标记实体为脏状态
|
||||
system.mark_dirty(entity_id, flags, None);
|
||||
|
||||
assert!(system.is_dirty(entity_id, flags));
|
||||
assert!(!system.is_dirty(entity_id, DirtyFlag::COMPONENT_ADDED));
|
||||
assert_eq!(system.dirty_entity_count(), 1);
|
||||
|
||||
// 清除脏标记
|
||||
system.clear_dirty(entity_id, flags);
|
||||
assert!(!system.is_dirty(entity_id, flags));
|
||||
assert_eq!(system.dirty_entity_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_multiple_flags() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
let entity_id = 1;
|
||||
|
||||
// 标记多个类型的脏状态
|
||||
system.mark_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
system.mark_dirty(entity_id, DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
|
||||
assert!(system.is_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(system.is_dirty(entity_id, DirtyFlag::TRANSFORM_CHANGED));
|
||||
assert!(system.is_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED | DirtyFlag::TRANSFORM_CHANGED));
|
||||
|
||||
// 部分清除
|
||||
system.clear_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED);
|
||||
assert!(!system.is_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED));
|
||||
assert!(system.is_dirty(entity_id, DirtyFlag::TRANSFORM_CHANGED));
|
||||
|
||||
// 全部清除
|
||||
system.clear_dirty(entity_id, DirtyFlag::ALL);
|
||||
assert!(!system.is_dirty(entity_id, DirtyFlag::TRANSFORM_CHANGED));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_listener() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
let entity_id = 1;
|
||||
|
||||
// 使用Arc<Mutex>来在闭包中共享状态
|
||||
let callback_count = Arc::new(Mutex::new(0));
|
||||
let callback_count_clone = Arc::clone(&callback_count);
|
||||
|
||||
// 添加监听器
|
||||
let listener_id = system.add_listener(
|
||||
DirtyFlag::COMPONENT_MODIFIED,
|
||||
0,
|
||||
move |_data| {
|
||||
*callback_count_clone.lock().unwrap() += 1;
|
||||
}
|
||||
);
|
||||
|
||||
// 标记脏状态应该触发监听器
|
||||
system.mark_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
assert_eq!(*callback_count.lock().unwrap(), 1);
|
||||
|
||||
// 标记其他类型的脏状态不应该触发监听器
|
||||
system.mark_dirty(entity_id, DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
assert_eq!(*callback_count.lock().unwrap(), 1);
|
||||
|
||||
// 移除监听器
|
||||
assert!(system.remove_listener(listener_id));
|
||||
|
||||
// 再次标记脏状态不应该触发监听器
|
||||
system.mark_dirty(entity_id, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
assert_eq!(*callback_count.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_filtering() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
|
||||
system.mark_dirty(1, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
system.mark_dirty(2, DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
system.mark_dirty(3, DirtyFlag::COMPONENT_MODIFIED | DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
|
||||
// 获取包含组件修改标记的实体
|
||||
let component_modified = system.get_dirty_entities(DirtyFlag::COMPONENT_MODIFIED);
|
||||
assert_eq!(component_modified.len(), 2); // 实体1和3
|
||||
|
||||
// 获取包含变换修改标记的实体
|
||||
let transform_changed = system.get_dirty_entities(DirtyFlag::TRANSFORM_CHANGED);
|
||||
assert_eq!(transform_changed.len(), 2); // 实体2和3
|
||||
|
||||
// 获取包含两种标记的实体
|
||||
let both_flags = system.get_dirty_entities(DirtyFlag::COMPONENT_MODIFIED | DirtyFlag::TRANSFORM_CHANGED);
|
||||
assert_eq!(both_flags.len(), 3); // 所有实体
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_stats() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
|
||||
system.mark_dirty(1, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
system.mark_dirty(2, DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
system.clear_dirty(1, DirtyFlag::ALL);
|
||||
|
||||
let stats = system.get_stats();
|
||||
assert_eq!(stats.total_markings, 2);
|
||||
assert_eq!(stats.total_cleanups, 1);
|
||||
assert_eq!(stats.dirty_entity_count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_stale_cleanup() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
|
||||
system.mark_dirty(1, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
system.mark_dirty(2, DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
|
||||
// 等待一小段时间让标记变老
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
|
||||
// 清理超过5毫秒的老标记
|
||||
let removed_count = system.cleanup_stale_dirty_entities(5);
|
||||
assert_eq!(removed_count, 2);
|
||||
assert_eq!(system.dirty_entity_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_frame_management() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
|
||||
system.begin_frame();
|
||||
assert_eq!(system.get_stats().current_frame, 1);
|
||||
|
||||
system.mark_dirty(1, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
system.end_frame();
|
||||
|
||||
let stats = system.get_stats();
|
||||
assert_eq!(stats.current_frame, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_batch_configuration() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
|
||||
system.configure_batch_processing(50, 8.0);
|
||||
assert_eq!(system.batch_size, 50);
|
||||
assert_eq!(system.max_processing_time_ms, 8.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_tracking_clear() {
|
||||
let mut system = DirtyTrackingSystem::new();
|
||||
|
||||
system.mark_dirty(1, DirtyFlag::COMPONENT_MODIFIED, None);
|
||||
system.mark_dirty(2, DirtyFlag::TRANSFORM_CHANGED, None);
|
||||
|
||||
let _listener_id = system.add_listener(DirtyFlag::ALL, 0, |_| {});
|
||||
|
||||
assert_eq!(system.dirty_entity_count(), 2);
|
||||
assert_eq!(system.listeners.len(), 1);
|
||||
|
||||
system.clear();
|
||||
|
||||
assert_eq!(system.dirty_entity_count(), 0);
|
||||
// 注意:clear()不会清除监听器
|
||||
assert_eq!(system.listeners.len(), 1);
|
||||
assert_eq!(system.get_stats().total_markings, 0);
|
||||
}
|
||||
}
|
||||
818
packages/core-rust/src/utils/extensions.rs
Normal file
818
packages/core-rust/src/utils/extensions.rs
Normal file
@@ -0,0 +1,818 @@
|
||||
use std::any::{Any, TypeId};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/**
|
||||
* 数字扩展工具
|
||||
* 提供数字转换和处理的实用方法
|
||||
*/
|
||||
pub struct NumberExtension;
|
||||
|
||||
impl NumberExtension {
|
||||
/**
|
||||
* 将Option<T>转换为数字,如果值为None则返回0
|
||||
*/
|
||||
pub fn to_number_from_option<T>(value: Option<T>) -> f64
|
||||
where
|
||||
T: Into<f64>,
|
||||
{
|
||||
value.map(|v| v.into()).unwrap_or(0.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为数字,如果解析失败则返回默认值
|
||||
*/
|
||||
pub fn parse_or_default(value: &str, default: f64) -> f64 {
|
||||
value.parse::<f64>().unwrap_or(default)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为数字,如果解析失败则返回0
|
||||
*/
|
||||
pub fn parse_or_zero(value: &str) -> f64 {
|
||||
Self::parse_or_default(value, 0.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为整数,如果解析失败则返回默认值
|
||||
*/
|
||||
pub fn parse_int_or_default(value: &str, default: i64) -> i64 {
|
||||
value.parse::<i64>().unwrap_or(default)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为整数,如果解析失败则返回0
|
||||
*/
|
||||
pub fn parse_int_or_zero(value: &str) -> i64 {
|
||||
Self::parse_int_or_default(value, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将布尔值转换为数字
|
||||
*/
|
||||
pub fn bool_to_number(value: bool) -> f64 {
|
||||
if value { 1.0 } else { 0.0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数字转换为布尔值
|
||||
*/
|
||||
pub fn number_to_bool(value: f64) -> bool {
|
||||
value != 0.0
|
||||
}
|
||||
|
||||
/**
|
||||
* 限制数字在指定范围内
|
||||
*/
|
||||
pub fn clamp(value: f64, min: f64, max: f64) -> f64 {
|
||||
if value < min {
|
||||
min
|
||||
} else if value > max {
|
||||
max
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数字是否在指定范围内
|
||||
*/
|
||||
pub fn is_in_range(value: f64, min: f64, max: f64) -> bool {
|
||||
value >= min && value <= max
|
||||
}
|
||||
|
||||
/**
|
||||
* 四舍五入到指定小数位数
|
||||
*/
|
||||
pub fn round_to_decimal_places(value: f64, decimal_places: u32) -> f64 {
|
||||
let multiplier = 10_f64.powi(decimal_places as i32);
|
||||
(value * multiplier).round() / multiplier
|
||||
}
|
||||
|
||||
/**
|
||||
* 将弧度转换为角度
|
||||
*/
|
||||
pub fn radians_to_degrees(radians: f64) -> f64 {
|
||||
radians * 180.0 / std::f64::consts::PI
|
||||
}
|
||||
|
||||
/**
|
||||
* 将角度转换为弧度
|
||||
*/
|
||||
pub fn degrees_to_radians(degrees: f64) -> f64 {
|
||||
degrees * std::f64::consts::PI / 180.0
|
||||
}
|
||||
|
||||
/**
|
||||
* 线性插值
|
||||
*/
|
||||
pub fn lerp(from: f64, to: f64, t: f64) -> f64 {
|
||||
from + (to - from) * t
|
||||
}
|
||||
|
||||
/**
|
||||
* 反向线性插值,返回t值
|
||||
*/
|
||||
pub fn inverse_lerp(from: f64, to: f64, value: f64) -> f64 {
|
||||
if (to - from).abs() < f64::EPSILON {
|
||||
0.0
|
||||
} else {
|
||||
(value - from) / (to - from)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个数字之间的距离
|
||||
*/
|
||||
pub fn distance(a: f64, b: f64) -> f64 {
|
||||
(a - b).abs()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查两个浮点数是否近似相等
|
||||
*/
|
||||
pub fn approximately_equal(a: f64, b: f64, epsilon: Option<f64>) -> bool {
|
||||
let eps = epsilon.unwrap_or(f64::EPSILON);
|
||||
(a - b).abs() < eps
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值包装在0到max之间(循环)
|
||||
*/
|
||||
pub fn wrap(value: f64, max: f64) -> f64 {
|
||||
if max <= 0.0 {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
let mut result = value % max;
|
||||
if result < 0.0 {
|
||||
result += max;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算数字的符号(-1, 0, 1)
|
||||
*/
|
||||
pub fn sign(value: f64) -> f64 {
|
||||
if value > 0.0 {
|
||||
1.0
|
||||
} else if value < 0.0 {
|
||||
-1.0
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型工具
|
||||
* 提供类型相关的实用方法
|
||||
*/
|
||||
pub struct TypeUtils;
|
||||
|
||||
impl TypeUtils {
|
||||
/**
|
||||
* 获取类型的TypeId
|
||||
*/
|
||||
pub fn get_type_id<T: 'static>() -> TypeId {
|
||||
TypeId::of::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象的TypeId
|
||||
*/
|
||||
pub fn get_object_type_id<T: 'static>(_obj: &T) -> TypeId {
|
||||
TypeId::of::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型名称
|
||||
*/
|
||||
pub fn get_type_name<T: 'static>() -> &'static str {
|
||||
std::any::type_name::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象的类型名称
|
||||
*/
|
||||
pub fn get_object_type_name<T: 'static>(_obj: &T) -> &'static str {
|
||||
std::any::type_name::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查两个类型是否相同
|
||||
*/
|
||||
pub fn is_same_type<T: 'static, U: 'static>() -> bool {
|
||||
TypeId::of::<T>() == TypeId::of::<U>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查对象是否为指定类型
|
||||
*/
|
||||
pub fn is_type<T: 'static, U: 'static>(_obj: &T) -> bool {
|
||||
TypeId::of::<T>() == TypeId::of::<U>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试将Any trait对象转换为具体类型
|
||||
*/
|
||||
pub fn downcast_ref<T: 'static>(obj: &dyn Any) -> Option<&T> {
|
||||
obj.downcast_ref::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试将可变Any trait对象转换为具体类型
|
||||
*/
|
||||
pub fn downcast_mut<T: 'static>(obj: &mut dyn Any) -> Option<&mut T> {
|
||||
obj.downcast_mut::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以转换为指定类型
|
||||
*/
|
||||
pub fn can_downcast<T: 'static>(obj: &dyn Any) -> bool {
|
||||
obj.is::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型的大小(字节)
|
||||
*/
|
||||
pub fn get_type_size<T>() -> usize {
|
||||
std::mem::size_of::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象的大小(字节)
|
||||
*/
|
||||
pub fn get_object_size<T>(obj: &T) -> usize {
|
||||
std::mem::size_of_val(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类型是否为零大小类型
|
||||
*/
|
||||
pub fn is_zero_sized<T>() -> bool {
|
||||
std::mem::size_of::<T>() == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型的对齐要求
|
||||
*/
|
||||
pub fn get_type_align<T>() -> usize {
|
||||
std::mem::align_of::<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类型是否实现了Copy trait(通过编译时检查)
|
||||
*/
|
||||
pub fn is_copy_type<T: Copy>() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类型是否实现了Clone trait(通过编译时检查)
|
||||
*/
|
||||
pub fn is_clone_type<T: Clone>() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类型是否实现了Debug trait(通过编译时检查)
|
||||
*/
|
||||
pub fn is_debug_type<T: Debug>() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地克隆对象(如果实现了Clone)
|
||||
*/
|
||||
pub fn safe_clone<T: Clone>(obj: &T) -> T {
|
||||
obj.clone()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型的显示字符串(如果实现了Debug)
|
||||
*/
|
||||
pub fn debug_string<T: Debug>(obj: &T) -> String {
|
||||
format!("{:?}", obj)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串扩展工具
|
||||
* 提供字符串处理的实用方法
|
||||
*/
|
||||
pub struct StringExtension;
|
||||
|
||||
impl StringExtension {
|
||||
/**
|
||||
* 检查字符串是否为空或仅包含空白字符
|
||||
*/
|
||||
pub fn is_null_or_whitespace(s: Option<&str>) -> bool {
|
||||
match s {
|
||||
None => true,
|
||||
Some(s) => s.trim().is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符串是否为空
|
||||
*/
|
||||
pub fn is_null_or_empty(s: Option<&str>) -> bool {
|
||||
match s {
|
||||
None => true,
|
||||
Some(s) => s.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 截断字符串到指定长度
|
||||
*/
|
||||
pub fn truncate(s: &str, max_length: usize) -> String {
|
||||
if s.len() <= max_length {
|
||||
s.to_string()
|
||||
} else {
|
||||
let mut truncated = String::with_capacity(max_length + 3);
|
||||
truncated.push_str(&s[..max_length]);
|
||||
truncated.push_str("...");
|
||||
truncated
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为Pascal命名
|
||||
*/
|
||||
pub fn to_pascal_case(s: &str) -> String {
|
||||
s.split_whitespace()
|
||||
.map(|word| {
|
||||
let mut chars = word.chars();
|
||||
match chars.next() {
|
||||
None => String::new(),
|
||||
Some(first) => first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase(),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("")
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为camel命名
|
||||
*/
|
||||
pub fn to_camel_case(s: &str) -> String {
|
||||
let pascal = Self::to_pascal_case(s);
|
||||
if pascal.is_empty() {
|
||||
return pascal;
|
||||
}
|
||||
|
||||
let mut chars = pascal.chars();
|
||||
match chars.next() {
|
||||
None => String::new(),
|
||||
Some(first) => first.to_lowercase().collect::<String>() + chars.as_str(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为snake_case
|
||||
*/
|
||||
pub fn to_snake_case(s: &str) -> String {
|
||||
s.chars()
|
||||
.enumerate()
|
||||
.flat_map(|(i, c)| {
|
||||
if i > 0 && c.is_uppercase() {
|
||||
vec!['_', c.to_lowercase().next().unwrap()]
|
||||
} else {
|
||||
vec![c.to_lowercase().next().unwrap()]
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重复字符串指定次数
|
||||
*/
|
||||
pub fn repeat(s: &str, count: usize) -> String {
|
||||
s.repeat(count)
|
||||
}
|
||||
|
||||
/**
|
||||
* 左侧填充字符到指定长度
|
||||
*/
|
||||
pub fn pad_left(s: &str, total_width: usize, pad_char: char) -> String {
|
||||
if s.len() >= total_width {
|
||||
s.to_string()
|
||||
} else {
|
||||
let pad_count = total_width - s.len();
|
||||
pad_char.to_string().repeat(pad_count) + s
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 右侧填充字符到指定长度
|
||||
*/
|
||||
pub fn pad_right(s: &str, total_width: usize, pad_char: char) -> String {
|
||||
if s.len() >= total_width {
|
||||
s.to_string()
|
||||
} else {
|
||||
let pad_count = total_width - s.len();
|
||||
s.to_string() + &pad_char.to_string().repeat(pad_count)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转字符串
|
||||
*/
|
||||
pub fn reverse(s: &str) -> String {
|
||||
s.chars().rev().collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计子字符串出现次数
|
||||
*/
|
||||
pub fn count_occurrences(s: &str, pattern: &str) -> usize {
|
||||
if pattern.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
let mut start = 0;
|
||||
|
||||
while let Some(pos) = s[start..].find(pattern) {
|
||||
count += 1;
|
||||
start += pos + pattern.len();
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除字符串中的所有空白字符
|
||||
*/
|
||||
pub fn remove_whitespace(s: &str) -> String {
|
||||
s.chars().filter(|c| !c.is_whitespace()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 集合扩展工具
|
||||
* 提供集合操作的实用方法
|
||||
*/
|
||||
pub struct CollectionExtension;
|
||||
|
||||
impl CollectionExtension {
|
||||
/**
|
||||
* 检查Vector是否为空或None
|
||||
*/
|
||||
pub fn is_null_or_empty<T>(vec: Option<&Vec<T>>) -> bool {
|
||||
match vec {
|
||||
None => true,
|
||||
Some(v) => v.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地获取Vector中指定索引的元素
|
||||
*/
|
||||
pub fn get_safe<T>(vec: &[T], index: usize) -> Option<&T> {
|
||||
vec.get(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找满足条件的第一个元素
|
||||
*/
|
||||
pub fn find<T, F>(vec: &[T], predicate: F) -> Option<&T>
|
||||
where
|
||||
F: Fn(&T) -> bool,
|
||||
{
|
||||
vec.iter().find(|&item| predicate(item))
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找满足条件的所有元素
|
||||
*/
|
||||
pub fn find_all<T, F>(vec: &[T], predicate: F) -> Vec<&T>
|
||||
where
|
||||
F: Fn(&T) -> bool,
|
||||
{
|
||||
vec.iter().filter(|&item| predicate(item)).collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在满足条件的元素
|
||||
*/
|
||||
pub fn exists<T, F>(vec: &[T], predicate: F) -> bool
|
||||
where
|
||||
F: Fn(&T) -> bool,
|
||||
{
|
||||
vec.iter().any(|item| predicate(item))
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查所有元素是否都满足条件
|
||||
*/
|
||||
pub fn all<T, F>(vec: &[T], predicate: F) -> bool
|
||||
where
|
||||
F: Fn(&T) -> bool,
|
||||
{
|
||||
vec.iter().all(|item| predicate(item))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Vector的最大值
|
||||
*/
|
||||
pub fn max<T: Ord + Clone>(vec: &[T]) -> Option<T> {
|
||||
vec.iter().max().cloned()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Vector的最小值
|
||||
*/
|
||||
pub fn min<T: Ord + Clone>(vec: &[T]) -> Option<T> {
|
||||
vec.iter().min().cloned()
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算数字Vector的和
|
||||
*/
|
||||
pub fn sum<T>(vec: &[T]) -> T
|
||||
where
|
||||
T: std::iter::Sum + Copy,
|
||||
{
|
||||
vec.iter().copied().sum()
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算数字Vector的平均值
|
||||
*/
|
||||
pub fn average(vec: &[f64]) -> Option<f64> {
|
||||
if vec.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Self::sum(vec) / vec.len() as f64)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 去重Vector中的元素
|
||||
*/
|
||||
pub fn distinct<T: Eq + Clone>(vec: &[T]) -> Vec<T> {
|
||||
let mut result = Vec::new();
|
||||
for item in vec {
|
||||
if !result.contains(item) {
|
||||
result.push(item.clone());
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 分块处理Vector
|
||||
*/
|
||||
pub fn chunk<T>(vec: &[T], size: usize) -> Vec<&[T]> {
|
||||
if size == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
vec.chunks(size).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_parse() {
|
||||
assert_eq!(NumberExtension::parse_or_zero("123"), 123.0);
|
||||
assert_eq!(NumberExtension::parse_or_zero("123.45"), 123.45);
|
||||
assert_eq!(NumberExtension::parse_or_zero("invalid"), 0.0);
|
||||
assert_eq!(NumberExtension::parse_or_default("invalid", 99.0), 99.0);
|
||||
|
||||
assert_eq!(NumberExtension::parse_int_or_zero("123"), 123);
|
||||
assert_eq!(NumberExtension::parse_int_or_zero("invalid"), 0);
|
||||
assert_eq!(NumberExtension::parse_int_or_default("invalid", 99), 99);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_bool_conversion() {
|
||||
assert_eq!(NumberExtension::bool_to_number(true), 1.0);
|
||||
assert_eq!(NumberExtension::bool_to_number(false), 0.0);
|
||||
|
||||
assert_eq!(NumberExtension::number_to_bool(1.0), true);
|
||||
assert_eq!(NumberExtension::number_to_bool(0.0), false);
|
||||
assert_eq!(NumberExtension::number_to_bool(0.5), true);
|
||||
assert_eq!(NumberExtension::number_to_bool(-1.0), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_clamp() {
|
||||
assert_eq!(NumberExtension::clamp(5.0, 0.0, 10.0), 5.0);
|
||||
assert_eq!(NumberExtension::clamp(-1.0, 0.0, 10.0), 0.0);
|
||||
assert_eq!(NumberExtension::clamp(15.0, 0.0, 10.0), 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_range() {
|
||||
assert!(NumberExtension::is_in_range(5.0, 0.0, 10.0));
|
||||
assert!(!NumberExtension::is_in_range(-1.0, 0.0, 10.0));
|
||||
assert!(!NumberExtension::is_in_range(15.0, 0.0, 10.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_round() {
|
||||
assert_eq!(NumberExtension::round_to_decimal_places(3.14159, 2), 3.14);
|
||||
assert_eq!(NumberExtension::round_to_decimal_places(3.14159, 0), 3.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_angle_conversion() {
|
||||
let degrees = NumberExtension::radians_to_degrees(std::f64::consts::PI);
|
||||
assert!((degrees - 180.0).abs() < 0.001);
|
||||
|
||||
let radians = NumberExtension::degrees_to_radians(180.0);
|
||||
assert!((radians - std::f64::consts::PI).abs() < 0.001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_lerp() {
|
||||
assert_eq!(NumberExtension::lerp(0.0, 10.0, 0.5), 5.0);
|
||||
assert_eq!(NumberExtension::lerp(0.0, 10.0, 0.0), 0.0);
|
||||
assert_eq!(NumberExtension::lerp(0.0, 10.0, 1.0), 10.0);
|
||||
|
||||
assert_eq!(NumberExtension::inverse_lerp(0.0, 10.0, 5.0), 0.5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_distance() {
|
||||
assert_eq!(NumberExtension::distance(5.0, 3.0), 2.0);
|
||||
assert_eq!(NumberExtension::distance(3.0, 5.0), 2.0);
|
||||
assert_eq!(NumberExtension::distance(-2.0, 3.0), 5.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_approximately_equal() {
|
||||
assert!(NumberExtension::approximately_equal(1.0, 1.0000001, Some(0.001)));
|
||||
assert!(!NumberExtension::approximately_equal(1.0, 1.1, Some(0.001)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_wrap() {
|
||||
assert_eq!(NumberExtension::wrap(5.0, 10.0), 5.0);
|
||||
assert_eq!(NumberExtension::wrap(15.0, 10.0), 5.0);
|
||||
assert_eq!(NumberExtension::wrap(-1.0, 10.0), 9.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_sign() {
|
||||
assert_eq!(NumberExtension::sign(5.0), 1.0);
|
||||
assert_eq!(NumberExtension::sign(-5.0), -1.0);
|
||||
assert_eq!(NumberExtension::sign(0.0), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_utils_type_id() {
|
||||
assert_eq!(TypeUtils::get_type_id::<i32>(), TypeUtils::get_type_id::<i32>());
|
||||
assert_ne!(TypeUtils::get_type_id::<i32>(), TypeUtils::get_type_id::<f64>());
|
||||
|
||||
let value = 42i32;
|
||||
assert_eq!(TypeUtils::get_object_type_id(&value), TypeUtils::get_type_id::<i32>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_utils_type_name() {
|
||||
assert!(TypeUtils::get_type_name::<i32>().contains("i32"));
|
||||
|
||||
let value = 42i32;
|
||||
assert!(TypeUtils::get_object_type_name(&value).contains("i32"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_utils_same_type() {
|
||||
assert!(TypeUtils::is_same_type::<i32, i32>());
|
||||
assert!(!TypeUtils::is_same_type::<i32, f64>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_utils_size() {
|
||||
assert_eq!(TypeUtils::get_type_size::<i32>(), 4);
|
||||
assert_eq!(TypeUtils::get_type_size::<i64>(), 8);
|
||||
|
||||
let value = 42i32;
|
||||
assert_eq!(TypeUtils::get_object_size(&value), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_utils_zero_sized() {
|
||||
assert!(TypeUtils::is_zero_sized::<()>());
|
||||
assert!(!TypeUtils::is_zero_sized::<i32>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_extension_null_checks() {
|
||||
assert!(StringExtension::is_null_or_empty(None));
|
||||
assert!(StringExtension::is_null_or_empty(Some("")));
|
||||
assert!(!StringExtension::is_null_or_empty(Some("hello")));
|
||||
|
||||
assert!(StringExtension::is_null_or_whitespace(None));
|
||||
assert!(StringExtension::is_null_or_whitespace(Some(" ")));
|
||||
assert!(!StringExtension::is_null_or_whitespace(Some("hello")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_extension_truncate() {
|
||||
assert_eq!(StringExtension::truncate("hello world", 5), "hello...");
|
||||
assert_eq!(StringExtension::truncate("hi", 10), "hi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_extension_case_conversion() {
|
||||
assert_eq!(StringExtension::to_pascal_case("hello world"), "HelloWorld");
|
||||
assert_eq!(StringExtension::to_camel_case("hello world"), "helloWorld");
|
||||
assert_eq!(StringExtension::to_snake_case("HelloWorld"), "hello_world");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_extension_padding() {
|
||||
assert_eq!(StringExtension::pad_left("123", 5, '0'), "00123");
|
||||
assert_eq!(StringExtension::pad_right("123", 5, '0'), "12300");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_extension_reverse() {
|
||||
assert_eq!(StringExtension::reverse("hello"), "olleh");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_extension_count_occurrences() {
|
||||
assert_eq!(StringExtension::count_occurrences("hello world hello", "hello"), 2);
|
||||
assert_eq!(StringExtension::count_occurrences("test", "xyz"), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_null_checks() {
|
||||
assert!(CollectionExtension::is_null_or_empty(None::<&Vec<i32>>));
|
||||
assert!(CollectionExtension::is_null_or_empty(Some(&Vec::<i32>::new())));
|
||||
assert!(!CollectionExtension::is_null_or_empty(Some(&vec![1, 2, 3])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_safe_get() {
|
||||
let vec = vec![1, 2, 3];
|
||||
assert_eq!(CollectionExtension::get_safe(&vec, 0), Some(&1));
|
||||
assert_eq!(CollectionExtension::get_safe(&vec, 5), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_find() {
|
||||
let vec = vec![1, 2, 3, 4, 5];
|
||||
assert_eq!(CollectionExtension::find(&vec, |&x| x > 3), Some(&4));
|
||||
assert_eq!(CollectionExtension::find(&vec, |&x| x > 10), None);
|
||||
|
||||
let found_all = CollectionExtension::find_all(&vec, |&x| x > 3);
|
||||
assert_eq!(found_all, vec![&4, &5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_predicates() {
|
||||
let vec = vec![1, 2, 3, 4, 5];
|
||||
assert!(CollectionExtension::exists(&vec, |&x| x > 3));
|
||||
assert!(!CollectionExtension::exists(&vec, |&x| x > 10));
|
||||
|
||||
assert!(CollectionExtension::all(&vec, |&x| x > 0));
|
||||
assert!(!CollectionExtension::all(&vec, |&x| x > 3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_math() {
|
||||
let vec = vec![1.0, 2.0, 3.0, 4.0, 5.0];
|
||||
assert_eq!(CollectionExtension::sum(&vec), 15.0);
|
||||
assert_eq!(CollectionExtension::average(&vec), Some(3.0));
|
||||
|
||||
let int_vec = vec![1, 5, 3, 2, 4];
|
||||
assert_eq!(CollectionExtension::max(&int_vec), Some(5));
|
||||
assert_eq!(CollectionExtension::min(&int_vec), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_distinct() {
|
||||
let vec = vec![1, 2, 2, 3, 1, 4];
|
||||
let distinct = CollectionExtension::distinct(&vec);
|
||||
assert_eq!(distinct, vec![1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collection_extension_chunk() {
|
||||
let vec = vec![1, 2, 3, 4, 5, 6, 7];
|
||||
let chunks = CollectionExtension::chunk(&vec, 3);
|
||||
assert_eq!(chunks.len(), 3);
|
||||
assert_eq!(chunks[0], &[1, 2, 3]);
|
||||
assert_eq!(chunks[1], &[4, 5, 6]);
|
||||
assert_eq!(chunks[2], &[7]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number_extension_to_number_from_option() {
|
||||
assert_eq!(NumberExtension::to_number_from_option(Some(42)), 42.0);
|
||||
let result = NumberExtension::to_number_from_option(Some(3.14f32));
|
||||
assert!((result - 3.14).abs() < 0.0001); // 使用近似相等检查浮点数
|
||||
assert_eq!(NumberExtension::to_number_from_option::<i32>(None), 0.0);
|
||||
}
|
||||
}
|
||||
518
packages/core-rust/src/utils/identifier_pool.rs
Normal file
518
packages/core-rust/src/utils/identifier_pool.rs
Normal file
@@ -0,0 +1,518 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
/**
|
||||
* 延迟回收项结构
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
struct PendingRecycleItem {
|
||||
index: u16,
|
||||
generation: u16,
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
/**
|
||||
* 世代式ID池统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct IdentifierPoolStats {
|
||||
/// 已分配的总索引数
|
||||
pub total_allocated: u64,
|
||||
/// 总计回收次数
|
||||
pub total_recycled: u64,
|
||||
/// 当前活跃实体数
|
||||
pub current_active: u32,
|
||||
/// 当前空闲的索引数
|
||||
pub currently_free: u32,
|
||||
/// 等待回收的ID数
|
||||
pub pending_recycle: u32,
|
||||
/// 理论最大实体数(设计限制)
|
||||
pub max_possible_entities: u32,
|
||||
/// 当前使用的最大索引
|
||||
pub max_used_index: u16,
|
||||
/// 内存使用(字节)
|
||||
pub memory_usage: usize,
|
||||
/// 内存扩展次数
|
||||
pub memory_expansions: u32,
|
||||
/// 平均世代版本
|
||||
pub average_generation: f64,
|
||||
/// 世代存储大小
|
||||
pub generation_storage_size: usize,
|
||||
}
|
||||
|
||||
/**
|
||||
* 世代式ID池管理器
|
||||
*
|
||||
* 用于管理实体ID的分配和回收,支持世代版本控制以防止悬空引用问题。
|
||||
* 世代式ID由索引和版本组成,当ID被回收时版本会递增,确保旧引用失效。
|
||||
*
|
||||
* 支持动态扩展,理论上可以支持到65535个索引(16位),每个索引65535个版本(16位)。
|
||||
* 总计可以处理超过42亿个独特的ID组合,完全满足ECS大规模实体需求。
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct IdentifierPool {
|
||||
/// 下一个可用的索引
|
||||
next_available_index: u16,
|
||||
|
||||
/// 空闲的索引列表
|
||||
free_indices: Vec<u16>,
|
||||
|
||||
/// 每个索引对应的世代版本
|
||||
/// 使用HashMap实现动态扩展
|
||||
generations: HashMap<u16, u16>,
|
||||
|
||||
/// 延迟回收队列
|
||||
/// 防止在同一帧内立即重用ID,避免时序问题
|
||||
pending_recycle: Vec<PendingRecycleItem>,
|
||||
|
||||
/// 延迟回收时间(毫秒)
|
||||
recycle_delay: u64,
|
||||
|
||||
/// 内存扩展块大小
|
||||
expansion_block_size: u16,
|
||||
|
||||
/// 统计信息
|
||||
stats: IdentifierPoolStats,
|
||||
}
|
||||
|
||||
impl IdentifierPool {
|
||||
/// 最大索引限制(16位)
|
||||
/// 这是框架设计选择:16位索引 + 16位版本 = 32位ID,确保高效位操作
|
||||
pub const MAX_INDEX: u16 = 0xFFFF; // 65535
|
||||
|
||||
/// 最大世代限制(16位)
|
||||
pub const MAX_GENERATION: u16 = 0xFFFF; // 65535
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param recycle_delay 延迟回收时间(毫秒),默认为100ms
|
||||
* @param expansion_block_size 内存扩展块大小,默认为1024
|
||||
*/
|
||||
pub fn new(recycle_delay: u64, expansion_block_size: u16) -> Self {
|
||||
let mut pool = Self {
|
||||
next_available_index: 0,
|
||||
free_indices: Vec::new(),
|
||||
generations: HashMap::new(),
|
||||
pending_recycle: Vec::new(),
|
||||
recycle_delay,
|
||||
expansion_block_size,
|
||||
stats: IdentifierPoolStats::default(),
|
||||
};
|
||||
|
||||
// 预分配第一个块的世代信息
|
||||
pool.pre_allocate_generations(0, pool.expansion_block_size);
|
||||
pool
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用默认参数创建ID池
|
||||
*/
|
||||
pub fn with_defaults() -> Self {
|
||||
Self::new(100, 1024)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个可用的ID
|
||||
*
|
||||
* 返回一个32位ID,高16位为世代版本,低16位为索引。
|
||||
*
|
||||
* @returns 新分配的实体ID
|
||||
* @throws Error 当达到索引限制时
|
||||
*/
|
||||
pub fn check_out(&mut self) -> Result<u32, String> {
|
||||
// 处理延迟回收队列
|
||||
self.process_delayed_recycle(false);
|
||||
|
||||
let index: u16;
|
||||
|
||||
if let Some(recycled_index) = self.free_indices.pop() {
|
||||
// 重用回收的索引
|
||||
index = recycled_index;
|
||||
} else {
|
||||
// 分配新索引
|
||||
if self.next_available_index >= Self::MAX_INDEX {
|
||||
return Err(format!(
|
||||
"实体索引已达到框架设计限制 ({})。\
|
||||
这意味着您已经分配了超过65535个不同的实体索引。\
|
||||
这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。",
|
||||
Self::MAX_INDEX
|
||||
));
|
||||
}
|
||||
|
||||
index = self.next_available_index;
|
||||
self.next_available_index += 1;
|
||||
|
||||
// 按需扩展世代存储
|
||||
self.ensure_generation_capacity(index);
|
||||
}
|
||||
|
||||
let generation = self.generations.get(&index).copied().unwrap_or(1);
|
||||
self.stats.total_allocated += 1;
|
||||
self.stats.current_active += 1;
|
||||
|
||||
Ok(self.pack_id(index, generation))
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收一个ID
|
||||
*
|
||||
* 验证ID的有效性后,将其加入延迟回收队列。
|
||||
* ID不会立即可重用,而是在延迟时间后才真正回收。
|
||||
*
|
||||
* @param id 要回收的实体ID
|
||||
* @returns 是否成功回收(ID是否有效且未被重复回收)
|
||||
*/
|
||||
pub fn check_in(&mut self, id: u32) -> bool {
|
||||
let index = self.unpack_index(id);
|
||||
let generation = self.unpack_generation(id);
|
||||
|
||||
// 验证ID有效性
|
||||
if !self.is_valid_id(index, generation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否已经在待回收队列中
|
||||
let already_pending = self.pending_recycle.iter()
|
||||
.any(|item| item.index == index && item.generation == generation);
|
||||
|
||||
if already_pending {
|
||||
return false; // 已经在回收队列中,拒绝重复回收
|
||||
}
|
||||
|
||||
// 加入延迟回收队列
|
||||
self.pending_recycle.push(PendingRecycleItem {
|
||||
index,
|
||||
generation,
|
||||
timestamp: self.get_current_time_ms(),
|
||||
});
|
||||
|
||||
self.stats.current_active -= 1;
|
||||
self.stats.total_recycled += 1;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证ID是否有效
|
||||
*
|
||||
* 检查ID的索引和世代版本是否匹配当前状态。
|
||||
*
|
||||
* @param id 要验证的实体ID
|
||||
* @returns ID是否有效
|
||||
*/
|
||||
pub fn is_valid(&self, id: u32) -> bool {
|
||||
let index = self.unpack_index(id);
|
||||
let generation = self.unpack_generation(id);
|
||||
self.is_valid_id(index, generation)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*
|
||||
* @returns 池的当前状态统计
|
||||
*/
|
||||
pub fn get_stats(&self) -> IdentifierPoolStats {
|
||||
// 计算平均世代版本
|
||||
let (total_generation, generation_count) = self.generations.iter()
|
||||
.filter(|(&index, _)| index < self.next_available_index)
|
||||
.fold((0u64, 0u32), |(sum, count), (_, &generation)| {
|
||||
(sum + generation as u64, count + 1)
|
||||
});
|
||||
|
||||
let average_generation = if generation_count > 0 {
|
||||
(total_generation as f64) / (generation_count as f64)
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
|
||||
IdentifierPoolStats {
|
||||
total_allocated: self.stats.total_allocated,
|
||||
total_recycled: self.stats.total_recycled,
|
||||
current_active: self.stats.current_active,
|
||||
currently_free: self.free_indices.len() as u32,
|
||||
pending_recycle: self.pending_recycle.len() as u32,
|
||||
max_possible_entities: (Self::MAX_INDEX as u32) + 1,
|
||||
max_used_index: if self.next_available_index > 0 {
|
||||
self.next_available_index - 1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
memory_usage: self.calculate_memory_usage(),
|
||||
memory_expansions: self.stats.memory_expansions,
|
||||
average_generation: (average_generation * 100.0).round() / 100.0,
|
||||
generation_storage_size: self.generations.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制执行延迟回收处理
|
||||
*
|
||||
* 在某些情况下可能需要立即处理延迟回收队列,
|
||||
* 比如内存压力大或者需要精确的统计信息时。
|
||||
*/
|
||||
pub fn force_process_delayed_recycle(&mut self) {
|
||||
self.process_delayed_recycle(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期的延迟回收项
|
||||
*
|
||||
* 将超过延迟时间的回收项真正回收到空闲列表中。
|
||||
*
|
||||
* @param force_all 是否强制处理所有延迟回收项
|
||||
*/
|
||||
fn process_delayed_recycle(&mut self, force_all: bool) {
|
||||
if self.pending_recycle.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let now = self.get_current_time_ms();
|
||||
let mut ready_to_recycle = Vec::new();
|
||||
let mut still_pending = Vec::new();
|
||||
|
||||
// 分离已到期和未到期的项
|
||||
for item in self.pending_recycle.drain(..) {
|
||||
if force_all || now.saturating_sub(item.timestamp) >= self.recycle_delay {
|
||||
ready_to_recycle.push(item);
|
||||
} else {
|
||||
still_pending.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理到期的回收项
|
||||
for item in ready_to_recycle {
|
||||
// 再次验证ID有效性(防止重复回收)
|
||||
if self.is_valid_id(item.index, item.generation) {
|
||||
// 递增世代版本
|
||||
let new_generation = if item.generation >= Self::MAX_GENERATION {
|
||||
1 // 重置为1而不是0
|
||||
} else {
|
||||
item.generation + 1
|
||||
};
|
||||
|
||||
self.generations.insert(item.index, new_generation);
|
||||
|
||||
// 添加到空闲列表
|
||||
self.free_indices.push(item.index);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新待回收队列
|
||||
self.pending_recycle = still_pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预分配世代信息
|
||||
*
|
||||
* @param start_index 起始索引
|
||||
* @param count 分配数量
|
||||
*/
|
||||
fn pre_allocate_generations(&mut self, start_index: u16, count: u16) {
|
||||
for i in 0..count {
|
||||
let index = start_index.saturating_add(i);
|
||||
if index <= Self::MAX_INDEX {
|
||||
self.generations.insert(index, 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.stats.memory_expansions += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保指定索引的世代信息存在
|
||||
*
|
||||
* @param index 索引
|
||||
*/
|
||||
fn ensure_generation_capacity(&mut self, index: u16) {
|
||||
if !self.generations.contains_key(&index) {
|
||||
// 计算需要扩展的起始位置
|
||||
let expansion_start = (index / self.expansion_block_size) * self.expansion_block_size;
|
||||
|
||||
// 预分配一个块
|
||||
self.pre_allocate_generations(expansion_start, self.expansion_block_size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算内存使用量
|
||||
*
|
||||
* @returns 内存使用字节数
|
||||
*/
|
||||
fn calculate_memory_usage(&self) -> usize {
|
||||
let generation_map_size = self.generations.len() * (std::mem::size_of::<u16>() * 2 + 24); // HashMap overhead
|
||||
let free_indices_size = self.free_indices.capacity() * std::mem::size_of::<u16>();
|
||||
let pending_recycle_size = self.pending_recycle.capacity() * std::mem::size_of::<PendingRecycleItem>();
|
||||
|
||||
generation_map_size + free_indices_size + pending_recycle_size
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包索引和世代为32位ID
|
||||
*
|
||||
* @param index 索引(16位)
|
||||
* @param generation 世代版本(16位)
|
||||
* @returns 打包后的32位ID
|
||||
*/
|
||||
fn pack_id(&self, index: u16, generation: u16) -> u32 {
|
||||
((generation as u32) << 16) | (index as u32)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ID中解包索引
|
||||
*
|
||||
* @param id 32位ID
|
||||
* @returns 索引部分(16位)
|
||||
*/
|
||||
fn unpack_index(&self, id: u32) -> u16 {
|
||||
(id & 0xFFFF) as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ID中解包世代版本
|
||||
*
|
||||
* @param id 32位ID
|
||||
* @returns 世代版本部分(16位)
|
||||
*/
|
||||
fn unpack_generation(&self, id: u32) -> u16 {
|
||||
((id >> 16) & 0xFFFF) as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部ID有效性检查
|
||||
*
|
||||
* @param index 索引
|
||||
* @param generation 世代版本
|
||||
* @returns 是否有效
|
||||
*/
|
||||
fn is_valid_id(&self, index: u16, generation: u16) -> bool {
|
||||
if index >= self.next_available_index {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(¤t_generation) = self.generations.get(&index) {
|
||||
current_generation == generation
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间(毫秒)
|
||||
* 在实际应用中应该使用更准确的时间源
|
||||
*/
|
||||
fn get_current_time_ms(&self) -> u64 {
|
||||
// 简单的时间实现,实际使用中可能需要更精确的时间源
|
||||
// 在WASM环境中可以通过js_sys::Date获取
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for IdentifierPool {
|
||||
fn default() -> Self {
|
||||
Self::with_defaults()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_identifier_pool_basic() {
|
||||
let mut pool = IdentifierPool::with_defaults();
|
||||
|
||||
// 分配ID
|
||||
let id1 = pool.check_out().unwrap();
|
||||
let id2 = pool.check_out().unwrap();
|
||||
|
||||
assert_ne!(id1, id2);
|
||||
assert!(pool.is_valid(id1));
|
||||
assert!(pool.is_valid(id2));
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.current_active, 2);
|
||||
assert_eq!(stats.total_allocated, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_identifier_pool_recycle() {
|
||||
let mut pool = IdentifierPool::with_defaults();
|
||||
|
||||
let id = pool.check_out().unwrap();
|
||||
assert!(pool.is_valid(id));
|
||||
|
||||
// 回收ID
|
||||
assert!(pool.check_in(id));
|
||||
|
||||
// ID应该仍然有效直到延迟回收处理
|
||||
assert!(pool.is_valid(id));
|
||||
|
||||
// 强制处理延迟回收
|
||||
pool.force_process_delayed_recycle();
|
||||
|
||||
// 现在ID应该无效
|
||||
assert!(!pool.is_valid(id));
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.current_active, 0);
|
||||
assert_eq!(stats.currently_free, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_identifier_pool_generation_increment() {
|
||||
let mut pool = IdentifierPool::with_defaults();
|
||||
|
||||
let id1 = pool.check_out().unwrap();
|
||||
let index = pool.unpack_index(id1);
|
||||
let generation1 = pool.unpack_generation(id1);
|
||||
|
||||
// 回收并强制处理
|
||||
pool.check_in(id1);
|
||||
pool.force_process_delayed_recycle();
|
||||
|
||||
// 重新分配同一个索引
|
||||
let id2 = pool.check_out().unwrap();
|
||||
let index2 = pool.unpack_index(id2);
|
||||
let generation2 = pool.unpack_generation(id2);
|
||||
|
||||
assert_eq!(index, index2); // 同一个索引
|
||||
assert_eq!(generation2, generation1 + 1); // 世代递增
|
||||
assert!(!pool.is_valid(id1)); // 旧ID无效
|
||||
assert!(pool.is_valid(id2)); // 新ID有效
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_identifier_pool_double_recycle() {
|
||||
let mut pool = IdentifierPool::with_defaults();
|
||||
|
||||
let id = pool.check_out().unwrap();
|
||||
|
||||
// 第一次回收应该成功
|
||||
assert!(pool.check_in(id));
|
||||
|
||||
// 第二次回收应该失败
|
||||
assert!(!pool.check_in(id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_identifier_pool_stats() {
|
||||
let mut pool = IdentifierPool::with_defaults();
|
||||
|
||||
let _id1 = pool.check_out().unwrap();
|
||||
let id2 = pool.check_out().unwrap();
|
||||
let _id3 = pool.check_out().unwrap();
|
||||
|
||||
pool.check_in(id2);
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_allocated, 3);
|
||||
assert_eq!(stats.total_recycled, 1);
|
||||
assert_eq!(stats.current_active, 2);
|
||||
assert_eq!(stats.pending_recycle, 1);
|
||||
assert_eq!(stats.max_used_index, 2);
|
||||
}
|
||||
}
|
||||
456
packages/core-rust/src/utils/matcher.rs
Normal file
456
packages/core-rust/src/utils/matcher.rs
Normal file
@@ -0,0 +1,456 @@
|
||||
use std::any::TypeId;
|
||||
|
||||
/**
|
||||
* 组件类型标识符
|
||||
* 在Rust中使用TypeId来标识组件类型
|
||||
*/
|
||||
pub type ComponentType = TypeId;
|
||||
|
||||
/**
|
||||
* 查询条件结构
|
||||
* 定义实体查询的所有条件类型
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QueryCondition {
|
||||
/// 必须包含所有这些组件
|
||||
pub all: Vec<ComponentType>,
|
||||
/// 必须包含至少一个这些组件
|
||||
pub any: Vec<ComponentType>,
|
||||
/// 不能包含任何这些组件
|
||||
pub none: Vec<ComponentType>,
|
||||
/// 按标签查询
|
||||
pub tag: Option<u32>,
|
||||
/// 按名称查询
|
||||
pub name: Option<String>,
|
||||
/// 单组件查询
|
||||
pub component: Option<ComponentType>,
|
||||
}
|
||||
|
||||
impl Default for QueryCondition {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
all: Vec::new(),
|
||||
any: Vec::new(),
|
||||
none: Vec::new(),
|
||||
tag: None,
|
||||
name: None,
|
||||
component: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体匹配条件描述符
|
||||
*
|
||||
* 用于描述实体查询条件,不执行实际查询
|
||||
* 支持链式调用构建复杂查询条件
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct Matcher {
|
||||
condition: QueryCondition,
|
||||
}
|
||||
|
||||
impl Matcher {
|
||||
/**
|
||||
* 创建新的匹配器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
condition: QueryCondition::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 静态构造方法 ==========
|
||||
|
||||
/**
|
||||
* 创建匹配器,要求所有指定的组件
|
||||
*/
|
||||
pub fn all_of(component_types: &[ComponentType]) -> Self {
|
||||
let mut matcher = Self::new();
|
||||
matcher.all_of_types(component_types);
|
||||
matcher
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建匹配器,要求至少一个指定的组件
|
||||
*/
|
||||
pub fn any_of(component_types: &[ComponentType]) -> Self {
|
||||
let mut matcher = Self::new();
|
||||
matcher.any_of_types(component_types);
|
||||
matcher
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建匹配器,排除指定的组件
|
||||
*/
|
||||
pub fn none_of(component_types: &[ComponentType]) -> Self {
|
||||
let mut matcher = Self::new();
|
||||
matcher.none_of_types(component_types);
|
||||
matcher
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建按标签查询的匹配器
|
||||
*/
|
||||
pub fn by_tag(tag: u32) -> Self {
|
||||
let mut matcher = Self::new();
|
||||
matcher.with_tag(tag);
|
||||
matcher
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建按名称查询的匹配器
|
||||
*/
|
||||
pub fn by_name(name: String) -> Self {
|
||||
let mut matcher = Self::new();
|
||||
matcher.with_name(name);
|
||||
matcher
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单组件查询的匹配器
|
||||
*/
|
||||
pub fn by_component(component_type: ComponentType) -> Self {
|
||||
let mut matcher = Self::new();
|
||||
matcher.with_component(component_type);
|
||||
matcher
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建复杂查询构建器
|
||||
*/
|
||||
pub fn complex() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建空匹配器(向后兼容)
|
||||
*/
|
||||
pub fn empty() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
|
||||
// ========== 链式构建方法 ==========
|
||||
|
||||
/**
|
||||
* 必须包含所有指定组件
|
||||
*/
|
||||
pub fn all_of_types(&mut self, component_types: &[ComponentType]) -> &mut Self {
|
||||
self.condition.all.extend_from_slice(component_types);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 必须包含所有指定组件(单个组件版本)
|
||||
*/
|
||||
pub fn all(&mut self, component_type: ComponentType) -> &mut Self {
|
||||
self.condition.all.push(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 必须包含至少一个指定组件
|
||||
*/
|
||||
pub fn any_of_types(&mut self, component_types: &[ComponentType]) -> &mut Self {
|
||||
self.condition.any.extend_from_slice(component_types);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 必须包含至少一个指定组件(单个组件版本)
|
||||
*/
|
||||
pub fn any(&mut self, component_type: ComponentType) -> &mut Self {
|
||||
self.condition.any.push(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 不能包含任何指定组件
|
||||
*/
|
||||
pub fn none_of_types(&mut self, component_types: &[ComponentType]) -> &mut Self {
|
||||
self.condition.none.extend_from_slice(component_types);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 不能包含指定组件(单个组件版本)
|
||||
*/
|
||||
pub fn none(&mut self, component_type: ComponentType) -> &mut Self {
|
||||
self.condition.none.push(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 排除指定组件(别名方法)
|
||||
*/
|
||||
pub fn exclude(&mut self, component_type: ComponentType) -> &mut Self {
|
||||
self.none(component_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 至少包含其中之一(别名方法)
|
||||
*/
|
||||
pub fn one(&mut self, component_type: ComponentType) -> &mut Self {
|
||||
self.any(component_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按标签查询
|
||||
*/
|
||||
pub fn with_tag(&mut self, tag: u32) -> &mut Self {
|
||||
self.condition.tag = Some(tag);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称查询
|
||||
*/
|
||||
pub fn with_name(&mut self, name: String) -> &mut Self {
|
||||
self.condition.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 单组件查询
|
||||
*/
|
||||
pub fn with_component(&mut self, component_type: ComponentType) -> &mut Self {
|
||||
self.condition.component = Some(component_type);
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除标签条件
|
||||
*/
|
||||
pub fn without_tag(&mut self) -> &mut Self {
|
||||
self.condition.tag = None;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除名称条件
|
||||
*/
|
||||
pub fn without_name(&mut self) -> &mut Self {
|
||||
self.condition.name = None;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除单组件条件
|
||||
*/
|
||||
pub fn without_component(&mut self) -> &mut Self {
|
||||
self.condition.component = None;
|
||||
self
|
||||
}
|
||||
|
||||
// ========== 查询和工具方法 ==========
|
||||
|
||||
/**
|
||||
* 获取查询条件(只读)
|
||||
*/
|
||||
pub fn get_condition(&self) -> &QueryCondition {
|
||||
&self.condition
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询条件的克隆
|
||||
*/
|
||||
pub fn clone_condition(&self) -> QueryCondition {
|
||||
self.condition.clone()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为空条件
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.condition.all.is_empty() &&
|
||||
self.condition.any.is_empty() &&
|
||||
self.condition.none.is_empty() &&
|
||||
self.condition.tag.is_none() &&
|
||||
self.condition.name.is_none() &&
|
||||
self.condition.component.is_none()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置所有条件
|
||||
*/
|
||||
pub fn reset(&mut self) -> &mut Self {
|
||||
self.condition.all.clear();
|
||||
self.condition.any.clear();
|
||||
self.condition.none.clear();
|
||||
self.condition.tag = None;
|
||||
self.condition.name = None;
|
||||
self.condition.component = None;
|
||||
self
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆匹配器
|
||||
*/
|
||||
pub fn clone(&self) -> Self {
|
||||
Self {
|
||||
condition: self.condition.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有条件的组件类型数量(用于性能分析)
|
||||
*/
|
||||
pub fn component_type_count(&self) -> usize {
|
||||
self.condition.all.len() +
|
||||
self.condition.any.len() +
|
||||
self.condition.none.len() +
|
||||
if self.condition.component.is_some() { 1 } else { 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查查询条件的复杂度
|
||||
*/
|
||||
pub fn complexity_level(&self) -> u32 {
|
||||
let mut level = 0;
|
||||
|
||||
if !self.condition.all.is_empty() { level += 1; }
|
||||
if !self.condition.any.is_empty() { level += 2; }
|
||||
if !self.condition.none.is_empty() { level += 1; }
|
||||
if self.condition.tag.is_some() { level += 1; }
|
||||
if self.condition.name.is_some() { level += 1; }
|
||||
if self.condition.component.is_some() { level += 1; }
|
||||
|
||||
level
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Matcher {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于测试和调试的方法
|
||||
*/
|
||||
impl Matcher {
|
||||
/**
|
||||
* 格式化为调试字符串
|
||||
*/
|
||||
pub fn debug_string(&self) -> String {
|
||||
let mut parts = Vec::new();
|
||||
|
||||
if !self.condition.all.is_empty() {
|
||||
parts.push(format!("all({} types)", self.condition.all.len()));
|
||||
}
|
||||
|
||||
if !self.condition.any.is_empty() {
|
||||
parts.push(format!("any({} types)", self.condition.any.len()));
|
||||
}
|
||||
|
||||
if !self.condition.none.is_empty() {
|
||||
parts.push(format!("none({} types)", self.condition.none.len()));
|
||||
}
|
||||
|
||||
if let Some(tag) = self.condition.tag {
|
||||
parts.push(format!("tag({})", tag));
|
||||
}
|
||||
|
||||
if let Some(ref name) = self.condition.name {
|
||||
parts.push(format!("name({})", name));
|
||||
}
|
||||
|
||||
if self.condition.component.is_some() {
|
||||
parts.push("component(1 type)".to_string());
|
||||
}
|
||||
|
||||
if parts.is_empty() {
|
||||
"Matcher[empty]".to_string()
|
||||
} else {
|
||||
format!("Matcher[{}]", parts.join(" & "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实现Display trait以支持打印
|
||||
impl std::fmt::Display for Matcher {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.debug_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::any::TypeId;
|
||||
|
||||
// 测试用的示例组件
|
||||
struct TestComponent1;
|
||||
struct TestComponent2;
|
||||
struct TestComponent3;
|
||||
|
||||
#[test]
|
||||
fn test_matcher_all() {
|
||||
let mut matcher = Matcher::new();
|
||||
matcher.all(TypeId::of::<TestComponent1>())
|
||||
.all(TypeId::of::<TestComponent2>());
|
||||
|
||||
assert_eq!(matcher.get_condition().all.len(), 2);
|
||||
assert!(!matcher.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher_any() {
|
||||
let mut matcher = Matcher::new();
|
||||
matcher.any(TypeId::of::<TestComponent1>())
|
||||
.any(TypeId::of::<TestComponent2>());
|
||||
|
||||
assert_eq!(matcher.get_condition().any.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher_none() {
|
||||
let mut matcher = Matcher::new();
|
||||
matcher.none(TypeId::of::<TestComponent1>());
|
||||
|
||||
assert_eq!(matcher.get_condition().none.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher_complex() {
|
||||
let mut matcher = Matcher::complex();
|
||||
matcher.all(TypeId::of::<TestComponent1>())
|
||||
.any(TypeId::of::<TestComponent2>())
|
||||
.none(TypeId::of::<TestComponent3>())
|
||||
.with_tag(42)
|
||||
.with_name("test_entity".to_string());
|
||||
|
||||
assert_eq!(matcher.complexity_level(), 6);
|
||||
assert!(!matcher.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher_static_constructors() {
|
||||
let types = vec![TypeId::of::<TestComponent1>(), TypeId::of::<TestComponent2>()];
|
||||
let matcher = Matcher::all_of(&types);
|
||||
assert_eq!(matcher.get_condition().all.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher_reset() {
|
||||
let mut matcher = Matcher::new();
|
||||
matcher.all(TypeId::of::<TestComponent1>())
|
||||
.with_tag(42);
|
||||
|
||||
assert!(!matcher.is_empty());
|
||||
|
||||
matcher.reset();
|
||||
assert!(matcher.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher_clone() {
|
||||
let mut matcher = Matcher::new();
|
||||
matcher.all(TypeId::of::<TestComponent1>())
|
||||
.with_tag(42);
|
||||
|
||||
let cloned = matcher.clone();
|
||||
assert_eq!(cloned.get_condition().all.len(), 1);
|
||||
assert_eq!(cloned.get_condition().tag, Some(42));
|
||||
}
|
||||
}
|
||||
46
packages/core-rust/src/utils/mod.rs
Normal file
46
packages/core-rust/src/utils/mod.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
pub mod sparse_set;
|
||||
pub mod time;
|
||||
pub mod matcher;
|
||||
pub mod identifier_pool;
|
||||
pub mod component_pool;
|
||||
pub mod dirty_tracking;
|
||||
pub mod performance_monitor;
|
||||
pub mod timer;
|
||||
pub mod pool;
|
||||
pub mod debug;
|
||||
pub mod updatable;
|
||||
pub mod extensions;
|
||||
|
||||
pub use sparse_set::SparseSet;
|
||||
pub use time::Time;
|
||||
pub use matcher::{Matcher, QueryCondition, ComponentType};
|
||||
pub use identifier_pool::{IdentifierPool, IdentifierPoolStats};
|
||||
pub use component_pool::{ComponentPool, ComponentPoolManager, ComponentPoolStats, ComponentPoolManagerStats, PoolStatsSummary};
|
||||
pub use dirty_tracking::{DirtyTrackingSystem, DirtyFlag, DirtyData, DirtyTrackingStats, DirtyListener, DirtyListenerConfig};
|
||||
pub use performance_monitor::{PerformanceMonitor, PerformanceData, PerformanceStats, PerformanceWarning, PerformanceWarningType, WarningSeverity, PerformanceThresholds, ThresholdPair};
|
||||
pub use timer::{Timer, TimerManager, ITimer, TimerContext, TimerCallback, EmptyContext};
|
||||
pub use pool::{Pool, PoolManager, Poolable, PoolStats};
|
||||
pub use debug::{DebugManager, EntityDataCollector, SystemDataCollector, ComponentDataCollector, PerformanceDataCollector, DebugEntityData, DebugComponentInfo, DebugSystemInfo, DebugArchetypeInfo, DebugPerformanceInfo, DebugWarning, WarningLevel, DebugStats, DebugData};
|
||||
pub use updatable::{IUpdatable, IUpdatableComparer, SceneComponent, SceneComponentTrait, UpdatableManager, SceneComponentManager, is_updatable};
|
||||
pub use extensions::{NumberExtension, TypeUtils, StringExtension, CollectionExtension};
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn error(msg: String);
|
||||
}
|
||||
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
pub fn set_panic_hook() {
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "console_error_panic_hook"))]
|
||||
pub fn set_panic_hook() {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn log_error(msg: &str) {
|
||||
error(msg.to_string());
|
||||
}
|
||||
824
packages/core-rust/src/utils/performance_monitor.rs
Normal file
824
packages/core-rust/src/utils/performance_monitor.rs
Normal file
@@ -0,0 +1,824 @@
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/**
|
||||
* 性能数据
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerformanceData {
|
||||
/// 系统名称
|
||||
pub name: String,
|
||||
/// 执行时间(毫秒)
|
||||
pub execution_time: f64,
|
||||
/// 处理的实体数量
|
||||
pub entity_count: usize,
|
||||
/// 平均每个实体的处理时间
|
||||
pub average_time_per_entity: f64,
|
||||
/// 最后更新时间戳
|
||||
pub last_update_time: u64,
|
||||
/// 内存使用量(字节)
|
||||
pub memory_usage: Option<usize>,
|
||||
/// CPU使用率(百分比)
|
||||
pub cpu_usage: Option<f64>,
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerformanceStats {
|
||||
/// 总执行时间
|
||||
pub total_time: f64,
|
||||
/// 平均执行时间
|
||||
pub average_time: f64,
|
||||
/// 最小执行时间
|
||||
pub min_time: f64,
|
||||
/// 最大执行时间
|
||||
pub max_time: f64,
|
||||
/// 执行次数
|
||||
pub execution_count: u64,
|
||||
/// 最近的执行时间列表
|
||||
pub recent_times: VecDeque<f64>,
|
||||
/// 标准差
|
||||
pub standard_deviation: f64,
|
||||
/// 95百分位数
|
||||
pub percentile_95: f64,
|
||||
/// 99百分位数
|
||||
pub percentile_99: f64,
|
||||
}
|
||||
|
||||
impl Default for PerformanceStats {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
total_time: 0.0,
|
||||
average_time: 0.0,
|
||||
min_time: f64::MAX,
|
||||
max_time: 0.0,
|
||||
execution_count: 0,
|
||||
recent_times: VecDeque::new(),
|
||||
standard_deviation: 0.0,
|
||||
percentile_95: 0.0,
|
||||
percentile_99: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能警告类型
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PerformanceWarningType {
|
||||
HighExecutionTime,
|
||||
HighMemoryUsage,
|
||||
HighCpuUsage,
|
||||
FrequentGc,
|
||||
LowFps,
|
||||
HighEntityCount,
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能警告
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerformanceWarning {
|
||||
pub warning_type: PerformanceWarningType,
|
||||
pub system_name: String,
|
||||
pub message: String,
|
||||
pub severity: WarningSeverity,
|
||||
pub timestamp: u64,
|
||||
pub value: f64,
|
||||
pub threshold: f64,
|
||||
pub suggestion: Option<String>,
|
||||
}
|
||||
|
||||
/**
|
||||
* 警告严重程度
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WarningSeverity {
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
Critical,
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能阈值配置
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerformanceThresholds {
|
||||
/// 执行时间阈值(毫秒)
|
||||
pub execution_time: ThresholdPair,
|
||||
/// 内存使用阈值(MB)
|
||||
pub memory_usage: ThresholdPair,
|
||||
/// CPU使用率阈值(百分比)
|
||||
pub cpu_usage: ThresholdPair,
|
||||
/// FPS阈值
|
||||
pub fps: ThresholdPair,
|
||||
/// 实体数量阈值
|
||||
pub entity_count: ThresholdPair,
|
||||
}
|
||||
|
||||
/**
|
||||
* 阈值对(警告和临界值)
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ThresholdPair {
|
||||
pub warning: f64,
|
||||
pub critical: f64,
|
||||
}
|
||||
|
||||
impl Default for PerformanceThresholds {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
execution_time: ThresholdPair { warning: 16.67, critical: 33.33 }, // 60fps和30fps对应的帧时间
|
||||
memory_usage: ThresholdPair { warning: 100.0, critical: 200.0 }, // MB
|
||||
cpu_usage: ThresholdPair { warning: 70.0, critical: 90.0 }, // 百分比
|
||||
fps: ThresholdPair { warning: 45.0, critical: 30.0 },
|
||||
entity_count: ThresholdPair { warning: 1000.0, critical: 5000.0 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能监控器
|
||||
* 用于监控ECS系统的性能表现,提供详细的分析和优化建议
|
||||
*/
|
||||
pub struct PerformanceMonitor {
|
||||
system_data: FxHashMap<String, PerformanceData>,
|
||||
system_stats: FxHashMap<String, PerformanceStats>,
|
||||
warnings: Vec<PerformanceWarning>,
|
||||
is_enabled: bool,
|
||||
max_recent_samples: usize,
|
||||
max_warnings: usize,
|
||||
|
||||
// 性能阈值配置
|
||||
thresholds: PerformanceThresholds,
|
||||
|
||||
// FPS监控
|
||||
fps_history: VecDeque<f64>,
|
||||
last_frame_time: Option<Instant>,
|
||||
frame_count: u64,
|
||||
fps_update_interval: u64, // 毫秒
|
||||
last_fps_update: u64,
|
||||
current_fps: f64,
|
||||
|
||||
// 内存监控
|
||||
memory_check_interval: u64, // 毫秒
|
||||
last_memory_check: u64,
|
||||
memory_history: Vec<usize>,
|
||||
|
||||
// GC监控
|
||||
gc_count: u64,
|
||||
last_gc_check: u64,
|
||||
gc_check_interval: u64,
|
||||
}
|
||||
|
||||
impl Default for PerformanceMonitor {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PerformanceMonitor {
|
||||
/**
|
||||
* 创建新的性能监控器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
system_data: FxHashMap::default(),
|
||||
system_stats: FxHashMap::default(),
|
||||
warnings: Vec::new(),
|
||||
is_enabled: false,
|
||||
max_recent_samples: 60, // 保留最近60帧的数据
|
||||
max_warnings: 100, // 最大警告数量
|
||||
thresholds: PerformanceThresholds::default(),
|
||||
fps_history: VecDeque::new(),
|
||||
last_frame_time: None,
|
||||
frame_count: 0,
|
||||
fps_update_interval: 1000, // 1秒更新一次FPS
|
||||
last_fps_update: 0,
|
||||
current_fps: 60.0,
|
||||
memory_check_interval: 5000, // 5秒检查一次内存
|
||||
last_memory_check: 0,
|
||||
memory_history: Vec::new(),
|
||||
gc_count: 0,
|
||||
last_gc_check: 0,
|
||||
gc_check_interval: 1000,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用性能监控
|
||||
*/
|
||||
pub fn enable(&mut self) {
|
||||
self.is_enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用性能监控
|
||||
*/
|
||||
pub fn disable(&mut self) {
|
||||
self.is_enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否启用了性能监控
|
||||
*/
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.is_enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始监控系统性能
|
||||
* 返回开始时间戳(用于endMonitoring)
|
||||
*/
|
||||
pub fn start_monitoring(&self, _system_name: &str) -> Option<Instant> {
|
||||
if !self.is_enabled {
|
||||
return None;
|
||||
}
|
||||
Some(Instant::now())
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束监控并记录性能数据
|
||||
*/
|
||||
pub fn end_monitoring(
|
||||
&mut self,
|
||||
system_name: &str,
|
||||
start_time: Option<Instant>,
|
||||
entity_count: usize
|
||||
) {
|
||||
if !self.is_enabled || start_time.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let end_time = Instant::now();
|
||||
let execution_time = end_time.duration_since(start_time.unwrap()).as_secs_f64() * 1000.0;
|
||||
let average_time_per_entity = if entity_count > 0 {
|
||||
execution_time / entity_count as f64
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// 更新当前性能数据
|
||||
let data = PerformanceData {
|
||||
name: system_name.to_string(),
|
||||
execution_time,
|
||||
entity_count,
|
||||
average_time_per_entity,
|
||||
last_update_time: current_timestamp(),
|
||||
memory_usage: None,
|
||||
cpu_usage: None,
|
||||
};
|
||||
|
||||
self.system_data.insert(system_name.to_string(), data);
|
||||
|
||||
// 更新统计信息
|
||||
self.update_stats(system_name, execution_time);
|
||||
|
||||
// 检查警告
|
||||
self.check_warnings(system_name, execution_time, entity_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新系统统计信息
|
||||
*/
|
||||
fn update_stats(&mut self, system_name: &str, execution_time: f64) {
|
||||
{
|
||||
let stats = self.system_stats.entry(system_name.to_string()).or_insert_with(PerformanceStats::default);
|
||||
|
||||
// 更新基本统计
|
||||
stats.total_time += execution_time;
|
||||
stats.execution_count += 1;
|
||||
stats.average_time = stats.total_time / stats.execution_count as f64;
|
||||
stats.min_time = stats.min_time.min(execution_time);
|
||||
stats.max_time = stats.max_time.max(execution_time);
|
||||
|
||||
// 更新最近时间列表
|
||||
stats.recent_times.push_back(execution_time);
|
||||
if stats.recent_times.len() > self.max_recent_samples {
|
||||
stats.recent_times.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
// 计算高级统计信息
|
||||
if let Some(stats) = self.system_stats.get_mut(system_name) {
|
||||
Self::calculate_advanced_stats_static(stats);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算高级统计信息
|
||||
*/
|
||||
fn calculate_advanced_stats_static(stats: &mut PerformanceStats) {
|
||||
if stats.recent_times.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算标准差
|
||||
let mean: f64 = stats.recent_times.iter().sum::<f64>() / stats.recent_times.len() as f64;
|
||||
let variance: f64 = stats.recent_times.iter()
|
||||
.map(|&time| (time - mean).powi(2))
|
||||
.sum::<f64>() / stats.recent_times.len() as f64;
|
||||
stats.standard_deviation = variance.sqrt();
|
||||
|
||||
// 计算百分位数
|
||||
let mut sorted_times: Vec<f64> = stats.recent_times.iter().cloned().collect();
|
||||
sorted_times.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
let len = sorted_times.len();
|
||||
|
||||
if len > 0 {
|
||||
let index_95 = ((len as f64 * 0.95) as usize).min(len - 1);
|
||||
let index_99 = ((len as f64 * 0.99) as usize).min(len - 1);
|
||||
|
||||
stats.percentile_95 = sorted_times[index_95];
|
||||
stats.percentile_99 = sorted_times[index_99];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查性能警告
|
||||
*/
|
||||
fn check_warnings(&mut self, system_name: &str, execution_time: f64, entity_count: usize) {
|
||||
// 检查执行时间
|
||||
if execution_time > self.thresholds.execution_time.critical {
|
||||
self.add_warning(PerformanceWarning {
|
||||
warning_type: PerformanceWarningType::HighExecutionTime,
|
||||
system_name: system_name.to_string(),
|
||||
message: format!("System {} execution time is critically high: {:.2}ms", system_name, execution_time),
|
||||
severity: WarningSeverity::Critical,
|
||||
timestamp: current_timestamp(),
|
||||
value: execution_time,
|
||||
threshold: self.thresholds.execution_time.critical,
|
||||
suggestion: Some("Consider optimizing system logic or reducing entity count".to_string()),
|
||||
});
|
||||
} else if execution_time > self.thresholds.execution_time.warning {
|
||||
self.add_warning(PerformanceWarning {
|
||||
warning_type: PerformanceWarningType::HighExecutionTime,
|
||||
system_name: system_name.to_string(),
|
||||
message: format!("System {} execution time is high: {:.2}ms", system_name, execution_time),
|
||||
severity: WarningSeverity::Medium,
|
||||
timestamp: current_timestamp(),
|
||||
value: execution_time,
|
||||
threshold: self.thresholds.execution_time.warning,
|
||||
suggestion: Some("Monitor system performance and consider optimization".to_string()),
|
||||
});
|
||||
}
|
||||
|
||||
// 检查实体数量
|
||||
let entity_count_f64 = entity_count as f64;
|
||||
if entity_count_f64 > self.thresholds.entity_count.critical {
|
||||
self.add_warning(PerformanceWarning {
|
||||
warning_type: PerformanceWarningType::HighEntityCount,
|
||||
system_name: system_name.to_string(),
|
||||
message: format!("System {} processing critically high entity count: {}", system_name, entity_count),
|
||||
severity: WarningSeverity::Critical,
|
||||
timestamp: current_timestamp(),
|
||||
value: entity_count_f64,
|
||||
threshold: self.thresholds.entity_count.critical,
|
||||
suggestion: Some("Consider entity pooling or batch processing".to_string()),
|
||||
});
|
||||
} else if entity_count_f64 > self.thresholds.entity_count.warning {
|
||||
self.add_warning(PerformanceWarning {
|
||||
warning_type: PerformanceWarningType::HighEntityCount,
|
||||
system_name: system_name.to_string(),
|
||||
message: format!("System {} processing high entity count: {}", system_name, entity_count),
|
||||
severity: WarningSeverity::Medium,
|
||||
timestamp: current_timestamp(),
|
||||
value: entity_count_f64,
|
||||
threshold: self.thresholds.entity_count.warning,
|
||||
suggestion: Some("Monitor entity count and consider optimization if it continues growing".to_string()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加警告
|
||||
*/
|
||||
fn add_warning(&mut self, warning: PerformanceWarning) {
|
||||
self.warnings.push(warning);
|
||||
|
||||
// 限制警告数量
|
||||
if self.warnings.len() > self.max_warnings {
|
||||
self.warnings.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统的当前性能数据
|
||||
*/
|
||||
pub fn get_system_data(&self, system_name: &str) -> Option<&PerformanceData> {
|
||||
self.system_data.get(system_name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统的统计信息
|
||||
*/
|
||||
pub fn get_system_stats(&self, system_name: &str) -> Option<&PerformanceStats> {
|
||||
self.system_stats.get(system_name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有系统的性能数据
|
||||
*/
|
||||
pub fn get_all_system_data(&self) -> &FxHashMap<String, PerformanceData> {
|
||||
&self.system_data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有系统的统计信息
|
||||
*/
|
||||
pub fn get_all_system_stats(&self) -> &FxHashMap<String, PerformanceStats> {
|
||||
&self.system_stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性能报告
|
||||
*/
|
||||
pub fn get_performance_report(&self) -> String {
|
||||
if !self.is_enabled {
|
||||
return "Performance monitoring is disabled.".to_string();
|
||||
}
|
||||
|
||||
let mut lines = Vec::new();
|
||||
lines.push("=== ECS Performance Report ===".to_string());
|
||||
lines.push("".to_string());
|
||||
|
||||
// 按平均执行时间排序
|
||||
let mut sorted_systems: Vec<_> = self.system_stats.iter().collect();
|
||||
sorted_systems.sort_by(|a, b| b.1.average_time.partial_cmp(&a.1.average_time).unwrap());
|
||||
|
||||
for (system_name, stats) in sorted_systems {
|
||||
if let Some(data) = self.system_data.get(system_name) {
|
||||
lines.push(format!("System: {}", system_name));
|
||||
lines.push(format!(" Current: {:.2}ms ({} entities)", data.execution_time, data.entity_count));
|
||||
lines.push(format!(" Average: {:.2}ms", stats.average_time));
|
||||
lines.push(format!(" Min/Max: {:.2}ms / {:.2}ms", stats.min_time, stats.max_time));
|
||||
lines.push(format!(" Total: {:.2}ms ({} calls)", stats.total_time, stats.execution_count));
|
||||
|
||||
if data.average_time_per_entity > 0.0 {
|
||||
lines.push(format!(" Per Entity: {:.4}ms", data.average_time_per_entity));
|
||||
}
|
||||
|
||||
lines.push("".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// 总体统计
|
||||
let total_current_time: f64 = self.system_data.values()
|
||||
.map(|data| data.execution_time)
|
||||
.sum();
|
||||
|
||||
lines.push(format!("Total Frame Time: {:.2}ms", total_current_time));
|
||||
lines.push(format!("Systems Count: {}", self.system_data.len()));
|
||||
lines.push(format!("Current FPS: {:.1}", self.current_fps));
|
||||
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性能警告
|
||||
*/
|
||||
pub fn get_performance_warnings(&self, threshold_ms: Option<f64>) -> Vec<String> {
|
||||
let threshold = threshold_ms.unwrap_or(16.67); // 默认60fps阈值
|
||||
let mut warnings = Vec::new();
|
||||
|
||||
for (system_name, data) in &self.system_data {
|
||||
if data.execution_time > threshold {
|
||||
warnings.push(format!("{}: {:.2}ms (>{:.0}ms)",
|
||||
system_name, data.execution_time, threshold));
|
||||
}
|
||||
}
|
||||
|
||||
warnings
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有警告
|
||||
*/
|
||||
pub fn get_warnings(&self) -> &[PerformanceWarning] {
|
||||
&self.warnings
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有警告
|
||||
*/
|
||||
pub fn clear_warnings(&mut self) {
|
||||
self.warnings.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置所有性能数据
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.system_data.clear();
|
||||
self.system_stats.clear();
|
||||
self.warnings.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置指定系统的性能数据
|
||||
*/
|
||||
pub fn reset_system(&mut self, system_name: &str) {
|
||||
self.system_data.remove(system_name);
|
||||
self.system_stats.remove(system_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最大保留样本数
|
||||
*/
|
||||
pub fn set_max_recent_samples(&mut self, max_samples: usize) {
|
||||
self.max_recent_samples = max_samples;
|
||||
|
||||
// 裁剪现有数据
|
||||
for stats in self.system_stats.values_mut() {
|
||||
while stats.recent_times.len() > max_samples {
|
||||
stats.recent_times.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置性能阈值
|
||||
*/
|
||||
pub fn set_thresholds(&mut self, thresholds: PerformanceThresholds) {
|
||||
self.thresholds = thresholds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性能阈值
|
||||
*/
|
||||
pub fn get_thresholds(&self) -> &PerformanceThresholds {
|
||||
&self.thresholds
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新FPS
|
||||
*/
|
||||
pub fn update_fps(&mut self) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(last_time) = self.last_frame_time {
|
||||
let frame_time = now.duration_since(last_time).as_secs_f64() * 1000.0;
|
||||
self.fps_history.push_back(1000.0 / frame_time);
|
||||
|
||||
// 保持历史记录在合理范围内
|
||||
if self.fps_history.len() > self.max_recent_samples {
|
||||
self.fps_history.pop_front();
|
||||
}
|
||||
|
||||
// 每秒更新一次平均FPS
|
||||
let current_time = current_timestamp();
|
||||
if current_time - self.last_fps_update > self.fps_update_interval {
|
||||
if !self.fps_history.is_empty() {
|
||||
self.current_fps = self.fps_history.iter().sum::<f64>() / self.fps_history.len() as f64;
|
||||
}
|
||||
self.last_fps_update = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
self.last_frame_time = Some(now);
|
||||
self.frame_count += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前FPS
|
||||
*/
|
||||
pub fn get_current_fps(&self) -> f64 {
|
||||
self.current_fps
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平均FPS
|
||||
*/
|
||||
pub fn get_average_fps(&self) -> f64 {
|
||||
if self.fps_history.is_empty() {
|
||||
60.0
|
||||
} else {
|
||||
self.fps_history.iter().sum::<f64>() / self.fps_history.len() as f64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
|
||||
/**
|
||||
* 获取当前时间戳(毫秒)
|
||||
*/
|
||||
fn current_timestamp() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_performance_monitor_creation() {
|
||||
let monitor = PerformanceMonitor::new();
|
||||
assert!(!monitor.enabled());
|
||||
assert_eq!(monitor.get_current_fps(), 60.0);
|
||||
assert!(monitor.get_all_system_data().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_performance_monitor_enable_disable() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
|
||||
assert!(!monitor.enabled());
|
||||
|
||||
monitor.enable();
|
||||
assert!(monitor.enabled());
|
||||
|
||||
monitor.disable();
|
||||
assert!(!monitor.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_performance_monitoring_disabled() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
|
||||
assert!(start_time.is_none());
|
||||
|
||||
monitor.end_monitoring("TestSystem", start_time, 10);
|
||||
assert!(monitor.get_system_data("TestSystem").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_performance_monitoring_enabled() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
assert!(start_time.is_some());
|
||||
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
|
||||
monitor.end_monitoring("TestSystem", start_time, 5);
|
||||
|
||||
let data = monitor.get_system_data("TestSystem");
|
||||
assert!(data.is_some());
|
||||
|
||||
let data = data.unwrap();
|
||||
assert_eq!(data.name, "TestSystem");
|
||||
assert_eq!(data.entity_count, 5);
|
||||
assert!(data.execution_time >= 10.0);
|
||||
assert!(data.average_time_per_entity > 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_performance_stats_update() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
// 模拟多次执行
|
||||
for i in 0..3 {
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
thread::sleep(Duration::from_millis(5 + i)); // 不同的执行时间
|
||||
monitor.end_monitoring("TestSystem", start_time, 10);
|
||||
}
|
||||
|
||||
let stats = monitor.get_system_stats("TestSystem");
|
||||
assert!(stats.is_some());
|
||||
|
||||
let stats = stats.unwrap();
|
||||
assert_eq!(stats.execution_count, 3);
|
||||
assert!(stats.total_time > 0.0);
|
||||
assert!(stats.average_time > 0.0);
|
||||
assert!(stats.min_time > 0.0);
|
||||
assert!(stats.max_time > 0.0);
|
||||
assert_eq!(stats.recent_times.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_performance_warnings() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
// 设置较低的阈值以触发警告
|
||||
let mut thresholds = PerformanceThresholds::default();
|
||||
thresholds.execution_time.warning = 1.0;
|
||||
thresholds.execution_time.critical = 2.0;
|
||||
monitor.set_thresholds(thresholds);
|
||||
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
thread::sleep(Duration::from_millis(5)); // 足够触发警告
|
||||
monitor.end_monitoring("TestSystem", start_time, 10);
|
||||
|
||||
let warnings = monitor.get_warnings();
|
||||
assert!(!warnings.is_empty());
|
||||
assert_eq!(warnings[0].system_name, "TestSystem");
|
||||
assert_eq!(warnings[0].warning_type, PerformanceWarningType::HighExecutionTime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_performance_report() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
monitor.end_monitoring("TestSystem", start_time, 10);
|
||||
|
||||
let report = monitor.get_performance_report();
|
||||
assert!(report.contains("ECS Performance Report"));
|
||||
assert!(report.contains("TestSystem"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fps_monitoring() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
|
||||
// 模拟几帧
|
||||
for _ in 0..3 {
|
||||
monitor.update_fps();
|
||||
thread::sleep(Duration::from_millis(16)); // ~60fps
|
||||
}
|
||||
|
||||
let fps = monitor.get_current_fps();
|
||||
assert!(fps > 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reset_functionality() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
monitor.end_monitoring("TestSystem", start_time, 10);
|
||||
|
||||
assert!(monitor.get_system_data("TestSystem").is_some());
|
||||
|
||||
monitor.reset();
|
||||
assert!(monitor.get_system_data("TestSystem").is_none());
|
||||
assert!(monitor.get_warnings().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_recent_samples() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
monitor.set_max_recent_samples(2);
|
||||
|
||||
// 执行3次,但只应该保留最近2次的数据
|
||||
for _ in 0..3 {
|
||||
let start_time = monitor.start_monitoring("TestSystem");
|
||||
monitor.end_monitoring("TestSystem", start_time, 10);
|
||||
}
|
||||
|
||||
let stats = monitor.get_system_stats("TestSystem").unwrap();
|
||||
assert_eq!(stats.recent_times.len(), 2);
|
||||
assert_eq!(stats.execution_count, 3); // 总次数应该还是3
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_system_reset() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
let start_time1 = monitor.start_monitoring("TestSystem1");
|
||||
monitor.end_monitoring("TestSystem1", start_time1, 10);
|
||||
|
||||
let start_time2 = monitor.start_monitoring("TestSystem2");
|
||||
monitor.end_monitoring("TestSystem2", start_time2, 20);
|
||||
|
||||
assert!(monitor.get_system_data("TestSystem1").is_some());
|
||||
assert!(monitor.get_system_data("TestSystem2").is_some());
|
||||
|
||||
monitor.reset_system("TestSystem1");
|
||||
|
||||
assert!(monitor.get_system_data("TestSystem1").is_none());
|
||||
assert!(monitor.get_system_data("TestSystem2").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_percentile_calculations() {
|
||||
let mut monitor = PerformanceMonitor::new();
|
||||
monitor.enable();
|
||||
|
||||
// 添加一些已知的执行时间
|
||||
let times = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
|
||||
|
||||
for &time in × {
|
||||
// 直接设置执行时间进行测试
|
||||
monitor.update_stats("TestSystem", time);
|
||||
}
|
||||
|
||||
let stats = monitor.get_system_stats("TestSystem").unwrap();
|
||||
|
||||
// 95%应该是9.5左右,99%应该是9.9左右
|
||||
assert!(stats.percentile_95 >= 9.0);
|
||||
assert!(stats.percentile_99 >= 9.0);
|
||||
|
||||
// 标准差应该大于0
|
||||
assert!(stats.standard_deviation > 0.0);
|
||||
}
|
||||
}
|
||||
871
packages/core-rust/src/utils/pool.rs
Normal file
871
packages/core-rust/src/utils/pool.rs
Normal file
@@ -0,0 +1,871 @@
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::any::Any;
|
||||
|
||||
/**
|
||||
* 可池化对象trait
|
||||
*/
|
||||
pub trait Poolable: Send + Sync {
|
||||
/**
|
||||
* 重置对象状态,准备重用
|
||||
*/
|
||||
fn reset(&mut self);
|
||||
|
||||
/**
|
||||
* 获取对象的估算大小(字节)
|
||||
*/
|
||||
fn estimated_size(&self) -> usize {
|
||||
std::mem::size_of_val(self)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象池统计信息
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PoolStats {
|
||||
/// 池中对象数量
|
||||
pub size: usize,
|
||||
/// 池的最大大小
|
||||
pub max_size: usize,
|
||||
/// 总共创建的对象数量
|
||||
pub total_created: u64,
|
||||
/// 总共获取的次数
|
||||
pub total_obtained: u64,
|
||||
/// 总共释放的次数
|
||||
pub total_released: u64,
|
||||
/// 命中率(从池中获取的比例)
|
||||
pub hit_rate: f64,
|
||||
/// 内存使用估算(字节)
|
||||
pub estimated_memory_usage: usize,
|
||||
}
|
||||
|
||||
impl Default for PoolStats {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: 0,
|
||||
max_size: 0,
|
||||
total_created: 0,
|
||||
total_obtained: 0,
|
||||
total_released: 0,
|
||||
hit_rate: 0.0,
|
||||
estimated_memory_usage: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能通用对象池
|
||||
* 支持任意类型的对象池化,包含详细的统计信息
|
||||
*/
|
||||
pub struct Pool<T: Poolable> {
|
||||
/// 池中的对象
|
||||
objects: Vec<T>,
|
||||
/// 创建对象的函数
|
||||
create_fn: Box<dyn Fn() -> T + Send + Sync>,
|
||||
/// 池的最大大小
|
||||
max_size: usize,
|
||||
/// 统计信息
|
||||
stats: PoolStats,
|
||||
/// 估算的单个对象大小
|
||||
object_size: usize,
|
||||
}
|
||||
|
||||
impl<T: Poolable> Pool<T> {
|
||||
/**
|
||||
* 创建新的对象池
|
||||
*/
|
||||
pub fn new<F>(create_fn: F, max_size: usize, estimated_object_size: usize) -> Self
|
||||
where
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
{
|
||||
Self {
|
||||
objects: Vec::new(),
|
||||
create_fn: Box::new(create_fn),
|
||||
max_size,
|
||||
stats: PoolStats {
|
||||
max_size,
|
||||
..Default::default()
|
||||
},
|
||||
object_size: estimated_object_size,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从池中获取对象
|
||||
*/
|
||||
pub fn obtain(&mut self) -> T {
|
||||
self.stats.total_obtained += 1;
|
||||
|
||||
if let Some(mut obj) = self.objects.pop() {
|
||||
self.stats.size -= 1;
|
||||
self.update_hit_rate();
|
||||
self.update_memory_usage();
|
||||
obj.reset(); // 重置对象状态
|
||||
obj
|
||||
} else {
|
||||
// 池中没有可用对象,创建新对象
|
||||
self.stats.total_created += 1;
|
||||
self.update_hit_rate();
|
||||
(self.create_fn)()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放对象回池中
|
||||
*/
|
||||
pub fn release(&mut self, mut obj: T) {
|
||||
self.stats.total_released += 1;
|
||||
|
||||
// 如果池未满,将对象放回池中
|
||||
if self.stats.size < self.max_size {
|
||||
obj.reset();
|
||||
self.objects.push(obj);
|
||||
self.stats.size += 1;
|
||||
self.update_memory_usage();
|
||||
}
|
||||
// 如果池已满,让对象被drop
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> &PoolStats {
|
||||
&self.stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空池
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.objects.clear();
|
||||
self.stats.size = 0;
|
||||
self.update_memory_usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩池(移除多余的对象)
|
||||
*/
|
||||
pub fn compact(&mut self, target_size: Option<usize>) {
|
||||
let target = target_size.unwrap_or(self.objects.len() / 2);
|
||||
|
||||
while self.objects.len() > target {
|
||||
self.objects.pop();
|
||||
self.stats.size -= 1;
|
||||
}
|
||||
|
||||
self.update_memory_usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预填充池
|
||||
*/
|
||||
pub fn prewarm(&mut self, count: usize) {
|
||||
let actual_count = count.min(self.max_size - self.objects.len());
|
||||
|
||||
for _ in 0..actual_count {
|
||||
let mut obj = (self.create_fn)();
|
||||
obj.reset();
|
||||
self.objects.push(obj);
|
||||
self.stats.total_created += 1;
|
||||
self.stats.size += 1;
|
||||
}
|
||||
|
||||
self.update_memory_usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最大池大小
|
||||
*/
|
||||
pub fn set_max_size(&mut self, max_size: usize) {
|
||||
self.max_size = max_size;
|
||||
self.stats.max_size = max_size;
|
||||
|
||||
// 如果当前池大小超过新的最大值,进行压缩
|
||||
if self.objects.len() > max_size {
|
||||
self.compact(Some(max_size));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池中可用对象数量
|
||||
*/
|
||||
pub fn get_available_count(&self) -> usize {
|
||||
self.objects.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查池是否为空
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.objects.is_empty()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查池是否已满
|
||||
*/
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.objects.len() >= self.max_size
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池的最大大小
|
||||
*/
|
||||
pub fn max_size(&self) -> usize {
|
||||
self.max_size
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新命中率
|
||||
*/
|
||||
fn update_hit_rate(&mut self) {
|
||||
if self.stats.total_obtained == 0 {
|
||||
self.stats.hit_rate = 0.0;
|
||||
} else {
|
||||
let hits = self.stats.total_obtained - self.stats.total_created;
|
||||
self.stats.hit_rate = hits as f64 / self.stats.total_obtained as f64;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新内存使用估算
|
||||
*/
|
||||
fn update_memory_usage(&mut self) {
|
||||
self.stats.estimated_memory_usage = self.stats.size * self.object_size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool trait object for heterogeneous storage
|
||||
*/
|
||||
trait AnyPool: Send + Sync {
|
||||
fn clear(&mut self);
|
||||
fn compact(&mut self);
|
||||
fn get_stats(&self) -> PoolStats;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl<T: Poolable + 'static> AnyPool for Pool<T> {
|
||||
fn clear(&mut self) {
|
||||
Pool::clear(self);
|
||||
}
|
||||
|
||||
fn compact(&mut self) {
|
||||
Pool::compact(self, None);
|
||||
}
|
||||
|
||||
fn get_stats(&self) -> PoolStats {
|
||||
self.stats.clone()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 池管理器
|
||||
* 统一管理所有对象池
|
||||
*/
|
||||
pub struct PoolManager {
|
||||
/// 池映射
|
||||
pools: FxHashMap<String, Box<dyn AnyPool>>,
|
||||
/// 自动压缩间隔(毫秒)
|
||||
auto_compact_interval: u64,
|
||||
/// 上次压缩时间
|
||||
last_compact_time: u64,
|
||||
}
|
||||
|
||||
impl PoolManager {
|
||||
/**
|
||||
* 创建新的池管理器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pools: FxHashMap::default(),
|
||||
auto_compact_interval: 60000, // 60秒
|
||||
last_compact_time: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册池
|
||||
*/
|
||||
pub fn register_pool<T: Poolable + 'static>(&mut self, name: String, pool: Pool<T>) {
|
||||
self.pools.insert(name, Box::new(pool));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池
|
||||
*/
|
||||
pub fn get_pool<T: Poolable + 'static>(&mut self, name: &str) -> Option<&mut Pool<T>> {
|
||||
if let Some(pool) = self.pools.get_mut(name) {
|
||||
pool.as_any_mut().downcast_mut::<Pool<T>>()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或获取池
|
||||
*/
|
||||
pub fn create_pool<T, F>(
|
||||
&mut self,
|
||||
name: String,
|
||||
create_fn: F,
|
||||
max_size: usize,
|
||||
estimated_object_size: usize,
|
||||
) -> &mut Pool<T>
|
||||
where
|
||||
T: Poolable + 'static,
|
||||
F: Fn() -> T + Send + Sync + 'static,
|
||||
{
|
||||
if !self.pools.contains_key(&name) {
|
||||
let pool = Pool::new(create_fn, max_size, estimated_object_size);
|
||||
self.pools.insert(name.clone(), Box::new(pool));
|
||||
}
|
||||
|
||||
self.get_pool(&name).unwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新池管理器(应在游戏循环中调用)
|
||||
*/
|
||||
pub fn update(&mut self) {
|
||||
let now = current_timestamp();
|
||||
|
||||
if now - self.last_compact_time > self.auto_compact_interval {
|
||||
self.compact_all_pools();
|
||||
self.last_compact_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除池
|
||||
*/
|
||||
pub fn remove_pool(&mut self, name: &str) -> bool {
|
||||
if let Some(mut pool) = self.pools.remove(name) {
|
||||
pool.clear();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有池名称
|
||||
*/
|
||||
pub fn get_pool_names(&self) -> Vec<String> {
|
||||
self.pools.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取池数量
|
||||
*/
|
||||
pub fn get_pool_count(&self) -> usize {
|
||||
self.pools.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩所有池
|
||||
*/
|
||||
pub fn compact_all_pools(&mut self) {
|
||||
for pool in self.pools.values_mut() {
|
||||
pool.compact();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有池
|
||||
*/
|
||||
pub fn clear_all_pools(&mut self) {
|
||||
for pool in self.pools.values_mut() {
|
||||
pool.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有池的统计信息
|
||||
*/
|
||||
pub fn get_all_stats(&self) -> FxHashMap<String, PoolStats> {
|
||||
let mut stats = FxHashMap::default();
|
||||
|
||||
for (name, pool) in &self.pools {
|
||||
stats.insert(name.clone(), pool.get_stats());
|
||||
}
|
||||
|
||||
stats
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取总体统计信息
|
||||
*/
|
||||
pub fn get_global_stats(&self) -> PoolStats {
|
||||
let mut total_size = 0;
|
||||
let mut total_max_size = 0;
|
||||
let mut total_created = 0;
|
||||
let mut total_obtained = 0;
|
||||
let mut total_released = 0;
|
||||
let mut total_memory_usage = 0;
|
||||
|
||||
for pool in self.pools.values() {
|
||||
let stats = pool.get_stats();
|
||||
total_size += stats.size;
|
||||
total_max_size += stats.max_size;
|
||||
total_created += stats.total_created;
|
||||
total_obtained += stats.total_obtained;
|
||||
total_released += stats.total_released;
|
||||
total_memory_usage += stats.estimated_memory_usage;
|
||||
}
|
||||
|
||||
let hit_rate = if total_obtained == 0 {
|
||||
0.0
|
||||
} else {
|
||||
(total_obtained - total_created) as f64 / total_obtained as f64
|
||||
};
|
||||
|
||||
PoolStats {
|
||||
size: total_size,
|
||||
max_size: total_max_size,
|
||||
total_created,
|
||||
total_obtained,
|
||||
total_released,
|
||||
hit_rate,
|
||||
estimated_memory_usage: total_memory_usage,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取格式化的统计信息字符串
|
||||
*/
|
||||
pub fn get_stats_string(&self) -> String {
|
||||
let mut lines = vec![
|
||||
"=== Pool Manager Statistics ===".to_string(),
|
||||
"".to_string(),
|
||||
];
|
||||
|
||||
if self.pools.is_empty() {
|
||||
lines.push("No pools registered".to_string());
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
let global_stats = self.get_global_stats();
|
||||
lines.push(format!("Total Pools: {}", self.pools.len()));
|
||||
lines.push(format!("Global Hit Rate: {:.1}%", global_stats.hit_rate * 100.0));
|
||||
lines.push(format!(
|
||||
"Global Memory Usage: {:.1} KB",
|
||||
global_stats.estimated_memory_usage as f64 / 1024.0
|
||||
));
|
||||
lines.push("".to_string());
|
||||
|
||||
for (name, pool) in &self.pools {
|
||||
let stats = pool.get_stats();
|
||||
lines.push(format!("{}:", name));
|
||||
lines.push(format!(" Size: {}/{}", stats.size, stats.max_size));
|
||||
lines.push(format!(" Hit Rate: {:.1}%", stats.hit_rate * 100.0));
|
||||
lines.push(format!(
|
||||
" Memory: {:.1} KB",
|
||||
stats.estimated_memory_usage as f64 / 1024.0
|
||||
));
|
||||
lines.push("".to_string());
|
||||
}
|
||||
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自动压缩间隔
|
||||
*/
|
||||
pub fn set_auto_compact_interval(&mut self, interval_ms: u64) {
|
||||
self.auto_compact_interval = interval_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预填充所有池
|
||||
*/
|
||||
pub fn prewarm_all_pools(&mut self) {
|
||||
for pool in self.pools.values_mut() {
|
||||
let stats = pool.get_stats();
|
||||
let prewarm_count = (stats.max_size as f64 * 0.2) as usize; // 预填充20%
|
||||
// 注意:这里需要访问具体的池类型来调用prewarm
|
||||
// 在实际使用中,可能需要为AnyPool trait添加prewarm方法
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置池管理器
|
||||
*/
|
||||
pub fn reset(&mut self) {
|
||||
self.clear_all_pools();
|
||||
self.pools.clear();
|
||||
self.last_compact_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PoolManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
fn current_timestamp() -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// 测试对象
|
||||
#[derive(Debug, Clone)]
|
||||
struct TestObject {
|
||||
value: i32,
|
||||
data: String,
|
||||
}
|
||||
|
||||
impl TestObject {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
value: 0,
|
||||
data: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_value(value: i32) -> Self {
|
||||
Self {
|
||||
value,
|
||||
data: format!("data_{}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Poolable for TestObject {
|
||||
fn reset(&mut self) {
|
||||
self.value = 0;
|
||||
self.data.clear();
|
||||
}
|
||||
|
||||
fn estimated_size(&self) -> usize {
|
||||
std::mem::size_of::<Self>() + self.data.capacity()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_creation() {
|
||||
let pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
assert_eq!(pool.get_available_count(), 0);
|
||||
assert_eq!(pool.max_size(), 10);
|
||||
assert!(pool.is_empty());
|
||||
assert!(!pool.is_full());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_obtain_release() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
// 获取对象(池为空,应该创建新对象)
|
||||
let obj = pool.obtain();
|
||||
assert_eq!(obj.value, 0);
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_created, 1);
|
||||
assert_eq!(stats.total_obtained, 1);
|
||||
|
||||
// 释放对象
|
||||
pool.release(obj);
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_released, 1);
|
||||
assert_eq!(stats.size, 1);
|
||||
assert_eq!(pool.get_available_count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_reuse() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
// 创建并释放一个对象
|
||||
let mut obj = pool.obtain();
|
||||
obj.value = 42;
|
||||
obj.data = "test".to_string();
|
||||
pool.release(obj);
|
||||
|
||||
// 再次获取应该得到重置后的对象
|
||||
let obj = pool.obtain();
|
||||
assert_eq!(obj.value, 0);
|
||||
assert!(obj.data.is_empty());
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_created, 1); // 只创建了一次
|
||||
assert_eq!(stats.total_obtained, 2); // 获取了两次
|
||||
assert!(stats.hit_rate > 0.0); // 有命中率
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_max_size() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 2, 64);
|
||||
|
||||
// 释放3个对象,但池最大大小为2
|
||||
pool.release(TestObject::new());
|
||||
pool.release(TestObject::new());
|
||||
pool.release(TestObject::new()); // 这个应该被丢弃
|
||||
|
||||
assert_eq!(pool.get_available_count(), 2);
|
||||
assert!(pool.is_full());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_prewarm() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
pool.prewarm(5);
|
||||
|
||||
assert_eq!(pool.get_available_count(), 5);
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_created, 5);
|
||||
assert_eq!(stats.size, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_compact() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
// 预填充
|
||||
pool.prewarm(8);
|
||||
assert_eq!(pool.get_available_count(), 8);
|
||||
|
||||
// 压缩到一半
|
||||
pool.compact(Some(4));
|
||||
assert_eq!(pool.get_available_count(), 4);
|
||||
|
||||
// 默认压缩
|
||||
pool.compact(None);
|
||||
assert_eq!(pool.get_available_count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_clear() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
pool.prewarm(5);
|
||||
assert_eq!(pool.get_available_count(), 5);
|
||||
|
||||
pool.clear();
|
||||
assert_eq!(pool.get_available_count(), 0);
|
||||
assert!(pool.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_set_max_size() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
pool.prewarm(8);
|
||||
assert_eq!(pool.get_available_count(), 8);
|
||||
|
||||
// 减小最大大小应该自动压缩
|
||||
pool.set_max_size(5);
|
||||
assert_eq!(pool.max_size(), 5);
|
||||
assert_eq!(pool.get_available_count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_stats() {
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
// 获取和释放一些对象
|
||||
let obj1 = pool.obtain();
|
||||
let obj2 = pool.obtain();
|
||||
pool.release(obj1);
|
||||
|
||||
let obj3 = pool.obtain(); // 应该重用obj1
|
||||
pool.release(obj2);
|
||||
pool.release(obj3);
|
||||
|
||||
let stats = pool.get_stats();
|
||||
assert_eq!(stats.total_created, 2);
|
||||
assert_eq!(stats.total_obtained, 3);
|
||||
assert_eq!(stats.total_released, 3);
|
||||
assert!(stats.hit_rate > 0.0);
|
||||
assert_eq!(stats.size, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_creation() {
|
||||
let manager = PoolManager::new();
|
||||
assert_eq!(manager.get_pool_count(), 0);
|
||||
assert!(manager.get_pool_names().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_register_get() {
|
||||
let mut manager = PoolManager::new();
|
||||
let pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
manager.register_pool("test_objects".to_string(), pool);
|
||||
assert_eq!(manager.get_pool_count(), 1);
|
||||
|
||||
let retrieved_pool = manager.get_pool::<TestObject>("test_objects");
|
||||
assert!(retrieved_pool.is_some());
|
||||
|
||||
let non_existent = manager.get_pool::<TestObject>("non_existent");
|
||||
assert!(non_existent.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_create_pool() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let pool = manager.create_pool(
|
||||
"test_objects".to_string(),
|
||||
TestObject::new,
|
||||
10,
|
||||
64,
|
||||
);
|
||||
|
||||
assert_eq!(pool.max_size(), 10);
|
||||
assert_eq!(manager.get_pool_count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_remove_pool() {
|
||||
let mut manager = PoolManager::new();
|
||||
let pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
|
||||
manager.register_pool("test_objects".to_string(), pool);
|
||||
assert_eq!(manager.get_pool_count(), 1);
|
||||
|
||||
assert!(manager.remove_pool("test_objects"));
|
||||
assert_eq!(manager.get_pool_count(), 0);
|
||||
|
||||
assert!(!manager.remove_pool("non_existent"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_global_stats() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let pool1: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
let pool2: Pool<TestObject> = Pool::new(TestObject::new, 20, 128);
|
||||
|
||||
manager.register_pool("pool1".to_string(), pool1);
|
||||
manager.register_pool("pool2".to_string(), pool2);
|
||||
|
||||
let global_stats = manager.get_global_stats();
|
||||
assert_eq!(global_stats.max_size, 30); // 10 + 20
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_clear_all() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
pool.prewarm(5);
|
||||
|
||||
manager.register_pool("test_objects".to_string(), pool);
|
||||
|
||||
manager.clear_all_pools();
|
||||
|
||||
if let Some(pool) = manager.get_pool::<TestObject>("test_objects") {
|
||||
assert!(pool.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_compact_all() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let mut pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
pool.prewarm(8);
|
||||
|
||||
manager.register_pool("test_objects".to_string(), pool);
|
||||
|
||||
manager.compact_all_pools();
|
||||
|
||||
if let Some(pool) = manager.get_pool::<TestObject>("test_objects") {
|
||||
assert!(pool.get_available_count() <= 4); // 压缩后应该减少
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_stats_string() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
manager.register_pool("test_objects".to_string(), pool);
|
||||
|
||||
let stats_string = manager.get_stats_string();
|
||||
assert!(stats_string.contains("Pool Manager Statistics"));
|
||||
assert!(stats_string.contains("test_objects"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_reset() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let pool: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
manager.register_pool("test_objects".to_string(), pool);
|
||||
|
||||
assert_eq!(manager.get_pool_count(), 1);
|
||||
|
||||
manager.reset();
|
||||
|
||||
assert_eq!(manager.get_pool_count(), 0);
|
||||
assert_eq!(manager.last_compact_time, 0);
|
||||
}
|
||||
|
||||
// 测试不同类型的Poolable对象
|
||||
#[derive(Debug)]
|
||||
struct AnotherTestObject {
|
||||
id: u32,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl AnotherTestObject {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
active: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Poolable for AnotherTestObject {
|
||||
fn reset(&mut self) {
|
||||
self.id = 0;
|
||||
self.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_manager_multiple_types() {
|
||||
let mut manager = PoolManager::new();
|
||||
|
||||
let pool1: Pool<TestObject> = Pool::new(TestObject::new, 10, 64);
|
||||
let pool2: Pool<AnotherTestObject> = Pool::new(AnotherTestObject::new, 5, 32);
|
||||
|
||||
manager.register_pool("test_objects".to_string(), pool1);
|
||||
manager.register_pool("another_objects".to_string(), pool2);
|
||||
|
||||
assert_eq!(manager.get_pool_count(), 2);
|
||||
|
||||
let pool1 = manager.get_pool::<TestObject>("test_objects");
|
||||
assert!(pool1.is_some());
|
||||
|
||||
let pool2 = manager.get_pool::<AnotherTestObject>("another_objects");
|
||||
assert!(pool2.is_some());
|
||||
|
||||
// 尝试用错误的类型获取池
|
||||
let wrong_pool = manager.get_pool::<AnotherTestObject>("test_objects");
|
||||
assert!(wrong_pool.is_none());
|
||||
}
|
||||
}
|
||||
238
packages/core-rust/src/utils/sparse_set.rs
Normal file
238
packages/core-rust/src/utils/sparse_set.rs
Normal file
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* 高性能稀疏集合数据结构
|
||||
*
|
||||
* SparseSet是ECS系统中常用的数据结构,提供O(1)的插入、删除和查找操作
|
||||
* 同时支持密集数组迭代,非常适合存储稀疏的实体组件数据
|
||||
*/
|
||||
pub struct SparseSet {
|
||||
/// 稀疏数组,索引到密集数组的映射
|
||||
sparse: Vec<Option<usize>>,
|
||||
|
||||
/// 密集数组,存储实际的值
|
||||
dense: Vec<u32>,
|
||||
|
||||
/// 当前元素数量
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl SparseSet {
|
||||
/**
|
||||
* 创建新的稀疏集合
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
sparse: Vec::new(),
|
||||
dense: Vec::new(),
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定容量的稀疏集合
|
||||
*/
|
||||
pub fn with_capacity(sparse_capacity: usize, dense_capacity: usize) -> Self {
|
||||
Self {
|
||||
sparse: vec![None; sparse_capacity],
|
||||
dense: Vec::with_capacity(dense_capacity),
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入值
|
||||
*/
|
||||
pub fn insert(&mut self, value: u32) -> bool {
|
||||
let sparse_index = value as usize;
|
||||
|
||||
// 确保稀疏数组足够大
|
||||
if sparse_index >= self.sparse.len() {
|
||||
self.sparse.resize(sparse_index + 1, None);
|
||||
}
|
||||
|
||||
// 检查值是否已存在
|
||||
if self.sparse[sparse_index].is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 插入到密集数组
|
||||
let dense_index = self.size;
|
||||
if dense_index >= self.dense.len() {
|
||||
self.dense.push(value);
|
||||
} else {
|
||||
self.dense[dense_index] = value;
|
||||
}
|
||||
|
||||
// 建立稀疏数组映射
|
||||
self.sparse[sparse_index] = Some(dense_index);
|
||||
self.size += 1;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除值
|
||||
*/
|
||||
pub fn remove(&mut self, value: u32) -> bool {
|
||||
let sparse_index = value as usize;
|
||||
|
||||
// 检查边界和存在性
|
||||
if sparse_index >= self.sparse.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(dense_index) = self.sparse[sparse_index] else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// 移除稀疏数组映射
|
||||
self.sparse[sparse_index] = None;
|
||||
|
||||
// 将最后一个元素移动到被删除位置(保持密集性)
|
||||
let last_index = self.size - 1;
|
||||
if dense_index != last_index {
|
||||
let last_value = self.dense[last_index];
|
||||
self.dense[dense_index] = last_value;
|
||||
|
||||
// 更新被移动元素的稀疏数组映射
|
||||
self.sparse[last_value as usize] = Some(dense_index);
|
||||
}
|
||||
|
||||
self.size -= 1;
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查值是否存在
|
||||
*/
|
||||
pub fn contains(&self, value: u32) -> bool {
|
||||
let sparse_index = value as usize;
|
||||
sparse_index < self.sparse.len() && self.sparse[sparse_index].is_some()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元素数量
|
||||
*/
|
||||
pub fn len(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为空
|
||||
*/
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.size == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空集合
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.sparse.clear();
|
||||
self.dense.clear();
|
||||
self.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密集数组的引用
|
||||
*/
|
||||
pub fn dense(&self) -> &[u32] {
|
||||
&self.dense[0..self.size]
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密集数组的可变引用
|
||||
*/
|
||||
pub fn dense_mut(&mut self) -> &mut [u32] {
|
||||
&mut self.dense[0..self.size]
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代所有值
|
||||
*/
|
||||
pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
|
||||
self.dense[0..self.size].iter().copied()
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入
|
||||
*/
|
||||
pub fn insert_batch(&mut self, values: &[u32]) {
|
||||
for &value in values {
|
||||
self.insert(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取值在密集数组中的索引
|
||||
*/
|
||||
pub fn get_dense_index(&self, value: u32) -> Option<usize> {
|
||||
let sparse_index = value as usize;
|
||||
if sparse_index < self.sparse.len() {
|
||||
self.sparse[sparse_index]
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预分配容量
|
||||
*/
|
||||
pub fn reserve(&mut self, sparse_capacity: usize, dense_capacity: usize) {
|
||||
if sparse_capacity > self.sparse.len() {
|
||||
self.sparse.resize(sparse_capacity, None);
|
||||
}
|
||||
if dense_capacity > self.dense.capacity() {
|
||||
self.dense.reserve(dense_capacity - self.dense.capacity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 与另一个稀疏集合取交集
|
||||
*/
|
||||
pub fn intersection(&self, other: &SparseSet) -> SparseSet {
|
||||
let mut result = SparseSet::new();
|
||||
|
||||
for value in self.iter() {
|
||||
if other.contains(value) {
|
||||
result.insert(value);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* 与另一个稀疏集合取并集
|
||||
*/
|
||||
pub fn union(&self, other: &SparseSet) -> SparseSet {
|
||||
let mut result = SparseSet::new();
|
||||
|
||||
// 添加当前集合的所有元素
|
||||
for value in self.iter() {
|
||||
result.insert(value);
|
||||
}
|
||||
|
||||
// 添加另一个集合的所有元素
|
||||
for value in other.iter() {
|
||||
result.insert(value);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SparseSet {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SparseSet {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SparseSet")
|
||||
.field("size", &self.size)
|
||||
.field("sparse_len", &self.sparse.len())
|
||||
.field("dense_elements", &self.dense[0..self.size].to_vec())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
124
packages/core-rust/src/utils/time.rs
Normal file
124
packages/core-rust/src/utils/time.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
/**
|
||||
* 时间管理工具类
|
||||
* 提供游戏时间相关的功能,包括帧时间、总时间、时间缩放等
|
||||
*/
|
||||
pub struct Time {
|
||||
/// 上一帧到当前帧的时间间隔(秒)
|
||||
delta_time: f64,
|
||||
|
||||
/// 未缩放的帧时间间隔(秒)
|
||||
unscaled_delta_time: f64,
|
||||
|
||||
/// 游戏开始以来的总时间(秒)
|
||||
total_time: f64,
|
||||
|
||||
/// 未缩放的总时间(秒)
|
||||
unscaled_total_time: f64,
|
||||
|
||||
/// 时间缩放比例
|
||||
time_scale: f64,
|
||||
|
||||
/// 当前帧数
|
||||
frame_count: u64,
|
||||
}
|
||||
|
||||
impl Time {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
delta_time: 0.0,
|
||||
unscaled_delta_time: 0.0,
|
||||
total_time: 0.0,
|
||||
unscaled_total_time: 0.0,
|
||||
time_scale: 1.0,
|
||||
frame_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局Time实例
|
||||
*/
|
||||
pub fn instance() -> &'static Mutex<Time> {
|
||||
static TIME: OnceLock<Mutex<Time>> = OnceLock::new();
|
||||
TIME.get_or_init(|| Mutex::new(Time::new()))
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用外部引擎提供的deltaTime更新时间信息
|
||||
*/
|
||||
pub fn update(delta_time: f64) {
|
||||
let mut time = Self::instance().lock().unwrap();
|
||||
time.unscaled_delta_time = delta_time;
|
||||
time.delta_time = delta_time * time.time_scale;
|
||||
|
||||
// 更新总时间
|
||||
time.unscaled_total_time += time.unscaled_delta_time;
|
||||
time.total_time += time.delta_time;
|
||||
|
||||
// 更新帧数
|
||||
time.frame_count += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取帧时间间隔
|
||||
*/
|
||||
pub fn delta_time() -> f64 {
|
||||
Self::instance().lock().unwrap().delta_time
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未缩放的帧时间间隔
|
||||
*/
|
||||
pub fn unscaled_delta_time() -> f64 {
|
||||
Self::instance().lock().unwrap().unscaled_delta_time
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取总时间
|
||||
*/
|
||||
pub fn total_time() -> f64 {
|
||||
Self::instance().lock().unwrap().total_time
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未缩放的总时间
|
||||
*/
|
||||
pub fn unscaled_total_time() -> f64 {
|
||||
Self::instance().lock().unwrap().unscaled_total_time
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间缩放比例
|
||||
*/
|
||||
pub fn time_scale() -> f64 {
|
||||
Self::instance().lock().unwrap().time_scale
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置时间缩放比例
|
||||
*/
|
||||
pub fn set_time_scale(scale: f64) {
|
||||
Self::instance().lock().unwrap().time_scale = scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前帧数
|
||||
*/
|
||||
pub fn frame_count() -> u64 {
|
||||
Self::instance().lock().unwrap().frame_count
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置时间
|
||||
*/
|
||||
pub fn reset() {
|
||||
let mut time = Self::instance().lock().unwrap();
|
||||
time.delta_time = 0.0;
|
||||
time.unscaled_delta_time = 0.0;
|
||||
time.total_time = 0.0;
|
||||
time.unscaled_total_time = 0.0;
|
||||
time.time_scale = 1.0;
|
||||
time.frame_count = 0;
|
||||
}
|
||||
}
|
||||
665
packages/core-rust/src/utils/timer.rs
Normal file
665
packages/core-rust/src/utils/timer.rs
Normal file
@@ -0,0 +1,665 @@
|
||||
use crate::utils::Time;
|
||||
use std::any::Any;
|
||||
|
||||
/**
|
||||
* 定时器回调函数类型
|
||||
*/
|
||||
pub type TimerCallback = Box<dyn FnMut(&mut dyn TimerContext) + Send + Sync>;
|
||||
|
||||
/**
|
||||
* 定时器上下文trait
|
||||
* 用于提供回调函数访问的上下文数据
|
||||
*/
|
||||
pub trait TimerContext: Send + Sync {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的空上下文实现
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct EmptyContext;
|
||||
|
||||
impl TimerContext for EmptyContext {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时器接口trait
|
||||
*/
|
||||
pub trait ITimer {
|
||||
/**
|
||||
* 停止此计时器再次运行。这对非重复计时器没有影响。
|
||||
*/
|
||||
fn stop(&mut self);
|
||||
|
||||
/**
|
||||
* 将计时器的运行时间重置为0
|
||||
*/
|
||||
fn reset(&mut self);
|
||||
|
||||
/**
|
||||
* 返回上下文
|
||||
*/
|
||||
fn get_context(&self) -> &dyn TimerContext;
|
||||
|
||||
/**
|
||||
* 返回可变上下文
|
||||
*/
|
||||
fn get_context_mut(&mut self) -> &mut dyn TimerContext;
|
||||
|
||||
/**
|
||||
* 检查定时器是否已完成
|
||||
*/
|
||||
fn is_done(&self) -> bool;
|
||||
|
||||
/**
|
||||
* 获取已运行的时间
|
||||
*/
|
||||
fn elapsed_time(&self) -> f64;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时器实现
|
||||
*/
|
||||
pub struct Timer {
|
||||
/// 上下文数据
|
||||
context: Box<dyn TimerContext>,
|
||||
/// 定时器间隔时间(秒)
|
||||
time_in_seconds: f64,
|
||||
/// 是否重复执行
|
||||
repeats: bool,
|
||||
/// 回调函数
|
||||
on_time: Option<TimerCallback>,
|
||||
/// 是否已完成
|
||||
is_done: bool,
|
||||
/// 已运行时间
|
||||
elapsed_time: f64,
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
/**
|
||||
* 创建新的定时器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
context: Box::new(EmptyContext),
|
||||
time_in_seconds: 0.0,
|
||||
repeats: false,
|
||||
on_time: None,
|
||||
is_done: false,
|
||||
elapsed_time: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化定时器
|
||||
*/
|
||||
pub fn initialize<F>(
|
||||
&mut self,
|
||||
time_in_seconds: f64,
|
||||
repeats: bool,
|
||||
context: Box<dyn TimerContext>,
|
||||
on_time: F,
|
||||
) where
|
||||
F: FnMut(&mut dyn TimerContext) + Send + Sync + 'static,
|
||||
{
|
||||
self.time_in_seconds = time_in_seconds;
|
||||
self.repeats = repeats;
|
||||
self.context = context;
|
||||
self.on_time = Some(Box::new(on_time));
|
||||
self.is_done = false;
|
||||
self.elapsed_time = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用简单回调初始化定时器
|
||||
*/
|
||||
pub fn initialize_simple<F>(
|
||||
&mut self,
|
||||
time_in_seconds: f64,
|
||||
repeats: bool,
|
||||
on_time: F,
|
||||
) where
|
||||
F: FnMut(&mut dyn TimerContext) + Send + Sync + 'static,
|
||||
{
|
||||
self.initialize(time_in_seconds, repeats, Box::new(EmptyContext), on_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新定时器状态
|
||||
* 返回是否已完成
|
||||
*/
|
||||
pub fn tick(&mut self, delta_time: f64) -> bool {
|
||||
if self.is_done {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.elapsed_time += delta_time;
|
||||
|
||||
// 检查是否到达触发时间
|
||||
if self.elapsed_time >= self.time_in_seconds {
|
||||
if let Some(callback) = &mut self.on_time {
|
||||
// 调用回调函数
|
||||
callback(self.context.as_mut());
|
||||
}
|
||||
|
||||
if self.repeats {
|
||||
// 重复定时器,重置经过时间但保留超出部分
|
||||
self.elapsed_time -= self.time_in_seconds;
|
||||
} else {
|
||||
// 一次性定时器,标记为完成
|
||||
self.is_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.is_done
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理定时器资源
|
||||
*/
|
||||
pub fn unload(&mut self) {
|
||||
self.on_time = None;
|
||||
self.context = Box::new(EmptyContext);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Timer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ITimer for Timer {
|
||||
fn stop(&mut self) {
|
||||
self.is_done = true;
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.elapsed_time = 0.0;
|
||||
self.is_done = false;
|
||||
}
|
||||
|
||||
fn get_context(&self) -> &dyn TimerContext {
|
||||
self.context.as_ref()
|
||||
}
|
||||
|
||||
fn get_context_mut(&mut self) -> &mut dyn TimerContext {
|
||||
self.context.as_mut()
|
||||
}
|
||||
|
||||
fn is_done(&self) -> bool {
|
||||
self.is_done
|
||||
}
|
||||
|
||||
fn elapsed_time(&self) -> f64 {
|
||||
self.elapsed_time
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时器管理器
|
||||
* 允许动作的延迟和重复执行
|
||||
*/
|
||||
pub struct TimerManager {
|
||||
/// 活跃的定时器列表
|
||||
timers: Vec<Timer>,
|
||||
/// 管理器是否启用
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl TimerManager {
|
||||
/**
|
||||
* 创建新的定时器管理器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
timers: Vec::new(),
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用管理器
|
||||
*/
|
||||
pub fn enable(&mut self) {
|
||||
self.enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用管理器
|
||||
*/
|
||||
pub fn disable(&mut self) {
|
||||
self.enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查管理器是否启用
|
||||
*/
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有定时器
|
||||
*/
|
||||
pub fn update(&mut self, time: &Time) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let delta_time = Time::delta_time();
|
||||
|
||||
// 从后向前遍历以安全地移除完成的定时器
|
||||
let mut i = self.timers.len();
|
||||
while i > 0 {
|
||||
i -= 1;
|
||||
if self.timers[i].tick(delta_time) {
|
||||
self.timers[i].unload();
|
||||
self.timers.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调度一个一次性或重复的计时器
|
||||
*/
|
||||
pub fn schedule<F>(
|
||||
&mut self,
|
||||
time_in_seconds: f64,
|
||||
repeats: bool,
|
||||
context: Box<dyn TimerContext>,
|
||||
on_time: F,
|
||||
) -> usize
|
||||
where
|
||||
F: FnMut(&mut dyn TimerContext) + Send + Sync + 'static,
|
||||
{
|
||||
let mut timer = Timer::new();
|
||||
timer.initialize(time_in_seconds, repeats, context, on_time);
|
||||
|
||||
self.timers.push(timer);
|
||||
self.timers.len() - 1 // 返回定时器的索引
|
||||
}
|
||||
|
||||
/**
|
||||
* 调度简单定时器(无上下文)
|
||||
*/
|
||||
pub fn schedule_simple<F>(
|
||||
&mut self,
|
||||
time_in_seconds: f64,
|
||||
repeats: bool,
|
||||
on_time: F,
|
||||
) -> usize
|
||||
where
|
||||
F: FnMut(&mut dyn TimerContext) + Send + Sync + 'static,
|
||||
{
|
||||
self.schedule(time_in_seconds, repeats, Box::new(EmptyContext), on_time)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止指定索引的定时器
|
||||
*/
|
||||
pub fn stop_timer(&mut self, index: usize) -> bool {
|
||||
if index < self.timers.len() {
|
||||
self.timers[index].stop();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置指定索引的定时器
|
||||
*/
|
||||
pub fn reset_timer(&mut self, index: usize) -> bool {
|
||||
if index < self.timers.len() {
|
||||
self.timers[index].reset();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活跃定时器数量
|
||||
*/
|
||||
pub fn active_timer_count(&self) -> usize {
|
||||
self.timers.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有定时器
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
for timer in &mut self.timers {
|
||||
timer.unload();
|
||||
}
|
||||
self.timers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的定时器
|
||||
*/
|
||||
pub fn get_timer(&self, index: usize) -> Option<&Timer> {
|
||||
self.timers.get(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的可变定时器
|
||||
*/
|
||||
pub fn get_timer_mut(&mut self, index: usize) -> Option<&mut Timer> {
|
||||
self.timers.get_mut(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有已完成的定时器
|
||||
*/
|
||||
pub fn cleanup_completed(&mut self) {
|
||||
self.timers.retain_mut(|timer| {
|
||||
if timer.is_done() {
|
||||
timer.unload();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TimerManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
// 测试上下文
|
||||
#[derive(Debug)]
|
||||
struct TestContext {
|
||||
pub value: i32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl TimerContext for TestContext {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_creation() {
|
||||
let timer = Timer::new();
|
||||
assert!(!timer.is_done());
|
||||
assert_eq!(timer.elapsed_time(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_simple_initialization() {
|
||||
let mut timer = Timer::new();
|
||||
let mut callback_called = false;
|
||||
|
||||
timer.initialize_simple(1.0, false, move |_context| {
|
||||
callback_called = true;
|
||||
});
|
||||
|
||||
assert!(!timer.is_done());
|
||||
assert_eq!(timer.elapsed_time(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_tick_completion() {
|
||||
let mut timer = Timer::new();
|
||||
let callback_count = Arc::new(Mutex::new(0));
|
||||
let callback_count_clone = Arc::clone(&callback_count);
|
||||
|
||||
timer.initialize_simple(1.0, false, move |_context| {
|
||||
*callback_count_clone.lock().unwrap() += 1;
|
||||
});
|
||||
|
||||
// 第一次tick,时间不够
|
||||
assert!(!timer.tick(0.5));
|
||||
assert!(!timer.is_done());
|
||||
assert_eq!(timer.elapsed_time(), 0.5);
|
||||
assert_eq!(*callback_count.lock().unwrap(), 0);
|
||||
|
||||
// 第二次tick,时间足够
|
||||
assert!(timer.tick(0.6));
|
||||
assert!(timer.is_done());
|
||||
assert_eq!(*callback_count.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_repeat() {
|
||||
let mut timer = Timer::new();
|
||||
let callback_count = Arc::new(Mutex::new(0));
|
||||
let callback_count_clone = Arc::clone(&callback_count);
|
||||
|
||||
timer.initialize_simple(0.5, true, move |_context| {
|
||||
*callback_count_clone.lock().unwrap() += 1;
|
||||
});
|
||||
|
||||
// 多次tick测试重复执行
|
||||
assert!(!timer.tick(0.6)); // 第一次触发
|
||||
assert_eq!(*callback_count.lock().unwrap(), 1);
|
||||
assert!(!timer.is_done());
|
||||
|
||||
assert!(!timer.tick(0.5)); // 第二次触发
|
||||
assert_eq!(*callback_count.lock().unwrap(), 2);
|
||||
assert!(!timer.is_done());
|
||||
|
||||
// 停止定时器
|
||||
timer.stop();
|
||||
assert!(timer.is_done());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_reset() {
|
||||
let mut timer = Timer::new();
|
||||
let callback_count = Arc::new(Mutex::new(0));
|
||||
let callback_count_clone = Arc::clone(&callback_count);
|
||||
|
||||
timer.initialize_simple(1.0, false, move |_context| {
|
||||
*callback_count_clone.lock().unwrap() += 1;
|
||||
});
|
||||
|
||||
// 部分执行后重置
|
||||
timer.tick(0.5);
|
||||
assert_eq!(timer.elapsed_time(), 0.5);
|
||||
|
||||
timer.reset();
|
||||
assert_eq!(timer.elapsed_time(), 0.0);
|
||||
assert!(!timer.is_done());
|
||||
|
||||
// 重新执行
|
||||
timer.tick(1.1);
|
||||
assert_eq!(*callback_count.lock().unwrap(), 1);
|
||||
assert!(timer.is_done());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_with_context() {
|
||||
let mut timer = Timer::new();
|
||||
let context = TestContext {
|
||||
value: 10,
|
||||
name: "test".to_string(),
|
||||
};
|
||||
|
||||
timer.initialize(1.0, false, Box::new(context), |context| {
|
||||
if let Some(test_context) = context.as_any_mut().downcast_mut::<TestContext>() {
|
||||
test_context.value += 5;
|
||||
}
|
||||
});
|
||||
|
||||
timer.tick(1.1);
|
||||
|
||||
let context = timer.get_context();
|
||||
if let Some(test_context) = context.as_any().downcast_ref::<TestContext>() {
|
||||
assert_eq!(test_context.value, 15);
|
||||
assert_eq!(test_context.name, "test");
|
||||
} else {
|
||||
panic!("Context type mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_creation() {
|
||||
let manager = TimerManager::new();
|
||||
assert!(manager.enabled());
|
||||
assert_eq!(manager.active_timer_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_schedule_simple() {
|
||||
let mut manager = TimerManager::new();
|
||||
let callback_count = Arc::new(Mutex::new(0));
|
||||
let callback_count_clone = Arc::clone(&callback_count);
|
||||
|
||||
let timer_id = manager.schedule_simple(1.0, false, move |_context| {
|
||||
*callback_count_clone.lock().unwrap() += 1;
|
||||
});
|
||||
|
||||
assert_eq!(manager.active_timer_count(), 1);
|
||||
assert_eq!(timer_id, 0);
|
||||
|
||||
let time = Time::new();
|
||||
manager.update(&time);
|
||||
|
||||
assert_eq!(*callback_count.lock().unwrap(), 0); // 时间不够
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_schedule_with_context() {
|
||||
let mut manager = TimerManager::new();
|
||||
let context = TestContext {
|
||||
value: 0,
|
||||
name: "manager_test".to_string(),
|
||||
};
|
||||
|
||||
manager.schedule(0.5, false, Box::new(context), |context| {
|
||||
if let Some(test_context) = context.as_any_mut().downcast_mut::<TestContext>() {
|
||||
test_context.value = 42;
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(manager.active_timer_count(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_update() {
|
||||
let mut manager = TimerManager::new();
|
||||
let callback_count = Arc::new(Mutex::new(0));
|
||||
let callback_count_clone = Arc::clone(&callback_count);
|
||||
|
||||
manager.schedule_simple(0.5, false, move |_context| {
|
||||
*callback_count_clone.lock().unwrap() += 1;
|
||||
});
|
||||
|
||||
// 创建一个模拟的时间对象
|
||||
let mut time = Time::new();
|
||||
|
||||
// 第一次更新,时间不够
|
||||
manager.update(&time);
|
||||
assert_eq!(manager.active_timer_count(), 1);
|
||||
assert_eq!(*callback_count.lock().unwrap(), 0);
|
||||
|
||||
// 手动设置delta_time来模拟时间流逝
|
||||
// 注意:这里我们需要用实际的时间更新机制
|
||||
// 在实际使用中,Time对象会自动更新delta_time
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_stop_timer() {
|
||||
let mut manager = TimerManager::new();
|
||||
|
||||
let timer_id = manager.schedule_simple(1.0, true, |_context| {
|
||||
// 回调函数
|
||||
});
|
||||
|
||||
assert_eq!(manager.active_timer_count(), 1);
|
||||
|
||||
assert!(manager.stop_timer(timer_id));
|
||||
assert!(!manager.stop_timer(999)); // 无效索引
|
||||
|
||||
// 定时器被停止但还在列表中
|
||||
assert_eq!(manager.active_timer_count(), 1);
|
||||
|
||||
let time = Time::new();
|
||||
manager.update(&time);
|
||||
|
||||
// 更新后被移除
|
||||
// 注意:需要足够的时间让tick返回true
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_clear() {
|
||||
let mut manager = TimerManager::new();
|
||||
|
||||
manager.schedule_simple(1.0, false, |_context| {});
|
||||
manager.schedule_simple(2.0, true, |_context| {});
|
||||
|
||||
assert_eq!(manager.active_timer_count(), 2);
|
||||
|
||||
manager.clear();
|
||||
assert_eq!(manager.active_timer_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_enable_disable() {
|
||||
let mut manager = TimerManager::new();
|
||||
|
||||
assert!(manager.enabled());
|
||||
|
||||
manager.disable();
|
||||
assert!(!manager.enabled());
|
||||
|
||||
manager.enable();
|
||||
assert!(manager.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_cleanup_completed() {
|
||||
let mut manager = TimerManager::new();
|
||||
|
||||
// 添加一个已完成的定时器
|
||||
let timer_id = manager.schedule_simple(0.1, false, |_context| {});
|
||||
|
||||
// 手动标记为完成
|
||||
if let Some(timer) = manager.get_timer_mut(timer_id) {
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
assert_eq!(manager.active_timer_count(), 1);
|
||||
|
||||
manager.cleanup_completed();
|
||||
assert_eq!(manager.active_timer_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timer_manager_get_timer() {
|
||||
let mut manager = TimerManager::new();
|
||||
|
||||
let timer_id = manager.schedule_simple(1.0, false, |_context| {});
|
||||
|
||||
assert!(manager.get_timer(timer_id).is_some());
|
||||
assert!(manager.get_timer(999).is_none());
|
||||
|
||||
assert!(manager.get_timer_mut(timer_id).is_some());
|
||||
assert!(manager.get_timer_mut(999).is_none());
|
||||
}
|
||||
}
|
||||
802
packages/core-rust/src/utils/updatable.rs
Normal file
802
packages/core-rust/src/utils/updatable.rs
Normal file
@@ -0,0 +1,802 @@
|
||||
use std::any::Any;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/**
|
||||
* 可更新接口
|
||||
* 当添加到组件时,只要组件和实体被启用,就会在每帧调用update方法
|
||||
*/
|
||||
pub trait IUpdatable: Send + Sync {
|
||||
/**
|
||||
* 检查是否启用
|
||||
*/
|
||||
fn is_enabled(&self) -> bool;
|
||||
|
||||
/**
|
||||
* 获取更新顺序
|
||||
*/
|
||||
fn get_update_order(&self) -> i32;
|
||||
|
||||
/**
|
||||
* 更新方法,每帧调用
|
||||
*/
|
||||
fn update(&mut self);
|
||||
|
||||
/**
|
||||
* 转换为Any trait对象(用于类型转换)
|
||||
*/
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/**
|
||||
* 转换为可变的Any trait对象(用于类型转换)
|
||||
*/
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于比较组件更新排序的比较器
|
||||
*/
|
||||
pub struct IUpdatableComparer;
|
||||
|
||||
impl IUpdatableComparer {
|
||||
/**
|
||||
* 比较两个IUpdatable对象的更新顺序
|
||||
*/
|
||||
pub fn compare(a: &dyn IUpdatable, b: &dyn IUpdatable) -> std::cmp::Ordering {
|
||||
a.get_update_order().cmp(&b.get_update_order())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查对象是否实现了IUpdatable接口
|
||||
* 注意:此函数目前无法在运行时动态检查,仅作为编译时类型检查的辅助
|
||||
*/
|
||||
pub fn is_updatable<T: IUpdatable>(_obj: &T) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景组件基类
|
||||
* 附加到场景的组件,用于实现场景级别的功能
|
||||
*/
|
||||
pub struct SceneComponent {
|
||||
/// 场景ID(用于标识所属场景,避免原始指针的线程安全问题)
|
||||
pub scene_id: Option<u32>,
|
||||
/// 更新顺序
|
||||
pub update_order: i32,
|
||||
/// 是否启用
|
||||
enabled: bool,
|
||||
/// 线程安全标记
|
||||
_phantom: PhantomData<*const ()>,
|
||||
}
|
||||
|
||||
impl SceneComponent {
|
||||
/**
|
||||
* 创建新的场景组件
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scene_id: None,
|
||||
update_order: 0,
|
||||
enabled: true,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带有指定更新顺序的场景组件
|
||||
*/
|
||||
pub fn with_update_order(update_order: i32) -> Self {
|
||||
Self {
|
||||
scene_id: None,
|
||||
update_order,
|
||||
enabled: true,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否启用
|
||||
*/
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否启用
|
||||
*/
|
||||
pub fn set_enabled(&mut self, enabled: bool) {
|
||||
if self.enabled != enabled {
|
||||
self.enabled = enabled;
|
||||
if self.enabled {
|
||||
self.on_enabled();
|
||||
} else {
|
||||
self.on_disabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取更新顺序
|
||||
*/
|
||||
pub fn get_update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置更新顺序
|
||||
*/
|
||||
pub fn set_update_order(&mut self, order: i32) {
|
||||
self.update_order = order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所属场景ID
|
||||
*/
|
||||
pub fn get_scene_id(&self) -> Option<u32> {
|
||||
self.scene_id
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置所属场景ID(内部方法,由Scene调用)
|
||||
*/
|
||||
pub fn set_scene_id(&mut self, scene_id: Option<u32>) {
|
||||
self.scene_id = scene_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当组件启用时调用(虚方法,由子类重写)
|
||||
*/
|
||||
pub fn on_enabled(&mut self) {
|
||||
// 默认实现为空,由子类重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 当组件禁用时调用(虚方法,由子类重写)
|
||||
*/
|
||||
pub fn on_disabled(&mut self) {
|
||||
// 默认实现为空,由子类重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 当组件从场景中移除时调用(虚方法,由子类重写)
|
||||
*/
|
||||
pub fn on_removed_from_scene(&mut self) {
|
||||
// 默认实现为空,由子类重写
|
||||
self.scene_id = None;
|
||||
}
|
||||
|
||||
/**
|
||||
* 每帧更新(虚方法,由子类重写)
|
||||
*/
|
||||
pub fn update(&mut self) {
|
||||
// 默认实现为空,由子类重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较组件的更新顺序
|
||||
*/
|
||||
pub fn compare(&self, other: &SceneComponent) -> std::cmp::Ordering {
|
||||
self.update_order.cmp(&other.update_order)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SceneComponent {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// 显式实现Send和Sync,因为PhantomData<*const ()>默认不实现这些traits
|
||||
unsafe impl Send for SceneComponent {}
|
||||
unsafe impl Sync for SceneComponent {}
|
||||
|
||||
impl IUpdatable for SceneComponent {
|
||||
fn is_enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
fn get_update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
SceneComponent::update(self);
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 可更新对象管理器
|
||||
* 负责管理和更新实现了IUpdatable接口的对象
|
||||
*/
|
||||
pub struct UpdatableManager {
|
||||
updatables: Vec<Box<dyn IUpdatable>>,
|
||||
needs_sort: bool,
|
||||
}
|
||||
|
||||
impl UpdatableManager {
|
||||
/**
|
||||
* 创建新的可更新对象管理器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
updatables: Vec::new(),
|
||||
needs_sort: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加可更新对象
|
||||
*/
|
||||
pub fn add_updatable(&mut self, updatable: Box<dyn IUpdatable>) {
|
||||
self.updatables.push(updatable);
|
||||
self.needs_sort = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除可更新对象(通过索引)
|
||||
*/
|
||||
pub fn remove_updatable(&mut self, index: usize) -> Option<Box<dyn IUpdatable>> {
|
||||
if index < self.updatables.len() {
|
||||
Some(self.updatables.remove(index))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可更新对象数量
|
||||
*/
|
||||
pub fn get_count(&self) -> usize {
|
||||
self.updatables.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有可更新对象
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.updatables.clear();
|
||||
self.needs_sort = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据更新顺序排序可更新对象
|
||||
*/
|
||||
pub fn sort_by_update_order(&mut self) {
|
||||
if self.needs_sort {
|
||||
self.updatables.sort_by(|a, b| IUpdatableComparer::compare(a.as_ref(), b.as_ref()));
|
||||
self.needs_sort = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有启用的可更新对象
|
||||
*/
|
||||
pub fn update_all(&mut self) {
|
||||
// 确保按更新顺序排序
|
||||
self.sort_by_update_order();
|
||||
|
||||
// 更新所有启用的对象
|
||||
for updatable in &mut self.updatables {
|
||||
if updatable.is_enabled() {
|
||||
updatable.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的可更新对象数量
|
||||
*/
|
||||
pub fn get_enabled_count(&self) -> usize {
|
||||
self.updatables.iter().filter(|u| u.is_enabled()).count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否需要排序
|
||||
*/
|
||||
pub fn needs_sorting(&self) -> bool {
|
||||
self.needs_sort
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制标记需要排序
|
||||
*/
|
||||
pub fn mark_needs_sort(&mut self) {
|
||||
self.needs_sort = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的可更新对象引用
|
||||
*/
|
||||
pub fn get_updatable(&self, index: usize) -> Option<&dyn IUpdatable> {
|
||||
self.updatables.get(index).map(|u| u.as_ref())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的可更新对象可变引用
|
||||
*/
|
||||
pub fn get_updatable_mut(&mut self, index: usize) -> Option<&mut Box<dyn IUpdatable>> {
|
||||
self.updatables.get_mut(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UpdatableManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景组件管理器
|
||||
* 专门用于管理场景组件
|
||||
*/
|
||||
pub struct SceneComponentManager {
|
||||
components: Vec<Box<dyn SceneComponentTrait>>,
|
||||
needs_sort: bool,
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景组件trait
|
||||
* 结合SceneComponent和IUpdatable的功能
|
||||
*/
|
||||
pub trait SceneComponentTrait: IUpdatable {
|
||||
/**
|
||||
* 获取场景组件的基础数据
|
||||
*/
|
||||
fn get_base(&self) -> &SceneComponent;
|
||||
|
||||
/**
|
||||
* 获取场景组件的可变基础数据
|
||||
*/
|
||||
fn get_base_mut(&mut self) -> &mut SceneComponent;
|
||||
|
||||
/**
|
||||
* 设置所属场景ID
|
||||
*/
|
||||
fn set_scene_id(&mut self, scene_id: Option<u32>);
|
||||
|
||||
/**
|
||||
* 当组件启用时调用
|
||||
*/
|
||||
fn on_enabled(&mut self);
|
||||
|
||||
/**
|
||||
* 当组件禁用时调用
|
||||
*/
|
||||
fn on_disabled(&mut self);
|
||||
|
||||
/**
|
||||
* 当组件从场景中移除时调用
|
||||
*/
|
||||
fn on_removed_from_scene(&mut self);
|
||||
}
|
||||
|
||||
impl SceneComponentManager {
|
||||
/**
|
||||
* 创建新的场景组件管理器
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
components: Vec::new(),
|
||||
needs_sort: false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加场景组件
|
||||
*/
|
||||
pub fn add_component(&mut self, component: Box<dyn SceneComponentTrait>) {
|
||||
self.components.push(component);
|
||||
self.needs_sort = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除场景组件
|
||||
*/
|
||||
pub fn remove_component(&mut self, index: usize) -> Option<Box<dyn SceneComponentTrait>> {
|
||||
if index < self.components.len() {
|
||||
let mut component = self.components.remove(index);
|
||||
component.on_removed_from_scene();
|
||||
Some(component)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件数量
|
||||
*/
|
||||
pub fn get_count(&self) -> usize {
|
||||
self.components.len()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有组件
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
for mut component in self.components.drain(..) {
|
||||
component.on_removed_from_scene();
|
||||
}
|
||||
self.needs_sort = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据更新顺序排序组件
|
||||
*/
|
||||
pub fn sort_by_update_order(&mut self) {
|
||||
if self.needs_sort {
|
||||
self.components.sort_by(|a, b| a.get_update_order().cmp(&b.get_update_order()));
|
||||
self.needs_sort = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有启用的组件
|
||||
*/
|
||||
pub fn update_all(&mut self) {
|
||||
// 确保按更新顺序排序
|
||||
self.sort_by_update_order();
|
||||
|
||||
// 更新所有启用的组件
|
||||
for component in &mut self.components {
|
||||
if component.is_enabled() {
|
||||
component.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置所有组件的场景ID
|
||||
*/
|
||||
pub fn set_scene_id_for_all(&mut self, scene_id: Option<u32>) {
|
||||
for component in &mut self.components {
|
||||
component.set_scene_id(scene_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的组件数量
|
||||
*/
|
||||
pub fn get_enabled_count(&self) -> usize {
|
||||
self.components.iter().filter(|c| c.is_enabled()).count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的组件引用
|
||||
*/
|
||||
pub fn get_component(&self, index: usize) -> Option<&dyn SceneComponentTrait> {
|
||||
self.components.get(index).map(|c| c.as_ref())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的组件可变引用
|
||||
*/
|
||||
pub fn get_component_mut(&mut self, index: usize) -> Option<&mut Box<dyn SceneComponentTrait>> {
|
||||
self.components.get_mut(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SceneComponentManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// 为SceneComponent实现SceneComponentTrait
|
||||
impl SceneComponentTrait for SceneComponent {
|
||||
fn get_base(&self) -> &SceneComponent {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_base_mut(&mut self) -> &mut SceneComponent {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_scene_id(&mut self, scene_id: Option<u32>) {
|
||||
SceneComponent::set_scene_id(self, scene_id);
|
||||
}
|
||||
|
||||
fn on_enabled(&mut self) {
|
||||
SceneComponent::on_enabled(self);
|
||||
}
|
||||
|
||||
fn on_disabled(&mut self) {
|
||||
SceneComponent::on_disabled(self);
|
||||
}
|
||||
|
||||
fn on_removed_from_scene(&mut self) {
|
||||
SceneComponent::on_removed_from_scene(self);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// 测试用的可更新对象
|
||||
struct TestUpdatable {
|
||||
enabled: bool,
|
||||
update_order: i32,
|
||||
update_count: usize,
|
||||
}
|
||||
|
||||
impl TestUpdatable {
|
||||
fn new(update_order: i32) -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
update_order,
|
||||
update_count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IUpdatable for TestUpdatable {
|
||||
fn is_enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
fn get_update_order(&self) -> i32 {
|
||||
self.update_order
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
self.update_count += 1;
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_creation() {
|
||||
let component = SceneComponent::new();
|
||||
assert!(component.enabled());
|
||||
assert_eq!(component.get_update_order(), 0);
|
||||
assert!(component.scene_id.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_with_update_order() {
|
||||
let component = SceneComponent::with_update_order(5);
|
||||
assert!(component.enabled());
|
||||
assert_eq!(component.get_update_order(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_enable_disable() {
|
||||
let mut component = SceneComponent::new();
|
||||
|
||||
assert!(component.enabled());
|
||||
|
||||
component.set_enabled(false);
|
||||
assert!(!component.enabled());
|
||||
|
||||
component.set_enabled(true);
|
||||
assert!(component.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_update_order() {
|
||||
let mut component = SceneComponent::new();
|
||||
|
||||
assert_eq!(component.get_update_order(), 0);
|
||||
|
||||
component.set_update_order(10);
|
||||
assert_eq!(component.get_update_order(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_comparison() {
|
||||
let component1 = SceneComponent::with_update_order(5);
|
||||
let component2 = SceneComponent::with_update_order(10);
|
||||
let component3 = SceneComponent::with_update_order(5);
|
||||
|
||||
assert_eq!(component1.compare(&component2), std::cmp::Ordering::Less);
|
||||
assert_eq!(component2.compare(&component1), std::cmp::Ordering::Greater);
|
||||
assert_eq!(component1.compare(&component3), std::cmp::Ordering::Equal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_updatable_comparer() {
|
||||
let updatable1 = TestUpdatable::new(5);
|
||||
let updatable2 = TestUpdatable::new(10);
|
||||
let updatable3 = TestUpdatable::new(5);
|
||||
|
||||
assert_eq!(IUpdatableComparer::compare(&updatable1, &updatable2), std::cmp::Ordering::Less);
|
||||
assert_eq!(IUpdatableComparer::compare(&updatable2, &updatable1), std::cmp::Ordering::Greater);
|
||||
assert_eq!(IUpdatableComparer::compare(&updatable1, &updatable3), std::cmp::Ordering::Equal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_updatable_manager_creation() {
|
||||
let manager = UpdatableManager::new();
|
||||
assert_eq!(manager.get_count(), 0);
|
||||
assert_eq!(manager.get_enabled_count(), 0);
|
||||
assert!(!manager.needs_sorting());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_updatable_manager_add_remove() {
|
||||
let mut manager = UpdatableManager::new();
|
||||
|
||||
let updatable = TestUpdatable::new(5);
|
||||
manager.add_updatable(Box::new(updatable));
|
||||
|
||||
assert_eq!(manager.get_count(), 1);
|
||||
assert_eq!(manager.get_enabled_count(), 1);
|
||||
assert!(manager.needs_sorting());
|
||||
|
||||
let removed = manager.remove_updatable(0);
|
||||
assert!(removed.is_some());
|
||||
assert_eq!(manager.get_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_updatable_manager_update_all() {
|
||||
let mut manager = UpdatableManager::new();
|
||||
|
||||
let updatable1 = TestUpdatable::new(10);
|
||||
let mut updatable2 = TestUpdatable::new(5);
|
||||
let updatable3 = TestUpdatable::new(15);
|
||||
|
||||
// 禁用第二个对象
|
||||
updatable2.enabled = false;
|
||||
|
||||
manager.add_updatable(Box::new(updatable1));
|
||||
manager.add_updatable(Box::new(updatable2));
|
||||
manager.add_updatable(Box::new(updatable3));
|
||||
|
||||
assert_eq!(manager.get_count(), 3);
|
||||
assert_eq!(manager.get_enabled_count(), 2); // 只有2个启用
|
||||
|
||||
// 更新所有对象
|
||||
manager.update_all();
|
||||
|
||||
// 检查更新次数(通过类型转换)
|
||||
if let Some(updatable) = manager.get_updatable(0) {
|
||||
if let Some(test_updatable) = updatable.as_any().downcast_ref::<TestUpdatable>() {
|
||||
// 由于排序,update_order=5的应该是第一个
|
||||
assert_eq!(test_updatable.update_order, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_updatable_manager_sorting() {
|
||||
let mut manager = UpdatableManager::new();
|
||||
|
||||
manager.add_updatable(Box::new(TestUpdatable::new(10)));
|
||||
manager.add_updatable(Box::new(TestUpdatable::new(5)));
|
||||
manager.add_updatable(Box::new(TestUpdatable::new(15)));
|
||||
|
||||
assert!(manager.needs_sorting());
|
||||
|
||||
manager.sort_by_update_order();
|
||||
|
||||
assert!(!manager.needs_sorting());
|
||||
|
||||
// 检查排序结果
|
||||
assert_eq!(manager.get_updatable(0).unwrap().get_update_order(), 5);
|
||||
assert_eq!(manager.get_updatable(1).unwrap().get_update_order(), 10);
|
||||
assert_eq!(manager.get_updatable(2).unwrap().get_update_order(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_updatable_manager_clear() {
|
||||
let mut manager = UpdatableManager::new();
|
||||
|
||||
manager.add_updatable(Box::new(TestUpdatable::new(5)));
|
||||
manager.add_updatable(Box::new(TestUpdatable::new(10)));
|
||||
|
||||
assert_eq!(manager.get_count(), 2);
|
||||
|
||||
manager.clear();
|
||||
|
||||
assert_eq!(manager.get_count(), 0);
|
||||
assert_eq!(manager.get_enabled_count(), 0);
|
||||
assert!(!manager.needs_sorting());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_manager_creation() {
|
||||
let manager = SceneComponentManager::new();
|
||||
assert_eq!(manager.get_count(), 0);
|
||||
assert_eq!(manager.get_enabled_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_manager_add_remove() {
|
||||
let mut manager = SceneComponentManager::new();
|
||||
|
||||
let component = SceneComponent::new();
|
||||
manager.add_component(Box::new(component));
|
||||
|
||||
assert_eq!(manager.get_count(), 1);
|
||||
assert_eq!(manager.get_enabled_count(), 1);
|
||||
|
||||
let removed = manager.remove_component(0);
|
||||
assert!(removed.is_some());
|
||||
assert_eq!(manager.get_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_manager_update_all() {
|
||||
let mut manager = SceneComponentManager::new();
|
||||
|
||||
let component1 = SceneComponent::with_update_order(10);
|
||||
let mut component2 = SceneComponent::with_update_order(5);
|
||||
let component3 = SceneComponent::with_update_order(15);
|
||||
|
||||
// 禁用第二个组件
|
||||
component2.set_enabled(false);
|
||||
|
||||
manager.add_component(Box::new(component1));
|
||||
manager.add_component(Box::new(component2));
|
||||
manager.add_component(Box::new(component3));
|
||||
|
||||
assert_eq!(manager.get_count(), 3);
|
||||
assert_eq!(manager.get_enabled_count(), 2); // 只有2个启用
|
||||
|
||||
// 更新所有组件
|
||||
manager.update_all();
|
||||
|
||||
// 检查排序结果
|
||||
assert_eq!(manager.get_component(0).unwrap().get_update_order(), 5);
|
||||
assert_eq!(manager.get_component(1).unwrap().get_update_order(), 10);
|
||||
assert_eq!(manager.get_component(2).unwrap().get_update_order(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_manager_clear() {
|
||||
let mut manager = SceneComponentManager::new();
|
||||
|
||||
manager.add_component(Box::new(SceneComponent::new()));
|
||||
manager.add_component(Box::new(SceneComponent::new()));
|
||||
|
||||
assert_eq!(manager.get_count(), 2);
|
||||
|
||||
manager.clear();
|
||||
|
||||
assert_eq!(manager.get_count(), 0);
|
||||
assert_eq!(manager.get_enabled_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_as_updatable() {
|
||||
let mut component = SceneComponent::with_update_order(5);
|
||||
|
||||
assert!(component.enabled());
|
||||
assert_eq!(component.get_update_order(), 5);
|
||||
|
||||
component.update();
|
||||
|
||||
component.set_enabled(false);
|
||||
assert!(!component.enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scene_component_trait_implementation() {
|
||||
let mut component = SceneComponent::with_update_order(10);
|
||||
|
||||
// 测试SceneComponentTrait方法
|
||||
assert_eq!(component.get_base().get_update_order(), 10);
|
||||
|
||||
component.get_base_mut().set_update_order(20);
|
||||
assert_eq!(component.get_update_order(), 20);
|
||||
|
||||
component.set_scene_id(None);
|
||||
assert!(component.get_base().scene_id.is_none());
|
||||
}
|
||||
}
|
||||
110
packages/core-rust/src/wasm/component_wrapper.rs
Normal file
110
packages/core-rust/src/wasm/component_wrapper.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use crate::core::component::{Component, BaseComponent};
|
||||
|
||||
/**
|
||||
* Component WASM绑定包装器
|
||||
* 提供组件管理功能,只暴露用户需要的API
|
||||
*/
|
||||
#[wasm_bindgen]
|
||||
pub struct ComponentWrapper {
|
||||
inner: BaseComponent,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl ComponentWrapper {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut component = BaseComponent::new();
|
||||
component.set_id(id);
|
||||
Self {
|
||||
inner: component,
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.inner.id()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_id(&mut self, id: u32) {
|
||||
self.inner.set_id(id);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.inner.enabled()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_enabled(&mut self, enabled: bool) {
|
||||
self.inner.set_enabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新组件
|
||||
*/
|
||||
pub fn update(&mut self) {
|
||||
self.inner.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件调试信息
|
||||
*/
|
||||
pub fn get_debug_info(&self) -> String {
|
||||
format!(
|
||||
"{{\"id\":{},\"enabled\":{},\"type\":\"Component\"}}",
|
||||
self.inner.id(),
|
||||
self.inner.enabled()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件名称
|
||||
*/
|
||||
pub fn get_name(&self) -> String {
|
||||
"Component".to_string()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查组件是否已销毁
|
||||
*/
|
||||
pub fn is_destroyed(&self) -> bool {
|
||||
false // BaseComponent不支持销毁状态,暂时返回false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ComponentRegistry WASM绑定包装器
|
||||
* 提供组件注册和类型管理功能
|
||||
*/
|
||||
#[wasm_bindgen]
|
||||
pub struct ComponentRegistryWrapper {
|
||||
// 暂时为空,因为ComponentRegistry主要是静态方法
|
||||
_placeholder: u8,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl ComponentRegistryWrapper {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
_placeholder: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已注册的组件数量
|
||||
*/
|
||||
pub fn get_component_count(&self) -> usize {
|
||||
// TODO: 从实际的ComponentRegistry获取
|
||||
0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件类型信息JSON字符串
|
||||
*/
|
||||
pub fn get_component_types_info(&self) -> String {
|
||||
"[]".to_string() // TODO: 返回实际的组件类型信息
|
||||
}
|
||||
}
|
||||
113
packages/core-rust/src/wasm/entity_manager_wrapper.rs
Normal file
113
packages/core-rust/src/wasm/entity_manager_wrapper.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use js_sys::Uint32Array;
|
||||
use crate::core::entity_manager::EntityManager;
|
||||
|
||||
/**
|
||||
* EntityManager WASM绑定包装器
|
||||
* 提供实体管理功能,只暴露用户需要的API
|
||||
*/
|
||||
#[wasm_bindgen]
|
||||
pub struct EntityManagerWrapper {
|
||||
inner: EntityManager,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl EntityManagerWrapper {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: EntityManager::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新实体
|
||||
*/
|
||||
pub fn create_entity(&mut self, name: Option<String>) -> u32 {
|
||||
let entity_name = name.unwrap_or_else(|| "Entity".to_string());
|
||||
self.inner.create_entity(Some(entity_name))
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建实体
|
||||
*/
|
||||
pub fn create_entities_batch(&mut self, count: u32, name_prefix: Option<String>) -> Uint32Array {
|
||||
let prefix = name_prefix.unwrap_or_else(|| "Entity".to_string());
|
||||
let entities = self.inner.create_entities_batch(count, Some(prefix));
|
||||
Uint32Array::from(&entities[..])
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实体
|
||||
*/
|
||||
pub fn destroy_entity(&mut self, entity_id: u32) -> bool {
|
||||
self.inner.destroy_entity(entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体ID
|
||||
*/
|
||||
pub fn get_all_entity_ids(&self) -> Uint32Array {
|
||||
let ids = self.inner.get_all_entity_ids();
|
||||
Uint32Array::from(&ids[..])
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取实体
|
||||
*/
|
||||
pub fn get_entity_by_name(&self, name: &str) -> Option<u32> {
|
||||
self.inner.get_entity_by_name(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据标签获取实体列表
|
||||
*/
|
||||
pub fn get_entities_by_tag(&self, tag: u32) -> Uint32Array {
|
||||
let entities = self.inner.get_entities_by_tag(tag);
|
||||
Uint32Array::from(&entities[..])
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体总数
|
||||
*/
|
||||
pub fn entity_count(&self) -> usize {
|
||||
self.inner.entity_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活状态的实体数量
|
||||
*/
|
||||
pub fn active_entity_count(&self) -> usize {
|
||||
self.inner.active_entity_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有实体
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
// EntityManager doesn't have clear method, would need implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息JSON字符串
|
||||
*/
|
||||
pub fn get_stats(&self) -> String {
|
||||
// 暂时返回简单的统计信息
|
||||
format!("{{\"entity_count\":{},\"active_entity_count\":{}}}",
|
||||
self.inner.entity_count(),
|
||||
self.inner.active_entity_count())
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityManagerWrapper {
|
||||
/**
|
||||
* 内部访问原始EntityManager的方法(不暴露给WASM)
|
||||
*/
|
||||
pub fn inner(&self) -> &EntityManager {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> &mut EntityManager {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
139
packages/core-rust/src/wasm/entity_wrapper.rs
Normal file
139
packages/core-rust/src/wasm/entity_wrapper.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use js_sys::Uint32Array;
|
||||
use crate::core::entity::Entity;
|
||||
|
||||
/**
|
||||
* Entity WASM绑定包装器
|
||||
* 只暴露用户需要操作的核心API
|
||||
*/
|
||||
#[wasm_bindgen]
|
||||
pub struct EntityWrapper {
|
||||
inner: Entity,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl EntityWrapper {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(name: String, id: u32) -> Self {
|
||||
Self {
|
||||
inner: {
|
||||
let mut entity = Entity::new(id);
|
||||
entity.set_name(name);
|
||||
entity
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.inner.id
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn name(&self) -> String {
|
||||
self.inner.name.clone()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn active(&self) -> bool {
|
||||
self.inner.active()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_active(&mut self, value: bool) {
|
||||
self.inner.set_active(value);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.inner.enabled()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_enabled(&mut self, value: bool) {
|
||||
self.inner.set_enabled(value);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn tag(&self) -> u32 {
|
||||
self.inner.tag()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_tag(&mut self, value: u32) {
|
||||
self.inner.set_tag(value);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn update_order(&self) -> i32 {
|
||||
self.inner.update_order()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_update_order(&mut self, value: i32) {
|
||||
self.inner.set_update_order(value);
|
||||
}
|
||||
|
||||
pub fn is_destroyed(&self) -> bool {
|
||||
self.inner.is_destroyed()
|
||||
}
|
||||
|
||||
pub fn get_parent_id(&self) -> Option<u32> {
|
||||
self.inner.get_parent_id()
|
||||
}
|
||||
|
||||
pub fn get_children_ids(&self) -> Uint32Array {
|
||||
let children = self.inner.get_children_ids();
|
||||
Uint32Array::from(&children[..])
|
||||
}
|
||||
|
||||
pub fn child_count(&self) -> usize {
|
||||
self.inner.child_count()
|
||||
}
|
||||
|
||||
pub fn component_count(&self) -> usize {
|
||||
self.inner.component_count()
|
||||
}
|
||||
|
||||
pub fn get_component_mask(&self) -> u64 {
|
||||
self.inner.get_component_mask()
|
||||
}
|
||||
|
||||
pub fn destroy(&mut self) {
|
||||
self.inner.destroy();
|
||||
}
|
||||
|
||||
pub fn update(&mut self) {
|
||||
self.inner.update();
|
||||
}
|
||||
|
||||
pub fn get_debug_info(&self) -> String {
|
||||
self.inner.get_debug_info()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = toString)]
|
||||
pub fn to_string(&self) -> String {
|
||||
self.inner.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityWrapper {
|
||||
/**
|
||||
* 内部访问原始Entity的方法(不暴露给WASM)
|
||||
*/
|
||||
pub fn inner(&self) -> &Entity {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> &mut Entity {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn from_entity(entity: Entity) -> Self {
|
||||
Self { inner: entity }
|
||||
}
|
||||
|
||||
pub fn into_entity(self) -> Entity {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
11
packages/core-rust/src/wasm/mod.rs
Normal file
11
packages/core-rust/src/wasm/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
pub mod entity_wrapper;
|
||||
pub mod entity_manager_wrapper;
|
||||
pub mod query_system_wrapper;
|
||||
pub mod scene_wrapper;
|
||||
pub mod component_wrapper;
|
||||
|
||||
pub use entity_wrapper::EntityWrapper;
|
||||
pub use entity_manager_wrapper::EntityManagerWrapper;
|
||||
pub use query_system_wrapper::QuerySystemWrapper;
|
||||
pub use scene_wrapper::SceneWrapper;
|
||||
pub use component_wrapper::{ComponentWrapper, ComponentRegistryWrapper};
|
||||
104
packages/core-rust/src/wasm/query_system_wrapper.rs
Normal file
104
packages/core-rust/src/wasm/query_system_wrapper.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use js_sys::Uint32Array;
|
||||
use crate::core::query_system::QuerySystem;
|
||||
|
||||
/**
|
||||
* QuerySystem WASM绑定包装器
|
||||
* 提供查询功能,只暴露用户需要的API
|
||||
*/
|
||||
#[wasm_bindgen]
|
||||
pub struct QuerySystemWrapper {
|
||||
inner: QuerySystem,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl QuerySystemWrapper {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: QuerySystem::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实体列表并重建索引
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn set_entities(&mut self, entity_ids: Uint32Array) {
|
||||
// QuerySystem doesn't have set_entities method, simplified for now
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询包含所有指定组件的实体
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn query_all(&self, component_mask: &str) -> String {
|
||||
// Simplified implementation - return empty result
|
||||
let empty_result = crate::core::query_system::QueryResult {
|
||||
entities: Vec::new(),
|
||||
count: 0,
|
||||
execution_time: 0.0,
|
||||
from_cache: false,
|
||||
};
|
||||
serde_json::to_string(&empty_result).unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
|
||||
/**
|
||||
* 按标签查询实体
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn query_by_tag(&self, tag: u32) -> String {
|
||||
// Simplified implementation - return empty result
|
||||
let empty_result = crate::core::query_system::QueryResult {
|
||||
entities: Vec::new(),
|
||||
count: 0,
|
||||
execution_time: 0.0,
|
||||
from_cache: false,
|
||||
};
|
||||
serde_json::to_string(&empty_result).unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称查询实体
|
||||
*/
|
||||
#[allow(unused_variables)]
|
||||
pub fn query_by_name(&mut self, name: &str) -> String {
|
||||
// 这里需要传入EntityManager,但WASM包装器暂时无法直接访问
|
||||
// 返回空结果,实际使用时可能需要重新设计API
|
||||
let empty_result = crate::core::query_system::QueryResult {
|
||||
entities: Vec::new(),
|
||||
count: 0,
|
||||
execution_time: 0.0,
|
||||
from_cache: false,
|
||||
};
|
||||
serde_json::to_string(&empty_result).unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统统计信息
|
||||
*/
|
||||
pub fn get_stats(&self) -> String {
|
||||
let stats = self.inner.get_stats();
|
||||
serde_json::to_string(&stats).unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有查询缓存
|
||||
*/
|
||||
pub fn clear_cache(&mut self) {
|
||||
self.inner.clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
impl QuerySystemWrapper {
|
||||
/**
|
||||
* 内部访问原始QuerySystem的方法(不暴露给WASM)
|
||||
*/
|
||||
pub fn inner(&self) -> &QuerySystem {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> &mut QuerySystem {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
169
packages/core-rust/src/wasm/scene_wrapper.rs
Normal file
169
packages/core-rust/src/wasm/scene_wrapper.rs
Normal file
@@ -0,0 +1,169 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use js_sys::Uint32Array;
|
||||
use crate::core::scene::Scene;
|
||||
|
||||
/**
|
||||
* Scene WASM绑定包装器
|
||||
* 提供场景管理功能,只暴露用户需要的API
|
||||
*/
|
||||
#[wasm_bindgen]
|
||||
pub struct SceneWrapper {
|
||||
inner: Scene,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl SceneWrapper {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(name: String) -> Self {
|
||||
let mut scene = Scene::new();
|
||||
scene.set_name(name);
|
||||
Self {
|
||||
inner: scene,
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 场景属性 ==========
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn name(&self) -> String {
|
||||
self.inner.name().to_string()
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.inner.set_name(name);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn active(&self) -> bool {
|
||||
self.inner.active()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_active(&mut self, active: bool) {
|
||||
self.inner.set_active(active);
|
||||
}
|
||||
|
||||
// ========== 实体管理 ==========
|
||||
|
||||
/**
|
||||
* 创建实体
|
||||
*/
|
||||
pub fn create_entity(&mut self, name: Option<String>) -> u32 {
|
||||
self.inner.create_entity(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建实体
|
||||
*/
|
||||
pub fn create_entities_batch(&mut self, count: u32, name_prefix: Option<String>) -> Uint32Array {
|
||||
let entities = self.inner.create_entities_batch(count, name_prefix);
|
||||
Uint32Array::from(&entities[..])
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实体
|
||||
*/
|
||||
pub fn destroy_entity(&mut self, entity_id: u32) -> bool {
|
||||
self.inner.destroy_entity(entity_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取实体
|
||||
*/
|
||||
pub fn get_entity_by_name(&self, name: &str) -> Option<u32> {
|
||||
self.inner.entity_manager().get_entity_by_name(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据标签获取实体列表
|
||||
*/
|
||||
pub fn get_entities_by_tag(&self, tag: u32) -> Uint32Array {
|
||||
let entities = self.inner.entity_manager().get_entities_by_tag(tag);
|
||||
Uint32Array::from(&entities[..])
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体ID
|
||||
*/
|
||||
pub fn get_all_entity_ids(&self) -> Uint32Array {
|
||||
let ids = self.inner.entity_manager().get_all_entity_ids();
|
||||
Uint32Array::from(&ids[..])
|
||||
}
|
||||
|
||||
// ========== 场景生命周期 ==========
|
||||
|
||||
/**
|
||||
* 初始化场景
|
||||
*/
|
||||
pub fn initialize(&mut self) {
|
||||
self.inner.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新场景
|
||||
*/
|
||||
pub fn update(&mut self, delta_time: f64) {
|
||||
self.inner.update(delta_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空场景
|
||||
*/
|
||||
pub fn clear(&mut self) {
|
||||
self.inner.clear();
|
||||
}
|
||||
|
||||
// ========== 统计信息 ==========
|
||||
|
||||
/**
|
||||
* 获取实体数量
|
||||
*/
|
||||
pub fn entity_count(&self) -> usize {
|
||||
self.inner.entity_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活实体数量
|
||||
*/
|
||||
pub fn active_entity_count(&self) -> usize {
|
||||
self.inner.active_entity_count()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试信息
|
||||
*/
|
||||
pub fn get_debug_info(&self) -> String {
|
||||
self.inner.get_debug_info()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息JSON字符串
|
||||
*/
|
||||
pub fn get_stats(&self) -> String {
|
||||
let stats = self.inner.get_stats();
|
||||
let system_count = self.inner.system_manager().system_count();
|
||||
let enabled_system_count = self.inner.system_manager().enabled_system_count();
|
||||
|
||||
format!(
|
||||
"{{\"total_entities_created\":{},\"total_entities_destroyed\":{},\"total_updates\":{},\"system_count\":{},\"enabled_system_count\":{}}}",
|
||||
stats.total_entities_created,
|
||||
stats.total_entities_destroyed,
|
||||
stats.total_updates,
|
||||
system_count,
|
||||
enabled_system_count
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl SceneWrapper {
|
||||
/**
|
||||
* 内部访问原始Scene的方法(不暴露给WASM)
|
||||
*/
|
||||
pub fn inner(&self) -> &Scene {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> &mut Scene {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user