From bc8b401ef66657a43d882eeec39b816faa655233 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 17 Jun 2026 16:08:58 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=80=BB=E4=BD=93=E6=9E=B6=E6=9E=84=20?= =?UTF-8?q?V14=20=E2=80=94=20FrameDataStore=20=E5=86=85=E5=AD=98=E5=9B=9E?= =?UTF-8?q?=E6=94=BE=E5=8F=8C=E5=B1=82=E5=AD=98=E5=82=A8=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/design/architecture/总体架构设计.md | 49 ++++++++++++++---------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/docs/design/architecture/总体架构设计.md b/docs/design/architecture/总体架构设计.md index a844290..ec5951e 100644 --- a/docs/design/architecture/总体架构设计.md +++ b/docs/design/architecture/总体架构设计.md @@ -1,8 +1,9 @@ # 反无人机仿真系统 — 总体架构设计 -> **版本**:V13 -> **日期**:2026-06-16 -> **状态**:已实现(探测实时链路 + 3D 球冠待实现) +> **版本**:V14 +> **日期**:2026-06-17 +> **状态**:已实现 +> **变更**:V14 新增 DataService 基础数据 CRUD + FrameDataStore 内存回放架构 > **Unity 版本**:22.3.62 > **.NET 版本**:.NET Standard 2.1 > **变更**:V13 探测行为决策固化——5 项规则确认(回退 Undetected / 融合取最早-同刻取精度高 / 不影响 FireSchedule / 盲区仅可视化 / 3D 球冠);新增 14.2.1 三维球冠几何(IsInCoverage)+ 14.7 数据模型变更清单;EquipmentDeployment 表加 4 个 3D 探测字段;DetectionSource 同步扩展 @@ -1257,38 +1258,46 @@ public interface IDefensePlanner ### 7.1 FrameDataStore 实现 -`FrameDataStore` 是**具体类**(非接口),采用内存缓存 + 仿真结束批量落库策略,避免每帧磁盘 IO: +`FrameDataStore` 采用**双层存储**架构:仿真期间内存缓冲 → 仿真结束保留 LiveFrames 副本 + 批量写入 SQLite: ```csharp -/// 帧数据存储 — 内存缓存,仿真结束时批量写入 SQLite public class FrameDataStore { - void BeginRecording(string taskId); // 仿真启动:清空缓冲区 - void RecordFrame(int frameIdx, float timestamp, // 每 Tick:仅写内存缓冲(零字符串分配) - List snapshots); - void Flush(); // 仿真结束:序列化 JSON + 单次事务批量入库 - void Discard(); // 丢弃未落库的缓冲 - List ReadFrames(string taskId, int fromFrame, int toFrame); // 回放读 - void DeleteTaskDb(string taskId); - int CleanupExpired(); // TTL 清理(按 RetentionDays,默认 180 天) - int BufferedFrameCount { get; } // 已缓冲帧数 + // 内存回放:Flush 后保留副本,供回放直接读取(零磁盘 IO) + public List LiveFrames { get; private set; } + + void BeginRecording(string taskId); // 清空 buffer + LiveFrames + void RecordFrame(...); // 仅写内存 List + void Flush(); // 序列化 → LiveFrames 副本 + SQLite 入库 + void Discard(); // 清空 buffer + LiveFrames + List ReadFrames(...); // 从 SQLite 读(历史仿真回放) } ``` -> **关键设计**:`RecordFrame` 在仿真热路径上**只搬强类型标量字段**(位置/血量/云团半径等)到内存 `List`,不做任何 JSON 拼接。JSON 序列化推迟到 `Flush` 一次性完成(详见第十四章性能设计)。 +**LiveFrames 生命周期**: +``` +仿真运行 → Flush() → LiveFrames = 当前仿真数据(同时写 SQLite) + ↓ + 回放:优先取 LiveFrames(内存,快) + ↓ +新仿真开始 → BeginRecording() → LiveFrames.Clear() + ↓ + 如需回放旧仿真 → 回退读 SQLite +``` ### 7.2 录制 -- 仿真启动时 `BeginRecording` 清空内存缓冲区 +- 仿真启动时 `BeginRecording` 清空内存缓冲区和 LiveFrames - 录制帧率 = 仿真 TickRate(每想定可配置,默认 20Hz) - 每 Tick 调用 `RecordFrame()`,仅追加到内存 `List`,零磁盘 IO、零字符串分配 -- 仿真结束 `Flush()`:序列化为 `SimFrameRecord` + 单事务 `InsertAll` 批量写入 `frames/{taskId}.db` -- 仿真事件 `SimEvent` 直接写入主库 `main.db`(每任务 ~30 条,轻量) +- 仿真结束 `Flush()`:序列化为 `SimFrameRecord` → 保留 `LiveFrames` 副本 → 单事务 `InsertAll` 写入 SQLite +- 仿真事件 `SimEvent` 直接写入主库 `main.db` ### 7.3 回放 -- ReplayController 协程驱动 -- 打开 `frames/{taskId}.db`,按 FrameIndex 范围查询 +- `ReplayController.LoadReplay(taskId, frameStore)` 双路径: + - 传入 `frameStore` 且 `LiveFrames` 非空 → 直接使用内存数据(仿真刚结束,零延迟) + - 否则 → 从 `frames/{taskId}.db` 读取(历史仿真) - WHERE FrameIndex BETWEEN a AND b 命中索引,毫秒级 - 回放帧率由前端控制(可与录制不同) - 支持暂停 / 快进 / 后退 / 跳转