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 命中索引,毫秒级
- 回放帧率由前端控制(可与录制不同)
- 支持暂停 / 快进 / 后退 / 跳转