# 元泰 EG 打包风险与源码整改清单

本文档用于记录当前项目在 Windows/Linux 打包时容易导致运行失败、功能失效或行为不一致的风险点，并给出建议的整改方向。

目标原则：

- 打包优先保证可运行，不追求安装包最小化
- 对动态导入、配置驱动加载、原生扩展依赖保持保守策略
- 对已声明移除的依赖，源码中不应再保留残留引用

---

## 一、已确认的打包风险

### 1. RenderPipeline 配置与插件属于运行时动态加载

相关位置：

- [RenderPipelineFile/config/plugins.yaml](/C:/Users/Tellme/apps/EG/RenderPipelineFile/config/plugins.yaml)
- [core/world.py](/C:/Users/Tellme/apps/EG/core/world.py)
- [build_scripts/build_windows.ps1](/C:/Users/Tellme/apps/EG/build_scripts/build_windows.ps1)

问题说明：

- `RenderPipeline` 会根据配置文件在运行时动态加载 `rpplugins.*`
- 这类插件不是普通静态 import，打包工具无法稳定自动发现
- 已实际出现 `ModuleNotFoundError: No module named 'rpplugins.ao'`

建议：

- 打包脚本显式包含 `rpcore`、`rplibs`、`rpplugins`
- 保留整个 `RenderPipelineFile` 目录
- 显式设置 `RenderPipeline` 的 `base_path` 和 `config_dir`
- 后续新增插件时，同步检查打包白名单

### 2. 文件路径驱动的动态模块加载

相关位置：

- [main.py](/C:/Users/Tellme/apps/EG/main.py)
- [core/script_system.py](/C:/Users/Tellme/apps/EG/core/script_system.py)

问题说明：

- 使用 `importlib.util.spec_from_file_location()` 按文件路径加载模块
- 例如 `demo/video_integration.py`
- 这类模块不会被打包器通过静态分析自动发现

建议：

- 继续将对应目录视为运行时资源并整体复制
- 更理想的方案是逐步改为标准包导入
- 所有此类动态加载点都应登记到打包白名单

### 3. 运行时外部工具依赖目录结构

相关位置：

- [core/world.py](/C:/Users/Tellme/apps/EG/core/world.py)
- [core/tool_manager.py](/C:/Users/Tellme/apps/EG/core/tool_manager.py)

问题说明：

- 程序会在运行时启动 `toolkit/day_time_editor/main.py`
- 还会启动 `toolkit/material_editor/main.py`
- 还会启动 `toolkit/plugin_configurator/main.py`
- 如果这些目录未被完整复制，主程序可能能启动，但局部功能会失效

建议：

- 将整个 `RenderPipelineFile` 视为正式运行时资源
- 子工具路径不应依赖“开发目录结构恰好存在”
- 后续可考虑增加启动前存在性检测和更友好的错误提示

---

## 二、建议项目团队整改的源码问题

### 1. 残留的 PyQt5 引用需要清理

相关位置：

- [ui/icon_manager.py](/C:/Users/Tellme/apps/EG/ui/icon_manager.py)
- [core/selection.py](/C:/Users/Tellme/apps/EG/core/selection.py)
- [scene/scene_manager_convert_tiles_mixin.py](/C:/Users/Tellme/apps/EG/scene/scene_manager_convert_tiles_mixin.py)
- [core/world.py](/C:/Users/Tellme/apps/EG/core/world.py)

问题说明：

- 项目文档中已经说明移除了 `PyQt5/PySide6`
- 但源码仍保留多处 `PyQt5` 引用
- 这会导致打包后功能行为不一致，或在特定分支下运行时报错

建议：

- 用当前实际 UI 栈替代残留 Qt 逻辑
- 删除仅为兼容历史方案保留的无效 Qt 代码
- 对必须保留的兼容逻辑，至少统一做降级处理和提示

### 2. Playwright 浏览器依赖不应处于“隐式依赖”状态

相关位置：

- [core/imgui_webview.py](/C:/Users/Tellme/apps/EG/core/imgui_webview.py)

问题说明：

- 该模块依赖 `playwright.async_api`
- 同时还依赖 Chromium 浏览器安装
- 如果发行版没有附带这些条件，对应功能会直接不可用

建议：

- 明确决定是否正式支持此功能
- 如果正式支持，则纳入依赖与打包流程
- 如果不正式支持，则在发行版中禁用并提示，而不是运行时才报错

### 3. glTF 专用加载依赖缺少明确归档

相关位置：

- [ui/panels/animation_tools.py](/C:/Users/Tellme/apps/EG/ui/panels/animation_tools.py)

问题说明：

- 这里存在运行时 `import gltf`
- 这不是启动必经路径，因此问题可能只在用户点击特定功能时暴露

建议：

- 如果该功能是正式能力，则将 `gltf` 明确加入依赖清单和打包清单
- 如果只是补充路径，应在缺模块时给出明确降级提示

### 4. 平台特定依赖应显式治理

相关位置：

- [core/tool_manager.py](/C:/Users/Tellme/apps/EG/core/tool_manager.py)

问题说明：

- 这里使用 `win32gui`、`win32con`
- 当前代码虽然做了异常兜底，但功能可能 silently fail

建议：

- 明确是否正式依赖 pywin32
- 如果依赖，则加入打包环境
- 如果不依赖，则删除窗口激活逻辑或改为可观测提示

### 5. 硬编码开发机路径需要移除

相关位置：

- [core/world.py](/C:/Users/Tellme/apps/EG/core/world.py)

问题说明：

- 存在 `/home/tiger/...` 这类硬编码本地路径
- 即使当前分支未使用，也不应保留在仓库中

建议：

- 清理所有开发机私有绝对路径
- 改为项目资源路径、配置路径或用户可配置路径

---

## 三、建议长期执行的工程规则

### 1. 建立“动态导入登记表”

所有以下模式都必须登记并同步给打包脚本：

- `importlib.import_module`
- `spec_from_file_location`
- `__import__`
- 配置文件驱动插件加载
- 子进程启动外部 Python 工具

### 2. 建立“运行时资源目录白名单”

以下内容不应依赖打包器自动分析：

- 配置文件
- shader
- 模型
- 字体
- 图标
- demo 脚本
- 插件目录
- 工具目录

### 3. 已移除依赖必须同步清理源码

如果项目文档声明：

- 已移除 `PyQt5`
- 已移除 `PySide6`

则源码中不应继续保留这些引用，避免“文档说没有，代码里还在偷偷依赖”的情况。

### 4. 可选功能必须有明确产品策略

对以下类型的依赖，需要明确归类：

- 浏览器内核
- glTF 专用加载器
- 平台专用 API
- 外部命令行工具

只能二选一：

- 正式支持并纳入安装/打包流程
- 默认禁用并提供明确提示

不应继续保持“开发环境可用、发行版碰运气”的状态。

---

## 四、当前打包策略建议

当前推荐策略：

- 尽量显式包含相关包，不追求安装包最小化
- 尽量整体复制运行时资源目录
- 对启动阶段异常保留日志文件，便于定位下一层问题

建议构建策略：

- 显式包含 `rpcore`、`rplibs`、`rpplugins`
- 尽量显式包含 `core`、`scene`、`project`、`ui`、`gui`、`scripts`、`ssbo_component`、`tools`、`TransformGizmo`
- 自动探测并尽量包含 `plugins`、`gltf`、`playwright` 等可选包
- 整体复制 `RenderPipelineFile`、`Resources`、`config`、`demo` 等目录

---

## 五、建议团队后续执行顺序

1. 先确保打包脚本采用保守策略，优先恢复发行版可运行性
2. 再逐步清理源码中的动态依赖、残留 Qt 引用、硬编码路径
3. 最后再考虑做安装包体积优化，而不是反过来

---

最后更新：2026-03-14
