From ca0ce8aa522438d9c672c14420df8ee5a301b2bf Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 18 Jun 2026 15:02:58 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=EF=BC=9ATargetConfig=E2=86=92DroneProfile,?= =?UTF-8?q?=20SimTask=E2=86=92Scenario,=20TaskFullConfig=E2=86=92ScenarioC?= =?UTF-8?q?onfig,=20TaskId=E2=86=92ScenarioId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DroneType 枚举清理:移除 Electric/Piston,重编号 HighSpeed=2 - planner_config.json / defaults.json 同步迁移 - 238 单元测试全部通过 --- CHANGELOG.md | 8 +- data/defaults.json | 12 +- data/planner_config.json | 4 +- docs/design/architecture/总体架构设计.md | 126 +++++++++--------- .../technical/DefensePlanner-技术方案.md | 6 +- docs/design/technical/仿真器实体与事件映射.md | 2 +- .../tasks/实施计划与任务跟踪.md | 4 +- docs/对接文档_Unity前端.md | 20 +-- .../Algorithms/ActiveFuelDamageModel.cs | 8 +- .../Algorithms/ActiveMaterialDamageModel.cs | 4 +- .../Algorithms/AlgorithmTypes.cs | 2 +- .../Algorithms/DamageModelRouter.cs | 4 +- .../Algorithms/DefensePlanner.cs | 10 +- .../Algorithms/IDamageModel.cs | 4 +- .../Algorithms/InertGasDamageModel.cs | 4 +- .../Algorithms/PlannerConfig.cs | 4 +- src/CounterDrone.Core/DatabaseManager.cs | 32 ++--- src/CounterDrone.Core/DefaultData.cs | 8 +- src/CounterDrone.Core/DefaultScenarios.cs | 12 +- .../Models/CloudDispersal.cs | 2 +- src/CounterDrone.Core/Models/CombatScene.cs | 2 +- src/CounterDrone.Core/Models/ControlZone.cs | 2 +- .../{TargetConfig.cs => DroneProfile.cs} | 8 +- src/CounterDrone.Core/Models/Enums.cs | 6 +- .../Models/EquipmentDeployment.cs | 2 +- src/CounterDrone.Core/Models/RoutePlan.cs | 2 +- .../Models/{SimTask.cs => Scenario.cs} | 4 +- .../{TaskFullConfig.cs => ScenarioConfig.cs} | 6 +- .../Models/SimFrameRecord.cs | 2 +- .../Models/SimulationReport.cs | 2 +- src/CounterDrone.Core/Models/Waypoint.cs | 2 +- .../Repository/ControlZoneRepository.cs | 8 +- .../Repository/DroneProfileRepository.cs | 24 ++++ .../EquipmentDeploymentRepository.cs | 12 +- .../Repository/RoutePlanRepository.cs | 8 +- ...askRepository.cs => ScenarioRepository.cs} | 12 +- .../Repository/TargetConfigRepository.cs | 24 ---- .../Repository/WaypointRepository.cs | 12 +- .../Services/IReportService.cs | 2 +- .../Services/IScenarioService.cs | 24 ++-- .../Services/ReportGenerator.cs | 11 +- .../Services/ReportService.cs | 4 +- .../Services/ScenarioService.cs | 102 +++++++------- .../Simulation/DroneEntity.cs | 6 +- .../Simulation/FrameDataStore.cs | 22 +-- .../Simulation/SimulationEngine.cs | 18 +-- .../Scripts/Managers/ManagerVerification.cs | 30 ++--- .../Scripts/Managers/ReplayController.cs | 4 +- .../Assets/Scripts/Managers/ReportManager.cs | 8 +- .../Scripts/Managers/ScenarioManager.cs | 22 +-- .../Scripts/Managers/SimulationBootstrap.cs | 26 ++-- .../Scripts/Managers/SimulationRunner.cs | 14 +- .../Assets/StreamingAssets/defaults.json | 12 +- .../DamageModelTests.cs | 22 +-- .../DatabaseManagerTests.cs | 12 +- .../DefensePlannerTests.cs | 8 +- .../DroneEntityTests.cs | 6 +- .../CounterDrone.Core.Tests/EdgeCaseTests.cs | 54 ++++---- .../FrameDataStoreTests.cs | 4 +- .../FullPipelineTests.cs | 48 +++---- .../PlannerConfigTests.cs | 11 +- .../ReportGeneratorTests.cs | 6 +- .../ReportServiceTests.cs | 18 +-- .../RepositoryEdgeTests.cs | 40 +++--- .../ScenarioServiceTests.cs | 18 +-- .../SimulationEngineTests.cs | 54 ++++---- 66 files changed, 508 insertions(+), 512 deletions(-) rename src/CounterDrone.Core/Models/{TargetConfig.cs => DroneProfile.cs} (75%) rename src/CounterDrone.Core/Models/{SimTask.cs => Scenario.cs} (93%) rename src/CounterDrone.Core/Models/{TaskFullConfig.cs => ScenarioConfig.cs} (87%) create mode 100644 src/CounterDrone.Core/Repository/DroneProfileRepository.cs rename src/CounterDrone.Core/Repository/{SimTaskRepository.cs => ScenarioRepository.cs} (61%) delete mode 100644 src/CounterDrone.Core/Repository/TargetConfigRepository.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index a11b598..841fd58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ ### Added — FrameDataStore LiveFrames 内存回放 - **Flush 后保留 LiveFrames 副本**:仿真刚结束可内存回放,零磁盘 IO -- **ReplayController 双路径**:`LoadReplay(taskId, frameStore)` 优先内存,回退 SQLite +- **ReplayController 双路径**:`LoadReplay(scenarioId, frameStore)` 优先内存,回退 SQLite - **LiveFrames 生命周期**:BeginRecording/Discard 清除 ### Changed — 3机空基编队测试启用 @@ -73,7 +73,7 @@ ### Changed — 消除硬编码 -- **速度从 waypoint.Speed 读取**:`DroneEntity.CruiseSpeed` / `GetDroneSpeedKph` 不再用 `TargetConfig.TypicalSpeed` +- **速度从 waypoint.Speed 读取**:`DroneEntity.CruiseSpeed` / `GetDroneSpeedKph` 不再用 `DroneProfile.TypicalSpeed` - **`AmmunitionSpec` +`Phase2Duration`**(30s):`CloudExpansionModel` 不再写死 `30f` - **`GetArrivalTime` 基于 DetectArc**:从探测点到中点算到达时间(而非航路起点) - **TestData 改为从 seeded 数据库读取**(不再内嵌 JSON 重复 defaults.json) @@ -101,8 +101,8 @@ ### Changed — 数据模型重命名 -- **`GroupId` → `WaveId`**:TargetConfig、EquipmentDeployment、RoutePlan、Waypoint 四表的编组外键重命名为批次外键 -- **RoutePlan 索引重命名**:`(TaskId, GroupId)` → `(TaskId, WaveId)` +- **`GroupId` → `WaveId`**DroneProfile 四表的编组外键重命名为批次外键 +- **RoutePlan 索引重命名**:`(ScenarioId, GroupId)` → `(ScenarioId, WaveId)` - **RoutePlanRepository / WaypointRepository**:`GetByTaskAndGroup` → `GetByTaskAndWave` - **IScenarioService.SaveRoute**:`groupId` 参数 → `waveId` diff --git a/data/defaults.json b/data/defaults.json index 361d99f..331add0 100644 --- a/data/defaults.json +++ b/data/defaults.json @@ -116,17 +116,17 @@ "targets": [ { "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)", - "TargetType": 0, "PowerType": 0, "Wingspan": 1.2, "TypicalSpeed": 60.0, "TypicalAltitude": 300.0 }, + "DroneType": 0, "PowerType": 0, "Wingspan": 1.2, "TypicalSpeed": 60.0, "TypicalAltitude": 300.0 }, { "Id": "electric-scout", "Name": "[Demo] 电推侦察无人机", - "TargetType": 2, "PowerType": 0, "Wingspan": 1.8, "TypicalSpeed": 100.0, "TypicalAltitude": 500.0 }, + "DroneType": 1, "PowerType": 0, "Wingspan": 1.8, "TypicalSpeed": 100.0, "TypicalAltitude": 500.0 }, { "Id": "fixed-piston", "Name": "[Demo] 固定翼活塞(Orlan类)", - "TargetType": 1, "PowerType": 1, "Wingspan": 3.5, "TypicalSpeed": 150.0, "TypicalAltitude": 1000.0 }, + "DroneType": 1, "PowerType": 1, "Wingspan": 3.5, "TypicalSpeed": 150.0, "TypicalAltitude": 1000.0 }, { "Id": "shahed", "Name": "[Demo] 活塞巡飞弹(Shahed类)", - "TargetType": 3, "PowerType": 1, "Wingspan": 2.5, "TypicalSpeed": 200.0, "TypicalAltitude": 500.0 }, + "DroneType": 1, "PowerType": 1, "Wingspan": 2.5, "TypicalSpeed": 200.0, "TypicalAltitude": 500.0 }, { "Id": "tb2", "Name": "[Demo] 中空长航时(TB2类)", - "TargetType": 1, "PowerType": 1, "Wingspan": 12.0, "TypicalSpeed": 220.0, "TypicalAltitude": 5500.0 }, + "DroneType": 1, "PowerType": 1, "Wingspan": 12.0, "TypicalSpeed": 220.0, "TypicalAltitude": 5500.0 }, { "Id": "cruise-missile", "Name": "[Demo] 巡航导弹(喷气式)", - "TargetType": 4, "PowerType": 2, "Wingspan": 1.5, "TypicalSpeed": 200.0, "TypicalAltitude": 2000.0 } + "DroneType": 2, "PowerType": 2, "Wingspan": 1.5, "TypicalSpeed": 200.0, "TypicalAltitude": 2000.0 } ], "detectionEquipment": [ diff --git a/data/planner_config.json b/data/planner_config.json index f2ad3bb..4af0885 100644 --- a/data/planner_config.json +++ b/data/planner_config.json @@ -5,9 +5,7 @@ "TypeCoefficient": { "HighSpeed": 4.0, "FixedWing": 2.0, - "Piston": 2.0, - "Rotor": 1.0, - "Electric": 1.0 + "Rotor": 1.0 }, "AmmoMatch": { "Electric": "InertGas", diff --git a/docs/design/architecture/总体架构设计.md b/docs/design/architecture/总体架构设计.md index ba6503a..707d2de 100644 --- a/docs/design/architecture/总体架构设计.md +++ b/docs/design/architecture/总体架构设计.md @@ -134,7 +134,7 @@ public class SimulationRunner : MonoBehaviour void Start() { // 通过 DI 或工厂获取实例(Core 创建) - _engine = SimulationEngineFactory.Create(taskId); + _engine = SimulationEngineFactory.Create(scenarioId); _recorder = ServiceFactory.CreateRecordService(); } @@ -185,7 +185,7 @@ enum WeatherType { Sunny = 0, Overcast = 1, Fog = 2, Rain = 3, Night = 4 } enum WindDirection { N = 0, NE = 1, E = 2, SE = 3, S = 4, SW = 5, W = 6, NW = 7 } // === 目标 === -enum TargetType { Rotor = 0, FixedWing = 1, Electric = 2, Piston = 3, HighSpeed = 4 } +enum DroneType { Rotor = 0, FixedWing = 1, Electric = 2, Piston = 3, HighSpeed = 4 } enum PowerType { Electric = 0, Piston = 1, Jet = 2 } // === 装备 & 搭载平台 === @@ -213,7 +213,7 @@ enum FormationMode { Single = 0, Formation = 1, Swarm = 2 } // 两者都往统一信息网络送探测信息,planner 基于融合后的探测边界规划。 // 无人机批次(DroneWave):有共同航路的一组无人机(攻击方)。 // 批次关联航路但不独占(多个批次可共享同一条航路)。 -// 配置层 = TargetConfig(含 WaveId) + RoutePlan(TaskId, WaveId) + Waypoints。 +// 配置层 = DroneProfile(含 WaveId) + RoutePlan(ScenarioId, WaveId) + Waypoints。 // === 运行时 === enum EntityType { Drone = 0, Platform = 1, DetectionEquip = 2, Cloud = 3, Munition = 4 } @@ -249,8 +249,8 @@ CounterDroneBackend_Data/ │ └── SimulationReport │ ├── frames/ ← 帧数据分库(6 个月 TTL) -│ ├── {taskId_001}.db ← 单任务 ~161 MB(30min 仿真) -│ └── {taskId_002}.db +│ ├── {scenarioId_001}.db ← 单任务 ~161 MB(30min 仿真) +│ └── {scenarioId_002}.db │ └── models/ ← 模型文件 + 预览图 ``` @@ -263,25 +263,25 @@ CounterDroneBackend_Data/ 主库(main.db)— 永久保留: ModelInfo — 模型元数据 AmmunitionSpec — 弹药基础参数(第三方数据,NEW) - SimTask — 仿真任务主表 + Scenario — 仿真任务主表 CombatScene — 步骤1:作战场景(含24h时间、天气) ControlZone — 步骤1+:管控区域/电子围栏(NEW) - TargetConfig — 步骤2:目标配置(含 WaveId 关联批次) + DroneProfile — 步骤2:目标配置(含 WaveId 关联批次) EquipmentDeployment — 步骤3:装备部署(火力单元含探测+打击,或独立探测节点) CloudDispersal — 步骤4:云团抛撒配置 - RoutePlan — 步骤5:航路规划(1:N SimTask,多批次;批次关联但不独占航路,FK 关联 TargetConfig.WaveId) + RoutePlan — 步骤5:航路规划(1:N Scenario,多批次;批次关联但不独占航路,FK 关联 DroneProfile.WaveId) Waypoint — 航路点 SimulationReport — 仿真报告 SimEvent — 仿真事件(时序图数据源) -任务分库(frames/{taskId}.db)— 6 个月 TTL: +任务分库(frames/{scenarioId}.db)— 6 个月 TTL: SimFrameRecord — 逐帧位置记录(回放用) ``` > **核心作战概念**: > - **火力单元(FireUnit)**:能独立完成搜索、跟踪、瞄准并实施打击的最小作战实体。包含探测(雷达/光电/红外)+ 打击(发射架/火炮)的完整闭环。配置层 = `EquipmentDeployment(LaunchPlatform)`。 > - **独立探测节点(DetectionNode)**:只探测不打击的侦查节点(如前沿警戒雷达)。配置层 = `EquipmentDeployment(Detection)`。 -> - **无人机批次(DroneWave)**:有共同航路的一组无人机(攻击方)。批次关联航路但不独占(多个批次可共享同一条航路)。配置层 = `TargetConfig(WaveId)` + `RoutePlan(TaskId, WaveId)` + `Waypoints`。 +> - **无人机批次(DroneWave)**:有共同航路的一组无人机(攻击方)。批次关联航路但不独占(多个批次可共享同一条航路)。配置层 = `DroneProfile(WaveId)` + `RoutePlan(ScenarioId, WaveId)` + `Waypoints`。 > - 原来的 `Group`(编组)表已移除:无人机编队概念升级为"批次",装备编组概念不再需要(火力单元是独立作战单位)。 ### 4.3 业务表详细设计 @@ -301,7 +301,7 @@ CounterDroneBackend_Data/ > 支持格式:**.fbx / .obj / .stl / .glb / .gltf**,单文件 ≤ 500MB,支持 2K 及以上分辨率贴图。 -#### SimTask — 仿真任务主表 +#### Scenario — 仿真任务主表 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| @@ -318,7 +318,7 @@ CounterDroneBackend_Data/ | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| -| TaskId | TEXT | PK, FK | 1:1 SimTask | +| ScenarioId | TEXT | PK, FK | 1:1 Scenario | | SceneType | INTEGER | | 0城市 1平原 2山区 3海岸 | | TimeOfDay | TEXT | DEFAULT "12:00" | **NEW** 24h 制时间,如 "14:30" | | WeatherType | INTEGER | | 0晴 1阴 2雾 3雨 4夜 | @@ -339,7 +339,7 @@ CounterDroneBackend_Data/ | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | Id | TEXT | PK | GUID | -| TaskId | TEXT | FK | | +| ScenarioId | TEXT | FK | | | Name | TEXT | | 区域名称 | | VerticesJson | TEXT | NOT NULL | 多边形顶点 JSON:`[{"x":0,"y":0,"z":0},...]` | | MinAltitude | REAL | | 区域底高 m | @@ -348,14 +348,14 @@ CounterDroneBackend_Data/ > 管控区域在场景设置(地形+天气)之后配置。无人机进入管控区域 → 触发 ZoneIntruded 事件 → 该无人机任务失败。 -#### TargetConfig — 步骤2:目标配置 +#### DroneProfile — 步骤2:目标配置 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | Id | TEXT | PK | GUID | -| TaskId | TEXT | FK | | +| ScenarioId | TEXT | FK | | | WaveId | TEXT | FK | 关联无人机批次(同一 WaveId 的无人机共享航路) | -| TargetType | INTEGER | | 0旋翼 1固定翼 2电推 3活塞 4高速 | +| DroneType | INTEGER | | 0旋翼 1固定翼 2电推 3活塞 4高速 | | Quantity | INTEGER | DEFAULT 1 | 目标数量 | | PowerType | INTEGER | | 0电推 1活塞 2喷吸气 | | Wingspan | REAL | | m | @@ -377,7 +377,7 @@ CounterDroneBackend_Data/ | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | Id | TEXT | PK | GUID | -| TaskId | TEXT | FK | | +| ScenarioId | TEXT | FK | | | EquipmentRole | INTEGER | | 0=独立探测节点 1=火力单元(发射平台) | | Quantity | INTEGER | DEFAULT 1 | 部署数量 | | WaveId | TEXT | NULLABLE | 可选关联批次(用于 UI 分组,火力单元是独立作战单位,不强依赖批次) | @@ -414,7 +414,7 @@ CounterDroneBackend_Data/ | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| -| TaskId | TEXT | PK, FK | 1:1 SimTask | +| ScenarioId | TEXT | PK, FK | 1:1 Scenario | | AerosolType | INTEGER | | 0吸入式灭火 1爆燃式 2吸入式爆炸 | | DisperseHeight | REAL | DEFAULT 300 | m | | TriggerMode | INTEGER | | 0时间 1区域 2手动 | @@ -440,11 +440,11 @@ CounterDroneBackend_Data/ #### RoutePlan — 步骤5:航路规划 -> **支持多批次**:通过 `TaskId + WaveId` 唯一标识一条航路,一个任务可有多个批次各自独立航路。 +> **支持多批次**:通过 `ScenarioId + WaveId` 唯一标识一条航路,一个任务可有多个批次各自独立航路。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| -| TaskId | TEXT | PK(复合) | | +| ScenarioId | TEXT | PK(复合) | | | WaveId | TEXT | PK(复合) | 关联批次:同一任务不同批次可有独立航路(多个批次可共享同一条航路) | | FormationMode | INTEGER | | 0单机 1编队 2蜂群 | | FormationSpacing | REAL | DEFAULT 50 | m | @@ -455,7 +455,7 @@ CounterDroneBackend_Data/ | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | Id | TEXT | PK | GUID | -| TaskId | TEXT | FK | | +| ScenarioId | TEXT | FK | | | OrderIndex | INTEGER | NOT NULL | 航路顺序 | | PosX | REAL | | 坐标(支持三维点选) | | PosY | REAL | | | @@ -466,21 +466,21 @@ CounterDroneBackend_Data/ #### ~~Group~~ — 编组(已移除) > **概念升级**:原 Group 表的两种类型已分别升级: -> - `DroneFleet`(无人机编队)→ **无人机批次(DroneWave)**:由 `TargetConfig(WaveId)` + `RoutePlan(TaskId, WaveId)` + `Waypoints` 隐式表达。批次关联航路但不独占(多个批次可共享同一条航路)。 +> - `DroneFleet`(无人机编队)→ **无人机批次(DroneWave)**:由 `DroneProfile(WaveId)` + `RoutePlan(ScenarioId, WaveId)` + `Waypoints` 隐式表达。批次关联航路但不独占(多个批次可共享同一条航路)。 > - `EquipmentGroup`(装备编组)→ **不再需要**。火力单元是独立作战的最小单位,不需要上层编组。 > -> 数据层:`Group` 表保留但不再主动使用(向后兼容)。`TargetConfig.WaveId` 语义为"批次 ID"。 +> 数据层:`Group` 表保留但不再主动使用(向后兼容)。`DroneProfile.WaveId` 语义为"批次 ID"。 ### 4.4 运行时表 -> **注意**:SimEvent 和 SimulationReport 存储在主库 main.db;SimFrameRecord 存储在各任务的独立分库 frames/{taskId}.db 中。 +> **注意**:SimEvent 和 SimulationReport 存储在主库 main.db;SimFrameRecord 存储在各任务的独立分库 frames/{scenarioId}.db 中。 #### SimFrameRecord — 逐帧记录 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | Id | INTEGER | PK AUTOINCREMENT | | -| TaskId | TEXT | FK | | +| ScenarioId | TEXT | FK | | | FrameIndex | INTEGER | | 帧序号 | | Timestamp | REAL | | 仿真时间(秒) | | EntityId | TEXT | | | @@ -511,7 +511,7 @@ CounterDroneBackend_Data/ | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | Id | TEXT | PK | GUID | -| TaskId | TEXT | FK | | +| ScenarioId | TEXT | FK | | | OccurredAt | REAL | | 仿真时间(秒) | | EventType | INTEGER | | 事件类型枚举 | | SourceId | TEXT | | 源实体 ID | @@ -691,7 +691,7 @@ Unity 渲染毁伤效果(尾焰异常、姿态失控、坠落) - 当前位置、速度、朝向 - HP(0~1 归一化) - DamageStage(Normal → EngineAnomaly → AttitudeLoss → Destroyed) - - 目标类型 TargetType、动力类型 PowerType + - 目标类型 DroneType、动力类型 PowerType - 存活状态(飞行中/抵达目标/侵入管控区/被摧毁) 运动模型(弧长驱动,统一在 RouteGeometry): @@ -964,12 +964,12 @@ public interface IDamageModel /// 累计暴露时间(s) /// 本次增量暴露时长(s) /// 本次毁伤值(0~1 归一化) - float CalculateDamage(TargetType droneType, PowerType powerType, + float CalculateDamage(DroneType droneType, PowerType powerType, AerosolType aerosolType, float cloudDensity, float exposureTime, float deltaTime); /// 达到 100% 毁伤所需的连续暴露时间 (s),供 planner 估算拦截可行性 - float RequiredExposureSeconds(TargetType droneType, PowerType powerType, AerosolType aerosolType); + float RequiredExposureSeconds(DroneType droneType, PowerType powerType, AerosolType aerosolType); DamageStage GetDamageStage(float accumulatedDamage); } @@ -1257,7 +1257,7 @@ public class FrameDataStore // 内存回放:Flush 后保留副本,供回放直接读取(零磁盘 IO) public List LiveFrames { get; private set; } - void BeginRecording(string taskId); // 清空 buffer + LiveFrames + void BeginRecording(string scenarioId); // 清空 buffer + LiveFrames void RecordFrame(...); // 仅写内存 List void Flush(); // 序列化 → LiveFrames 副本 + SQLite 入库 void Discard(); // 清空 buffer + LiveFrames @@ -1286,9 +1286,9 @@ public class FrameDataStore ### 7.3 回放 -- `ReplayController.LoadReplay(taskId, frameStore)` 双路径: +- `ReplayController.LoadReplay(scenarioId, frameStore)` 双路径: - 传入 `frameStore` 且 `LiveFrames` 非空 → 直接使用内存数据(仿真刚结束,零延迟) - - 否则 → 从 `frames/{taskId}.db` 读取(历史仿真) + - 否则 → 从 `frames/{scenarioId}.db` 读取(历史仿真) - WHERE FrameIndex BETWEEN a AND b 命中索引,毫秒级 - 回放帧率由前端控制(可与录制不同) - 支持暂停 / 快进 / 后退 / 跳转 @@ -1316,12 +1316,12 @@ public class FrameDataStore ### 7.5 TTL 清理策略 ``` -仿真完成 → 生成 frames/{taskId}.db +仿真完成 → 生成 frames/{scenarioId}.db │ ▼ CleanupExpired() 每天执行一次: ├─ 扫描 frames/ 目录 - ├─ 检查 {taskId}.db 的创建时间 + ├─ 检查 {scenarioId}.db 的创建时间 └─ 超过 6 个月 → 删除文件 可选扩展: @@ -1350,7 +1350,7 @@ public class FrameDataStore | 阶段 | 内容 | 数据来源 | |------|------|------| -| **仿真前** | 我方配置(装备类型/数量、火力单元部署、弹药类型/数量、部署位置、管控区域) | SimTask + 5 步配置 | +| **仿真前** | 我方配置(装备类型/数量、火力单元部署、弹药类型/数量、部署位置、管控区域) | Scenario + 5 步配置 | | **仿真中** | 关键事件时序表、各实体轨迹概要、云团演化数据 | SimEvent + SimFrameRecord | | **仿真后** | 拦截成功率、各阶段耗时、毁伤效果评估、对抗结果判定 | SimEvent 汇总统计 | @@ -1385,28 +1385,28 @@ interface IModelService // === 想定管理 === interface IScenarioService { - SimTask CreateTask(string name, string taskNumber); + Scenario CreateTask(string name, string taskNumber); void DeleteTask(string id); - PagedResult SearchTasks(string kw, DateTime? from, DateTime? to, int page, int size); - TaskFullConfig GetTaskDetail(string id); + PagedResult SearchTasks(string kw, DateTime? from, DateTime? to, int page, int size); + ScenarioConfig GetTaskDetail(string id); // 步骤保存 - void SaveScene(string taskId, CombatScene scene); - void SaveControlZones(string taskId, List zones); // NEW - void SaveTarget(string taskId, TargetConfig target); - void SaveDeployment(string taskId, List equips); // 重构 - void SaveCloudDispersal(string taskId, CloudDispersal cloud); - void SaveRoute(string taskId, RoutePlan route, List wps); - void UpdateStep(string taskId, int step); + void SaveScene(string scenarioId, CombatScene scene); + void SaveControlZones(string scenarioId, List zones); // NEW + void SaveTarget(string scenarioId, DroneProfile target); + void SaveDeployment(string scenarioId, List equips); // 重构 + void SaveCloudDispersal(string scenarioId, CloudDispersal cloud); + void SaveRoute(string scenarioId, RoutePlan route, List wps); + void UpdateStep(string scenarioId, int step); // 综合防御推荐(NEW — 多编队版) - DefenseRecommendation GetDefenseRecommendation(string taskId); + DefenseRecommendation GetDefenseRecommendation(string scenarioId); } // === 仿真引擎 === interface ISimulationEngine { - void Initialize(string taskId); + void Initialize(string scenarioId); SimulationFrameResult Tick(float deltaTime); // 返回本帧快照+新事件(复用对象池) void Pause(); void Resume(); @@ -1420,19 +1420,19 @@ interface ISimulationEngine // Stop/完成时调 Flush 批量落库。事件 SimEvent 由引擎直接写入主库。 class FrameDataStore { - void BeginRecording(string taskId); + void BeginRecording(string scenarioId); void RecordFrame(int frameIdx, float timestamp, List entities); void Flush(); // 批量落库 void Discard(); - List ReadFrames(string taskId, int fromFrame, int toFrame); - void DeleteTaskDb(string taskId); + List ReadFrames(string scenarioId, int fromFrame, int toFrame); + void DeleteTaskDb(string scenarioId); int CleanupExpired(); // TTL 清理(RetentionDays,默认 180) } // === 仿真报告 === interface IReportService { - SimulationReport Generate(string taskId); + SimulationReport Generate(string scenarioId); SimulationReport GetReport(string id); void DeleteReport(string id); byte[] ExportReport(string id, string format); // "pdf" | "word" @@ -1449,28 +1449,28 @@ interface IReportService 一个仿真任务可包含**多种类型、多批次**的无人机,每批次有独立的航路: ``` -SimTask "城市防御演习" +Scenario "城市防御演习" ├── CombatScene(共享) ├── ControlZone[](共享) ├── CloudDispersal(共享:云团参数,具体拦截方案由算法确定) │ ├── 批次 A(活塞×3) ← WaveId -│ ├── TargetConfig(WaveId=A,类型=活塞,数量=3) -│ ├── RoutePlan(TaskId + WaveId=A,航路 A:北→南) +│ ├── DroneProfile(WaveId=A,类型=活塞,数量=3) +│ ├── RoutePlan(ScenarioId + WaveId=A,航路 A:北→南) │ └── Waypoint[] │ ├── 批次 B(喷气×2) ← WaveId -│ ├── TargetConfig(WaveId=B,类型=高速,数量=2) -│ ├── RoutePlan(TaskId + WaveId=B,航路 B:西→东) +│ ├── DroneProfile(WaveId=B,类型=高速,数量=2) +│ ├── RoutePlan(ScenarioId + WaveId=B,航路 B:西→东) │ └── Waypoint[] │ └── 批次 C(旋翼×5) ← WaveId - ├── TargetConfig(WaveId=C,类型=旋翼,数量=5) - ├── RoutePlan(TaskId + WaveId=C,航路 C) + ├── DroneProfile(WaveId=C,类型=旋翼,数量=5) + ├── RoutePlan(ScenarioId + WaveId=C,航路 C) └── Waypoint[] ``` -**关键变更**:`RoutePlan` 主键为 `(TaskId, WaveId)` 复合键。`Waypoint` 通过 `(TaskId, WaveId)` 关联航路。 +**关键变更**:`RoutePlan` 主键为 `(ScenarioId, WaveId)` 复合键。`Waypoint` 通过 `(ScenarioId, WaveId)` 关联航路。 ### 推荐算法 @@ -1515,13 +1515,13 @@ engine.SetFireSchedule(merged); | 表 | 变更 | |------|------| -| `RoutePlan` | PK 为 (TaskId, WaveId) 复合键 | -| `TargetConfig` | 不变(已有 WaveId) | -| `Waypoint` | 关联 `(TaskId, WaveId)` 定位航路 | +| `RoutePlan` | PK 为 (ScenarioId, WaveId) 复合键 | +| `DroneProfile` | 不变(已有 WaveId) | +| `Waypoint` | 关联 `(ScenarioId, WaveId)` 定位航路 | `IScenarioService` 的 `SaveRoute` 签名: ```csharp -void SaveRoute(string taskId, string waveId, RoutePlan route, List wps); // waveId 参数 +void SaveRoute(string scenarioId, string waveId, RoutePlan route, List wps); // waveId 参数 ``` ### 报告 diff --git a/docs/design/technical/DefensePlanner-技术方案.md b/docs/design/technical/DefensePlanner-技术方案.md index cb2ee7a..a128641 100644 --- a/docs/design/technical/DefensePlanner-技术方案.md +++ b/docs/design/technical/DefensePlanner-技术方案.md @@ -59,7 +59,7 @@ class FireUnit { ```csharp class DroneWave { string WaveId; // 批次 ID - TargetConfig Target; // 类型、数量、动力、翼展、速度、高度 + DroneProfile Target; // 类型、数量、动力、翼展、速度、高度 List Waypoints; // 航路点 float ArrivalTime; // 预计算:到达防御区域中点的时间 s } @@ -292,7 +292,7 @@ public class DefaultDefensePlanner : IDefensePlanner | 旧接口 | 新接口 | 状态 | |--------|--------|------| | `IDefenseAdvisor.Recommend(ThreatProfile)` | `IDefensePlanner.Plan(fireUnits, threats, env)` | ✅ 已替换 | -| `IDefenseAdvisor.GetDefenseRecommendation(taskId)` | 不再需要 | ✅ 已删除 | +| `IDefenseAdvisor.GetDefenseRecommendation(scenarioId)` | 不再需要 | ✅ 已删除 | | `DefaultDefenseAdvisor.RecommendMultiGroup()` | Planner 原生支持多批次 | ✅ 已删除 | --- @@ -300,7 +300,7 @@ public class DefaultDefensePlanner : IDefensePlanner ## 7. 数据流改造(已实现) ``` -SimulationEngine.Initialize(taskId) +SimulationEngine.Initialize(scenarioId) │ │ // 引擎内部组装 ├── BuildFireUnits(config) → List diff --git a/docs/design/technical/仿真器实体与事件映射.md b/docs/design/technical/仿真器实体与事件映射.md index 830e18a..644bafb 100644 --- a/docs/design/technical/仿真器实体与事件映射.md +++ b/docs/design/technical/仿真器实体与事件映射.md @@ -39,7 +39,7 @@ ## 数据流 ``` -想定配置(EquipmentDeployment + TargetConfig + RoutePlan + CombatScene) +想定配置(EquipmentDeployment + DroneProfile + RoutePlan + CombatScene) │ ▼ SimulationEngine.Initialize() diff --git a/docs/implementation/tasks/实施计划与任务跟踪.md b/docs/implementation/tasks/实施计划与任务跟踪.md index 58c5311..e560463 100644 --- a/docs/implementation/tasks/实施计划与任务跟踪.md +++ b/docs/implementation/tasks/实施计划与任务跟踪.md @@ -181,7 +181,7 @@ Phase 12 ✅ 空基/地基统一规划 + 编队轴 + LaneDivider | 8.1.1 | 探测设备搜索逻辑 | ✅ 事前规划:`DetectionCalculator` 算统一信息网络最早探测点,planner 基于探测边界算到达时间;天气衰减光电;精度影响散布。**实时探测设计完成**(总体架构设计第十四章),待 Phase 10 开发 | | 8.1.2 | 蜂群运动模型 | ⬜ `FormationMode.Swarm` 枚举已定义,需差异化行为(随机扰动、个体差异) | | 8.1.3 | 空基平台 + DefensePlanner | ✅ 五步规划引擎,通道模型,物理间隔错发,路径积分毁伤判定 | -| 8.1.4 | 预置典型目标库 | ⬜ 具体无人机型号 JSON 配置(如 DJI Mavic 3、Shahed-136 等),导入 `TargetConfig` 默认值 | +| 8.1.4 | 预置典型目标库 | ⬜ 具体无人机型号 JSON 配置(如 DJI Mavic 3、Shahed-136 等),导入 `DroneProfile` 默认值 | | 8.1.5 | 毁伤曲线参数校准 | ✅ RequiredExposureSeconds 替代硬编码,密度阈值统一在引擎检查 | | 8.1.6 | Fallback/default 清理 | ✅ 删除所有硬编码默认值和静默 fallback,参数缺失即报错 | @@ -339,7 +339,7 @@ T1(数据层)→ T2(算法层 IsInCoverage) | # | 任务 | 说明 | |---|------|------| | 11.5.1 | FrameDataStore.LiveFrames | Flush 后保留副本;BeginRecording/Discard 清除 | -| 11.5.2 | ReplayController 双路径 | LoadReplay(taskId, frameStore) 优先内存,回退 SQLite | +| 11.5.2 | ReplayController 双路径 | LoadReplay(scenarioId, frameStore) 优先内存,回退 SQLite | ### 11.6 测试启用 diff --git a/docs/对接文档_Unity前端.md b/docs/对接文档_Unity前端.md index 05f74f4..49c5341 100644 --- a/docs/对接文档_Unity前端.md +++ b/docs/对接文档_Unity前端.md @@ -67,12 +67,12 @@ var scenario = GetComponent(); // 方式 A:预设想定(最快) var demos = scenario.Search("Demo", null, null, 1, 100); -var taskId = demos.Items[0].Id; +var scenarioId = demos.Items[0].Id; // 方式 B:自定义 var task = scenario.CreateTask("我的想定", ""); scenario.SaveScene(task.Id, new CombatScene { WindSpeed = 5, WindDirection = (int)WindDirection.E }); -scenario.SaveTarget(task.Id, new TargetConfig { WaveId = "w1", Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500 }); +scenario.SaveTarget(task.Id, new DroneProfile { WaveId = "w1", Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500 }); scenario.SaveRoute(task.Id, "w1", new RoutePlan(), new List { new() { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }, new() { PosX = 10000, PosY = 500, PosZ = 0, Speed = 200 } @@ -88,7 +88,7 @@ scenario.UpdateStep(task.Id, 5); ```csharp var runner = GetComponent(); -runner.LoadAndStart(taskId); +runner.LoadAndStart(scenarioId); runner.Engine.TimeScale = 4f; // 事件 @@ -110,8 +110,8 @@ void Update() { ```csharp var rm = GetComponent(); -var detail = scenario.GetDetail(taskId); -var report = rm.Generate(taskId, detail, runner.Engine.Events.ToList(), +var detail = scenario.GetDetail(scenarioId); +var report = rm.Generate(scenarioId, detail, runner.Engine.Events.ToList(), runner.Engine.Drones[0].Status.ToString(), runner.Engine.SimulationTime); string path = rm.Export(report.Id); ``` @@ -120,7 +120,7 @@ string path = rm.Export(report.Id); ```csharp var replay = GetComponent(); -replay.LoadReplay(taskId); +replay.LoadReplay(scenarioId); for (int i = 0; i < replay.TotalFrames; i++) { var frame = replay.GetFrame(i); // frame.SimulationTime, frame.EntitySnapshots... @@ -144,14 +144,14 @@ mgr.DataService.GetAllEnvironments() / GetAllFormations() / GetAllRoutes() // 想定 CRUD mgr.CreateTask(name, "") / mgr.DeleteTask(id) / mgr.Search(kw, from, to, page, size) mgr.SaveScene / SaveTarget / SaveDeployment / SaveCloud / SaveRoute / UpdateStep -mgr.GetDetail(id) → TaskFullConfig +mgr.GetDetail(id) → ScenarioConfig ``` ### SimulationRunner — 仿真执行 ```csharp var runner = GetComponent(); -runner.LoadAndStart(taskId); +runner.LoadAndStart(scenarioId); runner.Engine.TimeScale = 4f; runner.Engine.State / Drones / Clouds / Munitions / Platforms / DetectionEntities / Events runner.Engine.Tick(dt) → SimulationFrameResult { EntitySnapshots, NewEvents } @@ -163,7 +163,7 @@ runner.Stop(); ```csharp var rm = GetComponent(); -rm.Generate(taskId, detail, events, status, duration) → SimulationReport +rm.Generate(scenarioId, detail, events, status, duration) → SimulationReport rm.Export(reportId) → 文件路径 ``` @@ -171,7 +171,7 @@ rm.Export(reportId) → 文件路径 ```csharp var replay = GetComponent(); -replay.LoadReplay(taskId); +replay.LoadReplay(scenarioId); replay.TotalFrames / replay.GetFrame(index) ``` diff --git a/src/CounterDrone.Core/Algorithms/ActiveFuelDamageModel.cs b/src/CounterDrone.Core/Algorithms/ActiveFuelDamageModel.cs index a7c17a7..6b2621b 100644 --- a/src/CounterDrone.Core/Algorithms/ActiveFuelDamageModel.cs +++ b/src/CounterDrone.Core/Algorithms/ActiveFuelDamageModel.cs @@ -9,20 +9,20 @@ namespace CounterDrone.Core.Algorithms private const float BaseRate = 0.02f; private const float ExpFactor = 0.3f; - public float CalculateDamage(TargetType droneType, PowerType powerType, + public float CalculateDamage(DroneType droneType, PowerType powerType, AerosolType aerosolType, float cloudDensity, float exposureTime, float deltaTime) { if (aerosolType != AerosolType.ActiveFuel) return 0f; var exponential = (float)System.Math.Exp(exposureTime * ExpFactor); var damage = BaseRate * exponential * deltaTime; - var sensitivity = droneType == TargetType.HighSpeed ? 1.5f : 1.0f; + var sensitivity = droneType == DroneType.HighSpeed ? 1.5f : 1.0f; return damage * sensitivity; } - public float RequiredExposureSeconds(TargetType droneType, PowerType powerType, AerosolType aerosolType) + public float RequiredExposureSeconds(DroneType droneType, PowerType powerType, AerosolType aerosolType) { if (aerosolType != AerosolType.ActiveFuel) return float.MaxValue; - var sensitivity = droneType == TargetType.HighSpeed ? 1.5f : 1.0f; + var sensitivity = droneType == DroneType.HighSpeed ? 1.5f : 1.0f; // 数值求解:BaseRate * e^(t*ExpFactor) * sensitivity 的积分 = 1 // ∫[0,T] BaseRate * s * e^(k*t) dt = BaseRate * s * (e^(k*T) - 1) / k = 1 // e^(k*T) = 1 + k / (BaseRate * s) diff --git a/src/CounterDrone.Core/Algorithms/ActiveMaterialDamageModel.cs b/src/CounterDrone.Core/Algorithms/ActiveMaterialDamageModel.cs index 9069165..e2f947c 100644 --- a/src/CounterDrone.Core/Algorithms/ActiveMaterialDamageModel.cs +++ b/src/CounterDrone.Core/Algorithms/ActiveMaterialDamageModel.cs @@ -10,7 +10,7 @@ namespace CounterDrone.Core.Algorithms private const float ResidualRate = 0.05f; private bool _triggered; - public float CalculateDamage(TargetType droneType, PowerType powerType, + public float CalculateDamage(DroneType droneType, PowerType powerType, AerosolType aerosolType, float cloudDensity, float exposureTime, float deltaTime) { if (aerosolType != AerosolType.ActiveMaterial) return 0f; @@ -25,7 +25,7 @@ namespace CounterDrone.Core.Algorithms return ResidualRate * deltaTime; } - public float RequiredExposureSeconds(TargetType droneType, PowerType powerType, AerosolType aerosolType) + public float RequiredExposureSeconds(DroneType droneType, PowerType powerType, AerosolType aerosolType) { if (aerosolType != AerosolType.ActiveMaterial) return float.MaxValue; var sensitivity = powerType == PowerType.Jet ? 1.3f : 1.0f; diff --git a/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs b/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs index 6478ad3..a355956 100644 --- a/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs +++ b/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs @@ -51,7 +51,7 @@ namespace CounterDrone.Core.Algorithms public class DroneWave { public string WaveId { get; set; } = string.Empty; - public TargetConfig Target { get; set; } = new(); + public DroneProfile Target { get; set; } = new(); public RoutePlan Route { get; set; } = new(); public List Waypoints { get; set; } = new(); diff --git a/src/CounterDrone.Core/Algorithms/DamageModelRouter.cs b/src/CounterDrone.Core/Algorithms/DamageModelRouter.cs index bceadf6..c223671 100644 --- a/src/CounterDrone.Core/Algorithms/DamageModelRouter.cs +++ b/src/CounterDrone.Core/Algorithms/DamageModelRouter.cs @@ -9,7 +9,7 @@ namespace CounterDrone.Core.Algorithms private readonly ActiveMaterialDamageModel _activeMaterial = new(); private readonly ActiveFuelDamageModel _activeFuel = new(); - public float CalculateDamage(TargetType droneType, PowerType powerType, + public float CalculateDamage(DroneType droneType, PowerType powerType, AerosolType aerosolType, float cloudDensity, float exposureTime, float deltaTime) { return aerosolType switch @@ -21,7 +21,7 @@ namespace CounterDrone.Core.Algorithms }; } - public float RequiredExposureSeconds(TargetType droneType, PowerType powerType, AerosolType aerosolType) + public float RequiredExposureSeconds(DroneType droneType, PowerType powerType, AerosolType aerosolType) { return aerosolType switch { diff --git a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs index 97e8b70..4f95688 100644 --- a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs @@ -90,9 +90,9 @@ namespace CounterDrone.Core.Algorithms // Step 1: 威胁指数 // ═══════════════════════════════════════════════ - private static float CalcThreatIndex(PlannerConfig config, TargetConfig target) + private static float CalcThreatIndex(PlannerConfig config, DroneProfile target) { - float typeCoef = config.TypeCoefficient.GetValueOrDefault((TargetType)target.TargetType, 1f); + float typeCoef = config.TypeCoefficient.GetValueOrDefault((DroneType)target.DroneType, 1f); float speedCoef = (float)target.TypicalSpeed / 60f; return typeCoef * speedCoef; } @@ -359,7 +359,7 @@ namespace CounterDrone.Core.Algorithms if (!HasInterceptWindow(threat, midArc, expansionTime, deliveryTime)) return null; float avgSpeed = GetDroneSpeedMs(threat); - float neededExposure = _damageModel.RequiredExposureSeconds((TargetType)threat.Target.TargetType, (PowerType)threat.Target.PowerType, ammoType); + float neededExposure = _damageModel.RequiredExposureSeconds((DroneType)threat.Target.DroneType, (PowerType)threat.Target.PowerType, ammoType); float actualExposure = effectiveR * 2f / avgSpeed; float prob = Math.Min(_config.MaxInterceptProbability, actualExposure / neededExposure); @@ -394,7 +394,7 @@ namespace CounterDrone.Core.Algorithms var cloudModel = new CloudExpansionModel(ammo, env); float avgSpeed = GetDroneSpeedMs(threat); float neededExposure = _damageModel.RequiredExposureSeconds( - (TargetType)threat.Target.TargetType, (PowerType)threat.Target.PowerType, (AerosolType)ammo.AerosolType); + (DroneType)threat.Target.DroneType, (PowerType)threat.Target.PowerType, (AerosolType)ammo.AerosolType); float requiredCoverage = neededExposure * avgSpeed; // 间距由配置的重叠比例驱动,公式在 CloudExpansionModel(共享) float spacing = 2f * turbulentRadius * (1f - _config.CloudOverlapRatio); @@ -411,7 +411,7 @@ namespace CounterDrone.Core.Algorithms float actualExposure = actualCoverage / avgSpeed; var aerosolType = (AerosolType)ammo.AerosolType; - float neededExposure = _damageModel.RequiredExposureSeconds((TargetType)threat.Target.TargetType, (PowerType)threat.Target.PowerType, aerosolType); + float neededExposure = _damageModel.RequiredExposureSeconds((DroneType)threat.Target.DroneType, (PowerType)threat.Target.PowerType, aerosolType); return Math.Min(_config.MaxInterceptProbability, actualExposure / neededExposure); } diff --git a/src/CounterDrone.Core/Algorithms/IDamageModel.cs b/src/CounterDrone.Core/Algorithms/IDamageModel.cs index ffd18a6..b27c494 100644 --- a/src/CounterDrone.Core/Algorithms/IDamageModel.cs +++ b/src/CounterDrone.Core/Algorithms/IDamageModel.cs @@ -5,11 +5,11 @@ namespace CounterDrone.Core.Algorithms /// 毁伤模型接口 public interface IDamageModel { - float CalculateDamage(TargetType droneType, PowerType powerType, + float CalculateDamage(DroneType droneType, PowerType powerType, AerosolType aerosolType, float cloudDensity, float exposureTime, float deltaTime); /// 达到 100% 毁伤所需的连续暴露时间 (s) - float RequiredExposureSeconds(TargetType droneType, PowerType powerType, AerosolType aerosolType); + float RequiredExposureSeconds(DroneType droneType, PowerType powerType, AerosolType aerosolType); DamageStage GetDamageStage(float accumulatedDamage); } diff --git a/src/CounterDrone.Core/Algorithms/InertGasDamageModel.cs b/src/CounterDrone.Core/Algorithms/InertGasDamageModel.cs index 86b0b98..054eca5 100644 --- a/src/CounterDrone.Core/Algorithms/InertGasDamageModel.cs +++ b/src/CounterDrone.Core/Algorithms/InertGasDamageModel.cs @@ -8,7 +8,7 @@ namespace CounterDrone.Core.Algorithms { private const float DamageRate = 0.15f; // 每秒毁伤率 - public float CalculateDamage(TargetType droneType, PowerType powerType, + public float CalculateDamage(DroneType droneType, PowerType powerType, AerosolType aerosolType, float cloudDensity, float exposureTime, float deltaTime) { if (aerosolType != AerosolType.InertGas) return 0f; @@ -16,7 +16,7 @@ namespace CounterDrone.Core.Algorithms return DamageRate * sensitivity * deltaTime; } - public float RequiredExposureSeconds(TargetType droneType, PowerType powerType, AerosolType aerosolType) + public float RequiredExposureSeconds(DroneType droneType, PowerType powerType, AerosolType aerosolType) { if (aerosolType != AerosolType.InertGas) return float.MaxValue; var sensitivity = powerType == PowerType.Piston ? 1.5f : 1.0f; diff --git a/src/CounterDrone.Core/Algorithms/PlannerConfig.cs b/src/CounterDrone.Core/Algorithms/PlannerConfig.cs index b0edfcc..33acce8 100644 --- a/src/CounterDrone.Core/Algorithms/PlannerConfig.cs +++ b/src/CounterDrone.Core/Algorithms/PlannerConfig.cs @@ -20,8 +20,8 @@ namespace CounterDrone.Core.Algorithms /// 拦截概率上限(封顶值) public float MaxInterceptProbability { get; set; } - /// 威胁类型系数表(TargetType → 系数) - public Dictionary TypeCoefficient { get; set; } = new(); + /// 威胁类型系数表(DroneType → 系数) + public Dictionary TypeCoefficient { get; set; } = new(); /// 弹药匹配表(PowerType → AerosolType) public Dictionary AmmoMatch { get; set; } = new(); diff --git a/src/CounterDrone.Core/DatabaseManager.cs b/src/CounterDrone.Core/DatabaseManager.cs index f067dc7..bcdffed 100644 --- a/src/CounterDrone.Core/DatabaseManager.cs +++ b/src/CounterDrone.Core/DatabaseManager.cs @@ -31,19 +31,19 @@ namespace CounterDrone.Core } /// 创建/打开任务帧数据库 - public SQLiteConnection OpenFrameDb(string taskId) + public SQLiteConnection OpenFrameDb(string scenarioId) { - var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db"); + var dbPath = Path.Combine(_paths.GetFramesDir(), $"{scenarioId}.db"); var db = new SQLiteConnection(dbPath); db.CreateTable(); - db.CreateIndex("SimFrameRecord", new[] { "TaskId", "FrameIndex" }); + db.CreateIndex("SimFrameRecord", new[] { "ScenarioId", "FrameIndex" }); return db; } /// 删除任务帧数据库文件 - public void DeleteFrameDb(string taskId) + public void DeleteFrameDb(string scenarioId) { - var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db"); + var dbPath = Path.Combine(_paths.GetFramesDir(), $"{scenarioId}.db"); if (File.Exists(dbPath)) File.Delete(dbPath); } @@ -86,8 +86,8 @@ namespace CounterDrone.Core var defaults = DefaultData.Load(_paths); var scenario = new ScenarioService( - new SimTaskRepository(db), new CombatSceneRepository(db), - new ControlZoneRepository(db), new TargetConfigRepository(db), + new ScenarioRepository(db), new CombatSceneRepository(db), + new ControlZoneRepository(db), new DroneProfileRepository(db), new EquipmentDeploymentRepository(db), new CloudDispersalRepository(db), new RoutePlanRepository(db), new WaypointRepository(db)); @@ -100,14 +100,14 @@ namespace CounterDrone.Core { db.CreateTable(); db.CreateTable(); - db.CreateTable(); + db.CreateTable(); db.CreateTable(); db.CreateTable(); - db.CreateTable(); + db.CreateTable(); db.CreateTable(); db.CreateTable(); db.CreateTable(); - db.CreateIndex("RoutePlan", new[] { "TaskId", "WaveId" }, true); + db.CreateIndex("RoutePlan", new[] { "ScenarioId", "WaveId" }, true); db.CreateTable(); db.CreateTable(); db.CreateTable(); @@ -117,12 +117,12 @@ namespace CounterDrone.Core db.CreateTable(); db.CreateTable(); - db.CreateIndex("SimTask", "TaskNumber"); - db.CreateIndex("ControlZone", "TaskId"); - db.CreateIndex("TargetConfig", "TaskId"); - db.CreateIndex("EquipmentDeployment", "TaskId"); - db.CreateIndex("Waypoint", "TaskId"); - db.CreateIndex("SimulationReport", "TaskId"); + db.CreateIndex("Scenario", "TaskNumber"); + db.CreateIndex("ControlZone", "ScenarioId"); + db.CreateIndex("DroneProfile", "ScenarioId"); + db.CreateIndex("EquipmentDeployment", "ScenarioId"); + db.CreateIndex("Waypoint", "ScenarioId"); + db.CreateIndex("SimulationReport", "ScenarioId"); } } } diff --git a/src/CounterDrone.Core/DefaultData.cs b/src/CounterDrone.Core/DefaultData.cs index a07e0dc..10c26b9 100644 --- a/src/CounterDrone.Core/DefaultData.cs +++ b/src/CounterDrone.Core/DefaultData.cs @@ -163,18 +163,18 @@ namespace CounterDrone.Core [SQLite.PrimaryKey] public string Id { get; set; } = ""; public string Name { get; set; } = ""; - public int TargetType { get; set; } + public int DroneType { get; set; } public int PowerType { get; set; } public double Wingspan { get; set; } public double TypicalSpeed { get; set; } public double TypicalAltitude { get; set; } - public TargetConfig ToTargetConfig(string waveId = "default") + public DroneProfile ToDroneProfile(string waveId = "default") { - return new TargetConfig + return new DroneProfile { WaveId = waveId, - TargetType = TargetType, + DroneType = DroneType, PowerType = PowerType, Quantity = 1, Wingspan = Wingspan, diff --git a/src/CounterDrone.Core/DefaultScenarios.cs b/src/CounterDrone.Core/DefaultScenarios.cs index 7a43a7c..af2f0fb 100644 --- a/src/CounterDrone.Core/DefaultScenarios.cs +++ b/src/CounterDrone.Core/DefaultScenarios.cs @@ -37,7 +37,7 @@ namespace CounterDrone.Core { var t = s.CreateTask("[Demo] 无防御-无人机抵达目标", ""); s.SaveScene(t.Id, d.Environments.First(w => w.Id == "sunny-calm").ToCombatScene()); - s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "shahed").ToTargetConfig()); + s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "shahed").ToDroneProfile()); s.SaveRoute(t.Id, "default", d.Formations.First(f => f.Id == "single").ToRoutePlan(), R("3km-h400", 600, d)); s.SaveCloudDispersal(t.Id, new CloudDispersal()); s.SaveDeployment(t.Id, new List()); @@ -48,7 +48,7 @@ namespace CounterDrone.Core { var t = s.CreateTask("[Demo] 管控区域侵入", ""); s.SaveScene(t.Id, d.Environments.First(w => w.Id == "sunny-calm").ToCombatScene()); - s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "electric-scout").ToTargetConfig()); + s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "electric-scout").ToDroneProfile()); s.SaveRoute(t.Id, "default", d.Formations.First(f => f.Id == "single").ToRoutePlan(), R("3km-h300", 300, d)); s.SaveCloudDispersal(t.Id, new CloudDispersal()); s.SaveDeployment(t.Id, new List()); @@ -71,7 +71,7 @@ namespace CounterDrone.Core scene.WindSpeed = 5; scene.WindDirection = (int)WindDirection.W; s.SaveScene(t.Id, scene); - s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "shahed").ToTargetConfig()); + s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "shahed").ToDroneProfile()); s.SaveRoute(t.Id, "default", d.Formations.First(f => f.Id == "single").ToRoutePlan(), new List { new() { PosX = 6600, PosY = 500, PosZ = 0, Speed = 200 }, @@ -89,7 +89,7 @@ namespace CounterDrone.Core { var t = s.CreateTask("[Demo] 喷气式拦截-活性材料", ""); s.SaveScene(t.Id, d.Environments.First(w => w.Id == "sunny-calm").ToCombatScene()); - s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "cruise-missile").ToTargetConfig()); + s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "cruise-missile").ToDroneProfile()); s.SaveRoute(t.Id, "default", d.Formations.First(f => f.Id == "single").ToRoutePlan(), new List { new() { PosX = 18000, PosY = 500, PosZ = 0, Speed = 200 }, @@ -110,7 +110,7 @@ namespace CounterDrone.Core scene.WindSpeed = 5; scene.WindDirection = (int)WindDirection.E; s.SaveScene(t.Id, scene); - s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "shahed").ToTargetConfig()); + s.SaveTarget(t.Id, d.Drones.First(p => p.Id == "shahed").ToDroneProfile()); s.SaveRoute(t.Id, "default", d.Formations.First(f => f.Id == "single").ToRoutePlan(), new List { new() { PosX = 9500, PosY = 500, PosZ = 0, Speed = 200 }, @@ -131,7 +131,7 @@ namespace CounterDrone.Core scene.WindSpeed = 5; scene.WindDirection = (int)WindDirection.E; s.SaveScene(t.Id, scene); - var target = d.Drones.First(p => p.Id == "shahed").ToTargetConfig(); + var target = d.Drones.First(p => p.Id == "shahed").ToDroneProfile(); target.Quantity = 3; s.SaveTarget(t.Id, target); s.SaveRoute(t.Id, "default", d.Formations.First(f => f.Id == "line-3").ToRoutePlan(), diff --git a/src/CounterDrone.Core/Models/CloudDispersal.cs b/src/CounterDrone.Core/Models/CloudDispersal.cs index 3343cfa..9f69819 100644 --- a/src/CounterDrone.Core/Models/CloudDispersal.cs +++ b/src/CounterDrone.Core/Models/CloudDispersal.cs @@ -7,7 +7,7 @@ namespace CounterDrone.Core.Models public class CloudDispersal { [PrimaryKey] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public int AerosolType { get; set; } = (int)Models.AerosolType.InertGas; diff --git a/src/CounterDrone.Core/Models/CombatScene.cs b/src/CounterDrone.Core/Models/CombatScene.cs index dace670..492b8a4 100644 --- a/src/CounterDrone.Core/Models/CombatScene.cs +++ b/src/CounterDrone.Core/Models/CombatScene.cs @@ -7,7 +7,7 @@ namespace CounterDrone.Core.Models public class CombatScene { [PrimaryKey] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public int SceneType { get; set; } = (int)Models.SceneType.Plain; diff --git a/src/CounterDrone.Core/Models/ControlZone.cs b/src/CounterDrone.Core/Models/ControlZone.cs index 7e8dccc..04e872d 100644 --- a/src/CounterDrone.Core/Models/ControlZone.cs +++ b/src/CounterDrone.Core/Models/ControlZone.cs @@ -11,7 +11,7 @@ namespace CounterDrone.Core.Models public string Id { get; set; } = Guid.NewGuid().ToString(); [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; diff --git a/src/CounterDrone.Core/Models/TargetConfig.cs b/src/CounterDrone.Core/Models/DroneProfile.cs similarity index 75% rename from src/CounterDrone.Core/Models/TargetConfig.cs rename to src/CounterDrone.Core/Models/DroneProfile.cs index d27cb77..9e36b15 100644 --- a/src/CounterDrone.Core/Models/TargetConfig.cs +++ b/src/CounterDrone.Core/Models/DroneProfile.cs @@ -4,18 +4,18 @@ using SQLite; namespace CounterDrone.Core.Models { /// 步骤2:目标配置 - [Table("TargetConfig")] - public class TargetConfig + [Table("DroneProfile")] + public class DroneProfile { [PrimaryKey] public string Id { get; set; } = Guid.NewGuid().ToString(); [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public string WaveId { get; set; } = string.Empty; - public int TargetType { get; set; } = (int)Models.TargetType.Rotor; + public int DroneType { get; set; } = (int)Models.DroneType.Rotor; public int Quantity { get; set; } = 1; diff --git a/src/CounterDrone.Core/Models/Enums.cs b/src/CounterDrone.Core/Models/Enums.cs index 9ed80a0..d503fb8 100644 --- a/src/CounterDrone.Core/Models/Enums.cs +++ b/src/CounterDrone.Core/Models/Enums.cs @@ -33,13 +33,11 @@ namespace CounterDrone.Core.Models } // === 目标 === - public enum TargetType + public enum DroneType { Rotor = 0, FixedWing = 1, - Electric = 2, - Piston = 3, - HighSpeed = 4 + HighSpeed = 2 } public enum PowerType diff --git a/src/CounterDrone.Core/Models/EquipmentDeployment.cs b/src/CounterDrone.Core/Models/EquipmentDeployment.cs index bd864ee..cff6c34 100644 --- a/src/CounterDrone.Core/Models/EquipmentDeployment.cs +++ b/src/CounterDrone.Core/Models/EquipmentDeployment.cs @@ -11,7 +11,7 @@ namespace CounterDrone.Core.Models public string Id { get; set; } = Guid.NewGuid().ToString(); [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public int EquipmentRole { get; set; } = (int)Models.EquipmentRole.LaunchPlatform; diff --git a/src/CounterDrone.Core/Models/RoutePlan.cs b/src/CounterDrone.Core/Models/RoutePlan.cs index 10181e7..dba079a 100644 --- a/src/CounterDrone.Core/Models/RoutePlan.cs +++ b/src/CounterDrone.Core/Models/RoutePlan.cs @@ -11,7 +11,7 @@ namespace CounterDrone.Core.Models public string Id { get; set; } = Guid.NewGuid().ToString(); [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; [Indexed] public string WaveId { get; set; } = string.Empty; diff --git a/src/CounterDrone.Core/Models/SimTask.cs b/src/CounterDrone.Core/Models/Scenario.cs similarity index 93% rename from src/CounterDrone.Core/Models/SimTask.cs rename to src/CounterDrone.Core/Models/Scenario.cs index f632828..f6ee4df 100644 --- a/src/CounterDrone.Core/Models/SimTask.cs +++ b/src/CounterDrone.Core/Models/Scenario.cs @@ -4,8 +4,8 @@ using SQLite; namespace CounterDrone.Core.Models { /// 仿真任务主表 - [Table("SimTask")] - public class SimTask + [Table("Scenario")] + public class Scenario { [PrimaryKey] public string Id { get; set; } = Guid.NewGuid().ToString(); diff --git a/src/CounterDrone.Core/Models/TaskFullConfig.cs b/src/CounterDrone.Core/Models/ScenarioConfig.cs similarity index 87% rename from src/CounterDrone.Core/Models/TaskFullConfig.cs rename to src/CounterDrone.Core/Models/ScenarioConfig.cs index 711bf65..35a0d13 100644 --- a/src/CounterDrone.Core/Models/TaskFullConfig.cs +++ b/src/CounterDrone.Core/Models/ScenarioConfig.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; namespace CounterDrone.Core.Models { /// 想定完整配置(聚合 5 步配置) - public class TaskFullConfig + public class ScenarioConfig { - public SimTask Task { get; set; } = new(); + public Scenario Task { get; set; } = new(); public CombatScene Scene { get; set; } = new(); public List ControlZones { get; set; } = new(); - public List Targets { get; set; } = new(); + public List Targets { get; set; } = new(); public List Equipment { get; set; } = new(); public CloudDispersal Cloud { get; set; } = new(); /// 多批次航路(多批次支持) diff --git a/src/CounterDrone.Core/Models/SimFrameRecord.cs b/src/CounterDrone.Core/Models/SimFrameRecord.cs index 6a3998e..f807979 100644 --- a/src/CounterDrone.Core/Models/SimFrameRecord.cs +++ b/src/CounterDrone.Core/Models/SimFrameRecord.cs @@ -10,7 +10,7 @@ namespace CounterDrone.Core.Models public int Id { get; set; } [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public int FrameIndex { get; set; } diff --git a/src/CounterDrone.Core/Models/SimulationReport.cs b/src/CounterDrone.Core/Models/SimulationReport.cs index c2c88f4..d711d9a 100644 --- a/src/CounterDrone.Core/Models/SimulationReport.cs +++ b/src/CounterDrone.Core/Models/SimulationReport.cs @@ -11,7 +11,7 @@ namespace CounterDrone.Core.Models public string Id { get; set; } = Guid.NewGuid().ToString(); [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; public string TaskName { get; set; } = string.Empty; diff --git a/src/CounterDrone.Core/Models/Waypoint.cs b/src/CounterDrone.Core/Models/Waypoint.cs index 845c4dd..0d18036 100644 --- a/src/CounterDrone.Core/Models/Waypoint.cs +++ b/src/CounterDrone.Core/Models/Waypoint.cs @@ -11,7 +11,7 @@ namespace CounterDrone.Core.Models public string Id { get; set; } = Guid.NewGuid().ToString(); [Indexed] - public string TaskId { get; set; } = string.Empty; + public string ScenarioId { get; set; } = string.Empty; /// 关联的批次 ID(多批次支持) public string WaveId { get; set; } = string.Empty; diff --git a/src/CounterDrone.Core/Repository/ControlZoneRepository.cs b/src/CounterDrone.Core/Repository/ControlZoneRepository.cs index ab5dcf3..1e9d230 100644 --- a/src/CounterDrone.Core/Repository/ControlZoneRepository.cs +++ b/src/CounterDrone.Core/Repository/ControlZoneRepository.cs @@ -9,17 +9,17 @@ namespace CounterDrone.Core.Repository { public ControlZoneRepository(SQLiteConnection db) : base(db) { } - public List GetByTaskId(string taskId) + public List GetByScenarioId(string scenarioId) { return Db.Table() - .Where(z => z.TaskId == taskId) + .Where(z => z.ScenarioId == scenarioId) .OrderBy(z => z.OrderIndex) .ToList(); } - public void DeleteByTaskId(string taskId) + public void DeleteByScenarioId(string scenarioId) { - var zones = GetByTaskId(taskId); + var zones = GetByScenarioId(scenarioId); foreach (var z in zones) Db.Delete(z); } diff --git a/src/CounterDrone.Core/Repository/DroneProfileRepository.cs b/src/CounterDrone.Core/Repository/DroneProfileRepository.cs new file mode 100644 index 0000000..e6f2985 --- /dev/null +++ b/src/CounterDrone.Core/Repository/DroneProfileRepository.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq; +using CounterDrone.Core.Models; +using SQLite; + +namespace CounterDrone.Core.Repository +{ + public class DroneProfileRepository : BaseRepository + { + public DroneProfileRepository(SQLiteConnection db) : base(db) { } + + public List GetByScenarioId(string scenarioId) + { + return Db.Table().Where(t => t.ScenarioId == scenarioId).ToList(); + } + + public void DeleteByScenarioId(string scenarioId) + { + var targets = GetByScenarioId(scenarioId); + foreach (var t in targets) + Db.Delete(t); + } + } +} diff --git a/src/CounterDrone.Core/Repository/EquipmentDeploymentRepository.cs b/src/CounterDrone.Core/Repository/EquipmentDeploymentRepository.cs index 7c77b2a..4500f27 100644 --- a/src/CounterDrone.Core/Repository/EquipmentDeploymentRepository.cs +++ b/src/CounterDrone.Core/Repository/EquipmentDeploymentRepository.cs @@ -9,22 +9,22 @@ namespace CounterDrone.Core.Repository { public EquipmentDeploymentRepository(SQLiteConnection db) : base(db) { } - public List GetByTaskId(string taskId) + public List GetByScenarioId(string scenarioId) { - return Db.Table().Where(e => e.TaskId == taskId).ToList(); + return Db.Table().Where(e => e.ScenarioId == scenarioId).ToList(); } /// 按任务和角色查询装备(EquipmentRole: 0=Detection, 1=LaunchPlatform) - public List GetByTaskIdAndRole(string taskId, int equipmentRole) + public List GetByScenarioIdAndRole(string scenarioId, int equipmentRole) { return Db.Table() - .Where(e => e.TaskId == taskId && e.EquipmentRole == equipmentRole) + .Where(e => e.ScenarioId == scenarioId && e.EquipmentRole == equipmentRole) .ToList(); } - public void DeleteByTaskId(string taskId) + public void DeleteByScenarioId(string scenarioId) { - var equips = GetByTaskId(taskId); + var equips = GetByScenarioId(scenarioId); foreach (var e in equips) Db.Delete(e); } diff --git a/src/CounterDrone.Core/Repository/RoutePlanRepository.cs b/src/CounterDrone.Core/Repository/RoutePlanRepository.cs index f2c2bb1..e3af68d 100644 --- a/src/CounterDrone.Core/Repository/RoutePlanRepository.cs +++ b/src/CounterDrone.Core/Repository/RoutePlanRepository.cs @@ -9,15 +9,15 @@ namespace CounterDrone.Core.Repository { public RoutePlanRepository(SQLiteConnection db) : base(db) { } - public List GetByTaskId(string taskId) + public List GetByScenarioId(string scenarioId) { - return Db.Table().Where(r => r.TaskId == taskId).ToList(); + return Db.Table().Where(r => r.ScenarioId == scenarioId).ToList(); } - public RoutePlan GetByTaskAndWave(string taskId, string waveId) + public RoutePlan GetByTaskAndWave(string scenarioId, string waveId) { return Db.Table() - .FirstOrDefault(r => r.TaskId == taskId && r.WaveId == waveId); + .FirstOrDefault(r => r.ScenarioId == scenarioId && r.WaveId == waveId); } } } diff --git a/src/CounterDrone.Core/Repository/SimTaskRepository.cs b/src/CounterDrone.Core/Repository/ScenarioRepository.cs similarity index 61% rename from src/CounterDrone.Core/Repository/SimTaskRepository.cs rename to src/CounterDrone.Core/Repository/ScenarioRepository.cs index 65822cd..aa1c0af 100644 --- a/src/CounterDrone.Core/Repository/SimTaskRepository.cs +++ b/src/CounterDrone.Core/Repository/ScenarioRepository.cs @@ -5,18 +5,18 @@ using SQLite; namespace CounterDrone.Core.Repository { - public class SimTaskRepository : BaseRepository + public class ScenarioRepository : BaseRepository { - public SimTaskRepository(SQLiteConnection db) : base(db) { } + public ScenarioRepository(SQLiteConnection db) : base(db) { } - public SimTask GetByTaskNumber(string taskNumber) + public Scenario GetByTaskNumber(string taskNumber) { - return Db.Table().FirstOrDefault(t => t.TaskNumber == taskNumber); + return Db.Table().FirstOrDefault(t => t.TaskNumber == taskNumber); } - public List Search(string keyword, string? dateFrom, string? dateTo, int offset, int limit, out int totalCount) + public List Search(string keyword, string? dateFrom, string? dateTo, int offset, int limit, out int totalCount) { - var query = Db.Table().AsQueryable(); + var query = Db.Table().AsQueryable(); if (!string.IsNullOrWhiteSpace(keyword)) query = query.Where(t => t.Name.Contains(keyword) || t.TaskNumber.Contains(keyword)); diff --git a/src/CounterDrone.Core/Repository/TargetConfigRepository.cs b/src/CounterDrone.Core/Repository/TargetConfigRepository.cs deleted file mode 100644 index 0129183..0000000 --- a/src/CounterDrone.Core/Repository/TargetConfigRepository.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using CounterDrone.Core.Models; -using SQLite; - -namespace CounterDrone.Core.Repository -{ - public class TargetConfigRepository : BaseRepository - { - public TargetConfigRepository(SQLiteConnection db) : base(db) { } - - public List GetByTaskId(string taskId) - { - return Db.Table().Where(t => t.TaskId == taskId).ToList(); - } - - public void DeleteByTaskId(string taskId) - { - var targets = GetByTaskId(taskId); - foreach (var t in targets) - Db.Delete(t); - } - } -} diff --git a/src/CounterDrone.Core/Repository/WaypointRepository.cs b/src/CounterDrone.Core/Repository/WaypointRepository.cs index cba1bdd..aa7713b 100644 --- a/src/CounterDrone.Core/Repository/WaypointRepository.cs +++ b/src/CounterDrone.Core/Repository/WaypointRepository.cs @@ -9,25 +9,25 @@ namespace CounterDrone.Core.Repository { public WaypointRepository(SQLiteConnection db) : base(db) { } - public List GetByTaskId(string taskId) + public List GetByScenarioId(string scenarioId) { return Db.Table() - .Where(w => w.TaskId == taskId) + .Where(w => w.ScenarioId == scenarioId) .OrderBy(w => w.OrderIndex) .ToList(); } - public List GetByTaskAndWave(string taskId, string waveId) + public List GetByTaskAndWave(string scenarioId, string waveId) { return Db.Table() - .Where(w => w.TaskId == taskId && w.WaveId == waveId) + .Where(w => w.ScenarioId == scenarioId && w.WaveId == waveId) .OrderBy(w => w.OrderIndex) .ToList(); } - public void DeleteByTaskId(string taskId) + public void DeleteByScenarioId(string scenarioId) { - var wps = GetByTaskId(taskId); + var wps = GetByScenarioId(scenarioId); foreach (var w in wps) Db.Delete(w); } diff --git a/src/CounterDrone.Core/Services/IReportService.cs b/src/CounterDrone.Core/Services/IReportService.cs index 1d92d9e..ca6da5d 100644 --- a/src/CounterDrone.Core/Services/IReportService.cs +++ b/src/CounterDrone.Core/Services/IReportService.cs @@ -7,7 +7,7 @@ namespace CounterDrone.Core.Services /// 报告服务 public interface IReportService { - SimulationReport Generate(string taskId, TaskFullConfig config, + SimulationReport Generate(string scenarioId, ScenarioConfig config, List events, string finalDroneStatus, float duration); SimulationReport GetReport(string id); void DeleteReport(string id); diff --git a/src/CounterDrone.Core/Services/IScenarioService.cs b/src/CounterDrone.Core/Services/IScenarioService.cs index 325256d..4f5f8eb 100644 --- a/src/CounterDrone.Core/Services/IScenarioService.cs +++ b/src/CounterDrone.Core/Services/IScenarioService.cs @@ -6,25 +6,25 @@ namespace CounterDrone.Core.Services /// 想定管理服务 public interface IScenarioService { - SimTask CreateTask(string name, string taskNumber); + Scenario CreateTask(string name, string taskNumber); void DeleteTask(string id); - PagedResult SearchTasks(string keyword, string? dateFrom, string? dateTo, int page, int pageSize); - TaskFullConfig? GetTaskDetail(string id); + PagedResult SearchTasks(string keyword, string? dateFrom, string? dateTo, int page, int pageSize); + ScenarioConfig? GetTaskDetail(string id); - void SaveScene(string taskId, CombatScene scene); - void SaveControlZones(string taskId, List zones); - void SaveTarget(string taskId, TargetConfig target); - void SaveDeployment(string taskId, List equips); + void SaveScene(string scenarioId, CombatScene scene); + void SaveControlZones(string scenarioId, List zones); + void SaveTarget(string scenarioId, DroneProfile target); + void SaveDeployment(string scenarioId, List equips); /// 添加单个探测设备(独立于 SaveDeployment,不覆盖火力单元) - void AddDetection(string taskId, EquipmentDeployment detection); + void AddDetection(string scenarioId, EquipmentDeployment detection); /// 删除探测设备 void DeleteDetection(string detectionId); /// 获取任务的所有探测设备(EquipmentRole.Detection) - List GetDetections(string taskId); + List GetDetections(string scenarioId); - void SaveCloudDispersal(string taskId, CloudDispersal cloud); - void SaveRoute(string taskId, string waveId, RoutePlan route, List waypoints); - void UpdateStep(string taskId, int step); + void SaveCloudDispersal(string scenarioId, CloudDispersal cloud); + void SaveRoute(string scenarioId, string waveId, RoutePlan route, List waypoints); + void UpdateStep(string scenarioId, int step); } } diff --git a/src/CounterDrone.Core/Services/ReportGenerator.cs b/src/CounterDrone.Core/Services/ReportGenerator.cs index 45b1d5d..00851c7 100644 --- a/src/CounterDrone.Core/Services/ReportGenerator.cs +++ b/src/CounterDrone.Core/Services/ReportGenerator.cs @@ -9,7 +9,7 @@ namespace CounterDrone.Core.Services { public class ReportGenerator { - public string Generate(TaskFullConfig config, List events, + public string Generate(ScenarioConfig config, List events, Simulation.DroneStatus finalDroneStatus, float simulationDuration) { var sb = new StringBuilder(); @@ -70,7 +70,7 @@ namespace CounterDrone.Core.Services sb.AppendLine(); sb.AppendLine($"| 参数 | 值 |"); sb.AppendLine($"|------|-----|"); - sb.AppendLine($"| 类型 | {TranslateTarget((TargetType)(target?.TargetType ?? 0))} |"); + sb.AppendLine($"| 类型 | {TranslateTarget((DroneType)(target?.DroneType ?? 0))} |"); sb.AppendLine($"| 动力 | {TranslatePower((PowerType)(target?.PowerType ?? 0))} |"); sb.AppendLine($"| 数量 | {totalDrones} 架 |"); sb.AppendLine($"| 翼展 | {target?.Wingspan ?? 0:F1} m |"); @@ -282,11 +282,10 @@ namespace CounterDrone.Core.Services TriggerMode.Manual => "手动触发", _ => t.ToString(), }; - private static string TranslateTarget(TargetType t) => t switch + private static string TranslateTarget(DroneType t) => t switch { - TargetType.Rotor => "旋翼", TargetType.FixedWing => "固定翼", - TargetType.Electric => "电推", TargetType.Piston => "活塞", - TargetType.HighSpeed => "高速目标", _ => t.ToString(), + DroneType.Rotor => "旋翼", DroneType.FixedWing => "固定翼", + DroneType.HighSpeed => "高速目标", _ => t.ToString(), }; private static string TranslatePower(PowerType p) => p switch diff --git a/src/CounterDrone.Core/Services/ReportService.cs b/src/CounterDrone.Core/Services/ReportService.cs index ecc0400..08aee3a 100644 --- a/src/CounterDrone.Core/Services/ReportService.cs +++ b/src/CounterDrone.Core/Services/ReportService.cs @@ -20,7 +20,7 @@ namespace CounterDrone.Core.Services _paths = paths; } - public SimulationReport Generate(string taskId, TaskFullConfig config, + public SimulationReport Generate(string scenarioId, ScenarioConfig config, List events, string finalDroneStatus, float duration) { var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed); @@ -31,7 +31,7 @@ namespace CounterDrone.Core.Services var report = new SimulationReport { - TaskId = taskId, + ScenarioId = scenarioId, TaskName = config.Task.Name, TaskNumber = config.Task.TaskNumber, CompletedAt = DateTime.UtcNow.ToString("o"), diff --git a/src/CounterDrone.Core/Services/ScenarioService.cs b/src/CounterDrone.Core/Services/ScenarioService.cs index d8e8fd9..4b63198 100644 --- a/src/CounterDrone.Core/Services/ScenarioService.cs +++ b/src/CounterDrone.Core/Services/ScenarioService.cs @@ -9,20 +9,20 @@ namespace CounterDrone.Core.Services { public class ScenarioService : IScenarioService { - private readonly SimTaskRepository _taskRepo; + private readonly ScenarioRepository _taskRepo; private readonly CombatSceneRepository _sceneRepo; private readonly ControlZoneRepository _zoneRepo; - private readonly TargetConfigRepository _targetRepo; + private readonly DroneProfileRepository _targetRepo; private readonly EquipmentDeploymentRepository _equipRepo; private readonly CloudDispersalRepository _cloudRepo; private readonly RoutePlanRepository _routeRepo; private readonly WaypointRepository _waypointRepo; public ScenarioService( - SimTaskRepository taskRepo, + ScenarioRepository taskRepo, CombatSceneRepository sceneRepo, ControlZoneRepository zoneRepo, - TargetConfigRepository targetRepo, + DroneProfileRepository targetRepo, EquipmentDeploymentRepository equipRepo, CloudDispersalRepository cloudRepo, RoutePlanRepository routeRepo, @@ -40,7 +40,7 @@ namespace CounterDrone.Core.Services // ========== Task CRUD ========== - public SimTask CreateTask(string name, string taskNumber) + public Scenario CreateTask(string name, string taskNumber) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("任务名称不能为空"); @@ -52,7 +52,7 @@ namespace CounterDrone.Core.Services if (existing != null) throw new ArgumentException($"任务编号 {taskNumber} 已存在"); - var task = new SimTask + var task = new Scenario { Name = name, TaskNumber = taskNumber, @@ -69,7 +69,7 @@ namespace CounterDrone.Core.Services _taskRepo.Delete(id); } - public PagedResult SearchTasks(string keyword, string? dateFrom, string? dateTo, int page, int pageSize) + public PagedResult SearchTasks(string keyword, string? dateFrom, string? dateTo, int page, int pageSize) { if (page < 1) page = 1; if (pageSize < 1) pageSize = 10; @@ -77,7 +77,7 @@ namespace CounterDrone.Core.Services var items = _taskRepo.Search(keyword, dateFrom, dateTo, offset, pageSize, out var total); - return new PagedResult + return new PagedResult { Items = items, TotalCount = total, @@ -86,21 +86,21 @@ namespace CounterDrone.Core.Services }; } - public TaskFullConfig? GetTaskDetail(string id) + public ScenarioConfig? GetTaskDetail(string id) { var task = _taskRepo.GetById(id); if (task == null) return null; - return new TaskFullConfig + return new ScenarioConfig { Task = task, - Scene = _sceneRepo.GetById(id) ?? new CombatScene { TaskId = id }, - ControlZones = _zoneRepo.GetByTaskId(id), - Targets = _targetRepo.GetByTaskId(id), - Equipment = _equipRepo.GetByTaskId(id), - Cloud = _cloudRepo.GetById(id) ?? new CloudDispersal { TaskId = id }, - Routes = _routeRepo.GetByTaskId(id), - WaypointGroups = _waypointRepo.GetByTaskId(id) + Scene = _sceneRepo.GetById(id) ?? new CombatScene { ScenarioId = id }, + ControlZones = _zoneRepo.GetByScenarioId(id), + Targets = _targetRepo.GetByScenarioId(id), + Equipment = _equipRepo.GetByScenarioId(id), + Cloud = _cloudRepo.GetById(id) ?? new CloudDispersal { ScenarioId = id }, + Routes = _routeRepo.GetByScenarioId(id), + WaypointGroups = _waypointRepo.GetByScenarioId(id) .GroupBy(w => w.WaveId) .ToDictionary(g => g.Key, g => g.OrderBy(w => w.OrderIndex).ToList()), }; @@ -108,32 +108,32 @@ namespace CounterDrone.Core.Services // ========== Step Save ========== - public void SaveScene(string taskId, CombatScene scene) + public void SaveScene(string scenarioId, CombatScene scene) { - scene.TaskId = taskId; - var existing = _sceneRepo.GetById(taskId); + scene.ScenarioId = scenarioId; + var existing = _sceneRepo.GetById(scenarioId); if (existing != null) _sceneRepo.Update(scene); else _sceneRepo.Insert(scene); - TouchTask(taskId); + TouchTask(scenarioId); } - public void SaveControlZones(string taskId, List zones) + public void SaveControlZones(string scenarioId, List zones) { - _zoneRepo.DeleteByTaskId(taskId); + _zoneRepo.DeleteByScenarioId(scenarioId); for (int i = 0; i < zones.Count; i++) { - zones[i].TaskId = taskId; + zones[i].ScenarioId = scenarioId; zones[i].OrderIndex = i; } _zoneRepo.InsertAll(zones); - TouchTask(taskId); + TouchTask(scenarioId); } - public void SaveTarget(string taskId, TargetConfig target) + public void SaveTarget(string scenarioId, DroneProfile target) { - target.TaskId = taskId; + target.ScenarioId = scenarioId; if (string.IsNullOrEmpty(target.Id)) target.Id = Guid.NewGuid().ToString(); @@ -142,30 +142,30 @@ namespace CounterDrone.Core.Services _targetRepo.Update(target); else _targetRepo.Insert(target); - TouchTask(taskId); + TouchTask(scenarioId); } - public void SaveDeployment(string taskId, List equips) + public void SaveDeployment(string scenarioId, List equips) { - _equipRepo.DeleteByTaskId(taskId); + _equipRepo.DeleteByScenarioId(scenarioId); foreach (var e in equips) { - e.TaskId = taskId; + e.ScenarioId = scenarioId; if (string.IsNullOrEmpty(e.Id)) e.Id = Guid.NewGuid().ToString(); } _equipRepo.InsertAll(equips); - TouchTask(taskId); + TouchTask(scenarioId); } - public void AddDetection(string taskId, EquipmentDeployment detection) + public void AddDetection(string scenarioId, EquipmentDeployment detection) { - detection.TaskId = taskId; + detection.ScenarioId = scenarioId; detection.EquipmentRole = (int)EquipmentRole.Detection; if (string.IsNullOrEmpty(detection.Id)) detection.Id = Guid.NewGuid().ToString(); _equipRepo.Insert(detection); - TouchTask(taskId); + TouchTask(scenarioId); } public void DeleteDetection(string detectionId) @@ -173,27 +173,27 @@ namespace CounterDrone.Core.Services _equipRepo.Delete(detectionId); } - public List GetDetections(string taskId) + public List GetDetections(string scenarioId) { - return _equipRepo.GetByTaskIdAndRole(taskId, (int)EquipmentRole.Detection); + return _equipRepo.GetByScenarioIdAndRole(scenarioId, (int)EquipmentRole.Detection); } - public void SaveCloudDispersal(string taskId, CloudDispersal cloud) + public void SaveCloudDispersal(string scenarioId, CloudDispersal cloud) { - cloud.TaskId = taskId; - var existing = _cloudRepo.GetById(taskId); + cloud.ScenarioId = scenarioId; + var existing = _cloudRepo.GetById(scenarioId); if (existing != null) _cloudRepo.Update(cloud); else _cloudRepo.Insert(cloud); - TouchTask(taskId); + TouchTask(scenarioId); } - public void SaveRoute(string taskId, string waveId, RoutePlan route, List waypoints) + public void SaveRoute(string scenarioId, string waveId, RoutePlan route, List waypoints) { - route.TaskId = taskId; + route.ScenarioId = scenarioId; route.WaveId = waveId; - var existing = _routeRepo.GetByTaskAndWave(taskId, waveId); + var existing = _routeRepo.GetByTaskAndWave(scenarioId, waveId); if (existing != null) { route.Id = existing.Id; @@ -203,23 +203,23 @@ namespace CounterDrone.Core.Services _routeRepo.Insert(route); // 删除该批次的旧航路点,插入新的 - var oldWps = _waypointRepo.GetByTaskAndWave(taskId, waveId); + var oldWps = _waypointRepo.GetByTaskAndWave(scenarioId, waveId); foreach (var w in oldWps) _waypointRepo.Delete(w.Id); for (int i = 0; i < waypoints.Count; i++) { - waypoints[i].TaskId = taskId; + waypoints[i].ScenarioId = scenarioId; waypoints[i].WaveId = waveId; waypoints[i].OrderIndex = i; if (string.IsNullOrEmpty(waypoints[i].Id)) waypoints[i].Id = Guid.NewGuid().ToString(); } _waypointRepo.InsertAll(waypoints); - TouchTask(taskId); + TouchTask(scenarioId); } - public void UpdateStep(string taskId, int step) + public void UpdateStep(string scenarioId, int step) { - var task = _taskRepo.GetById(taskId); + var task = _taskRepo.GetById(scenarioId); if (task == null) return; if (step < 1) step = 1; @@ -231,9 +231,9 @@ namespace CounterDrone.Core.Services // ========== Helpers ========== - private void TouchTask(string taskId) + private void TouchTask(string scenarioId) { - var task = _taskRepo.GetById(taskId); + var task = _taskRepo.GetById(scenarioId); if (task != null) { task.UpdatedAt = DateTime.UtcNow.ToString("o"); diff --git a/src/CounterDrone.Core/Simulation/DroneEntity.cs b/src/CounterDrone.Core/Simulation/DroneEntity.cs index 30d44ff..cfee381 100644 --- a/src/CounterDrone.Core/Simulation/DroneEntity.cs +++ b/src/CounterDrone.Core/Simulation/DroneEntity.cs @@ -9,7 +9,7 @@ namespace CounterDrone.Core.Simulation { public string Id { get; } public string WaveId { get; } - public TargetType TargetType { get; } + public DroneType DroneType { get; } public PowerType PowerType { get; } public float Wingspan { get; } public float CruiseSpeed { get; } @@ -38,13 +38,13 @@ namespace CounterDrone.Core.Simulation /// 查找弧长 s 所在段:最大的 i 使 _cumArc[i] >= s。 private readonly float[] _cumArc; - public DroneEntity(string id, string waveId, TargetConfig config, List route, + public DroneEntity(string id, string waveId, DroneProfile config, List route, int formationIndex, float lateralSpacing, int longitudinalIndex, float longitudinalSpacing, FormationMode mode, int lateralAxis = 2, int longitudinalAxis = 0) { Id = id; WaveId = waveId; - TargetType = (TargetType)config.TargetType; + DroneType = (DroneType)config.DroneType; PowerType = (PowerType)config.PowerType; Wingspan = (float)config.Wingspan; float spd = (float)route[0].Speed; diff --git a/src/CounterDrone.Core/Simulation/FrameDataStore.cs b/src/CounterDrone.Core/Simulation/FrameDataStore.cs index 4aa3357..5cb93e5 100644 --- a/src/CounterDrone.Core/Simulation/FrameDataStore.cs +++ b/src/CounterDrone.Core/Simulation/FrameDataStore.cs @@ -11,7 +11,7 @@ namespace CounterDrone.Core.Simulation { private readonly IPathProvider _paths; private readonly List _buffer = new(); - private string _taskId = string.Empty; + private string _scenarioId = string.Empty; public int RetentionDays { get; set; } = 180; public int BufferedFrameCount { get; private set; } /// 仿真刚结束时保留内存快照,支持快速回放。Flush 后自动清空。 @@ -23,9 +23,9 @@ namespace CounterDrone.Core.Simulation } /// 开始录制。清空缓冲区,准备接收帧数据。 - public void BeginRecording(string taskId) + public void BeginRecording(string scenarioId) { - _taskId = taskId; + _scenarioId = scenarioId; _buffer.Clear(); LiveFrames.Clear(); BufferedFrameCount = 0; @@ -65,7 +65,7 @@ namespace CounterDrone.Core.Simulation var s = fr.Snapshot; var record = new SimFrameRecord { - TaskId = _taskId, FrameIndex = fr.FrameIndex, Timestamp = fr.Timestamp, + ScenarioId = _scenarioId, FrameIndex = fr.FrameIndex, Timestamp = fr.Timestamp, EntityId = s.EntityId, EntityType = (int)s.EntityType, PosX = s.PosX, PosY = s.PosY, PosZ = s.PosZ, StateData = s.EntityType switch @@ -84,30 +84,30 @@ namespace CounterDrone.Core.Simulation _buffer.Clear(); - var dbPath = Path.Combine(_paths.GetFramesDir(), $"{_taskId}.db"); + var dbPath = Path.Combine(_paths.GetFramesDir(), $"{_scenarioId}.db"); Directory.CreateDirectory(_paths.GetFramesDir()); using var db = new SQLiteConnection(dbPath); db.CreateTable(); - db.CreateIndex("SimFrameRecord", new[] { "TaskId", "FrameIndex" }); + db.CreateIndex("SimFrameRecord", new[] { "ScenarioId", "FrameIndex" }); db.InsertAll(records); } public void Discard() { _buffer.Clear(); LiveFrames.Clear(); BufferedFrameCount = 0; } - public List ReadFrames(string taskId, int fromFrame, int toFrame) + public List ReadFrames(string scenarioId, int fromFrame, int toFrame) { - var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db"); + var dbPath = Path.Combine(_paths.GetFramesDir(), $"{scenarioId}.db"); if (!File.Exists(dbPath)) return new List(); using var db = new SQLiteConnection(dbPath); return db.Table() - .Where(f => f.TaskId == taskId && f.FrameIndex >= fromFrame && f.FrameIndex <= toFrame) + .Where(f => f.ScenarioId == scenarioId && f.FrameIndex >= fromFrame && f.FrameIndex <= toFrame) .OrderBy(f => f.FrameIndex) .ToList(); } - public void DeleteFrameDb(string taskId) + public void DeleteFrameDb(string scenarioId) { - var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db"); + var dbPath = Path.Combine(_paths.GetFramesDir(), $"{scenarioId}.db"); if (File.Exists(dbPath)) File.Delete(dbPath); } diff --git a/src/CounterDrone.Core/Simulation/SimulationEngine.cs b/src/CounterDrone.Core/Simulation/SimulationEngine.cs index 196667f..cdedb86 100644 --- a/src/CounterDrone.Core/Simulation/SimulationEngine.cs +++ b/src/CounterDrone.Core/Simulation/SimulationEngine.cs @@ -54,7 +54,7 @@ namespace CounterDrone.Core.Simulation private bool _anyThreatDetected; private float _detectionTime; private readonly List _allEvents = new(); - private string _taskId = string.Empty; + private string _scenarioId = string.Empty; private readonly IDefensePlanner _planner; private int _entityCounter; @@ -82,10 +82,10 @@ namespace CounterDrone.Core.Simulation _nextFireIndex = 0; } - public void Initialize(string taskId) + public void Initialize(string scenarioId) { - _taskId = taskId; - var config = _scenarioService.GetTaskDetail(taskId); + _scenarioId = scenarioId; + var config = _scenarioService.GetTaskDetail(scenarioId); if (config == null) throw new InvalidOperationException("Task not found"); _scene = config.Scene; @@ -179,7 +179,7 @@ namespace CounterDrone.Core.Simulation } if (RecordFrames) - _frameStore.BeginRecording(_taskId); + _frameStore.BeginRecording(_scenarioId); _anyThreatDetected = false; State = SimulationState.Running; } @@ -363,7 +363,7 @@ namespace CounterDrone.Core.Simulation { float exposureIncrement = inCloudDistance / (drone.CruiseSpeed / 3.6f); drone.ExposureTime += exposureIncrement; - var dmg = _damageModel.CalculateDamage(drone.TargetType, drone.PowerType, cloud.AerosolType, cloud.Dispersion.CoreDensity, drone.ExposureTime, exposureIncrement); + var dmg = _damageModel.CalculateDamage(drone.DroneType, drone.PowerType, cloud.AerosolType, cloud.Dispersion.CoreDensity, drone.ExposureTime, exposureIncrement); drone.ApplyDamage(dmg); if (drone.Status == DroneStatus.Destroyed) { @@ -427,7 +427,7 @@ namespace CounterDrone.Core.Simulation public void Resume() { if (State == SimulationState.Paused) State = SimulationState.Running; } public void Stop() { State = SimulationState.Stopped; _frameStore.Flush(); } - private static List BuildFireUnits(TaskFullConfig config) + private static List BuildFireUnits(ScenarioConfig config) { var units = new List(); foreach (var eq in config.Equipment.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform)) @@ -464,7 +464,7 @@ namespace CounterDrone.Core.Simulation /// 构建统一信息网络的探测源列表。 /// 独立探测设备(EquipmentRole.Detection)+ 火力单元自带探测能力。 - private static List BuildDetectionSources(TaskFullConfig config) + private static List BuildDetectionSources(ScenarioConfig config) { var sources = new List(); foreach (var eq in config.Equipment) @@ -493,7 +493,7 @@ namespace CounterDrone.Core.Simulation return sources; } - private static List BuildDroneWaves(TaskFullConfig config) + private static List BuildDroneWaves(ScenarioConfig config) { var groups = new List(); foreach (var t in config.Targets) diff --git a/src/Unity/Assets/Scripts/Managers/ManagerVerification.cs b/src/Unity/Assets/Scripts/Managers/ManagerVerification.cs index 981beff..6d0e5b6 100644 --- a/src/Unity/Assets/Scripts/Managers/ManagerVerification.cs +++ b/src/Unity/Assets/Scripts/Managers/ManagerVerification.cs @@ -29,34 +29,34 @@ namespace CounterDrone.Unity var scenarioMgr = gameObject.AddComponent(); scenarioMgr.Awake(); var task = scenarioMgr.CreateTask("Verification", ""); - var taskId = task.Id; - Debug.Log($"2. ScenarioManager OK. Task: {taskId}"); + var scenarioId = task.Id; + Debug.Log($"2. ScenarioManager OK. Task: {scenarioId}"); - scenarioMgr.SaveScene(taskId, new CombatScene { WindSpeed = 0 }); - scenarioMgr.SaveTarget(taskId, new TargetConfig + scenarioMgr.SaveScene(scenarioId, new CombatScene { WindSpeed = 0 }); + scenarioMgr.SaveTarget(scenarioId, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston, + DroneType = (int)DroneType.FixedWing, PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500, }); - scenarioMgr.SaveRoute(taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + scenarioMgr.SaveRoute(scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }, new Waypoint { PosX = 10000, PosY = 500, PosZ = 0, Speed = 200 }, }); - scenarioMgr.UpdateStep(taskId, 3); + scenarioMgr.UpdateStep(scenarioId, 3); Debug.Log("3. Scenario configured"); var db = new DatabaseManager(paths).OpenMainDb(); SqliteConnectionTracker.Track(db); var ammoCatalog = db.Table().ToList(); - var detail = scenarioMgr.GetDetail(taskId); + var detail = scenarioMgr.GetDetail(scenarioId); var droneGroup = new DroneWave { WaveId = "default", - Target = detail.Targets[0], + DroneType = detail.Targets[0].DroneType, Route = detail.Routes[0], Waypoints = detail.WaypointGroups["default"], }; @@ -72,7 +72,7 @@ namespace CounterDrone.Unity AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel }, }); var result = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths)).Plan(fireUnits, new List { droneGroup }, detail.Scene, new List()); - scenarioMgr.SaveCloud(taskId, new CloudDispersal + scenarioMgr.SaveCloud(scenarioId, new CloudDispersal { PositionX = (droneGroup.Waypoints[0].PosX + droneGroup.Waypoints[^1].PosX) / 2, PositionY = (droneGroup.Waypoints[0].PosY + droneGroup.Waypoints[^1].PosY) / 2, @@ -92,7 +92,7 @@ namespace CounterDrone.Unity CruiseSpeed = u.CruiseSpeed > 0 ? u.CruiseSpeed : null, ReleaseAltitude = u.ReleaseAltitude > 0 ? u.ReleaseAltitude : null, }); - scenarioMgr.SaveDeployment(taskId, equips); + scenarioMgr.SaveDeployment(scenarioId, equips); SqliteConnectionTracker.Untrack(db); db.Dispose(); var plan = result.Best; @@ -100,7 +100,7 @@ namespace CounterDrone.Unity var runner = gameObject.AddComponent(); runner.Awake(); - runner.LoadAndStart(taskId); + runner.LoadAndStart(scenarioId); runner.Engine.TimeScale = 10f; float endTime = Time.realtimeSinceStartup + 60f; @@ -116,16 +116,16 @@ namespace CounterDrone.Unity var reportMgr = gameObject.AddComponent(); reportMgr.Awake(); - detail = scenarioMgr.GetDetail(taskId); + detail = scenarioMgr.GetDetail(scenarioId); var simEvents = new List(runner.Engine.Events); var status = runner.Engine.Drones.Count > 0 ? runner.Engine.Drones[0].Status.ToString() : "Unknown"; - var report = reportMgr.Generate(taskId, detail, simEvents, status, runner.Engine.SimulationTime); + var report = reportMgr.Generate(scenarioId, detail, simEvents, status, runner.Engine.SimulationTime); var path = reportMgr.Export(report.Id); Debug.Log($"6. Report OK. Exported: {path}"); var replay = gameObject.AddComponent(); replay.Awake(); - replay.LoadReplay(taskId); + replay.LoadReplay(scenarioId); Debug.Log($"7. Replay OK. {replay.TotalFrames} frames, {replay.CurrentFrames.Count} records"); Debug.Log("===== ALL MANAGERS VERIFIED ====="); diff --git a/src/Unity/Assets/Scripts/Managers/ReplayController.cs b/src/Unity/Assets/Scripts/Managers/ReplayController.cs index 3a6f96f..706a38d 100644 --- a/src/Unity/Assets/Scripts/Managers/ReplayController.cs +++ b/src/Unity/Assets/Scripts/Managers/ReplayController.cs @@ -24,7 +24,7 @@ namespace CounterDrone.Unity } /// 加载回放数据:优先使用传入的 frameStore 内存数据(仿真刚结束),否则读数据库 - public void LoadReplay(string taskId, FrameDataStore frameStore = null) + public void LoadReplay(string scenarioId, FrameDataStore frameStore = null) { if (frameStore != null && frameStore.LiveFrames.Count > 0) { @@ -34,7 +34,7 @@ namespace CounterDrone.Unity else { _frameStore ??= new FrameDataStore(_paths); - CurrentFrames = _frameStore.ReadFrames(taskId, 0, int.MaxValue); + CurrentFrames = _frameStore.ReadFrames(scenarioId, 0, int.MaxValue); } TotalFrames = CurrentFrames.Count > 0 diff --git a/src/Unity/Assets/Scripts/Managers/ReportManager.cs b/src/Unity/Assets/Scripts/Managers/ReportManager.cs index 03bb0d3..be98209 100644 --- a/src/Unity/Assets/Scripts/Managers/ReportManager.cs +++ b/src/Unity/Assets/Scripts/Managers/ReportManager.cs @@ -25,17 +25,17 @@ namespace CounterDrone.Unity void OnDisable() { SqliteConnectionTracker.Untrack(_db); _db?.Dispose(); _db = null; } - public SimulationReport Generate(string taskId, TaskFullConfig cfg, List events, string status, float duration) - => _service.Generate(taskId, cfg, events, status, duration); + public SimulationReport Generate(string scenarioId, ScenarioConfig cfg, List events, string status, float duration) + => _service.Generate(scenarioId, cfg, events, status, duration); public SimulationReport Get(string id) => _service.GetReport(id); public void Delete(string id) => _service.DeleteReport(id); public PagedResult Search(string kw, string from, string to, int page, int size) => _service.SearchReports(kw, from, to, page, size); - public string Export(string reportId) + public string Export(string reportId, string? outputDir = null) { - var dir = System.IO.Path.Combine(_paths.GetDataRoot(), "reports"); + var dir = outputDir ?? System.IO.Path.Combine(_paths.GetDataRoot(), "reports"); return _service.ExportToFile(reportId, dir); } diff --git a/src/Unity/Assets/Scripts/Managers/ScenarioManager.cs b/src/Unity/Assets/Scripts/Managers/ScenarioManager.cs index 6ca5a89..3d946b9 100644 --- a/src/Unity/Assets/Scripts/Managers/ScenarioManager.cs +++ b/src/Unity/Assets/Scripts/Managers/ScenarioManager.cs @@ -26,8 +26,8 @@ namespace CounterDrone.Unity _db = new DatabaseManager(paths).OpenMainDb(); SqliteConnectionTracker.Track(_db); _service = new ScenarioService( - new SimTaskRepository(_db), new CombatSceneRepository(_db), - new ControlZoneRepository(_db), new TargetConfigRepository(_db), + new ScenarioRepository(_db), new CombatSceneRepository(_db), + new ControlZoneRepository(_db), new DroneProfileRepository(_db), new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db), new RoutePlanRepository(_db), new WaypointRepository(_db)); _dataService = new DataService( @@ -45,18 +45,18 @@ namespace CounterDrone.Unity void OnDisable() { SqliteConnectionTracker.Untrack(_db); _db?.Dispose(); _db = null; } - public SimTask CreateTask(string name, string number) => _service.CreateTask(name, number); + public Scenario CreateTask(string name, string number) => _service.CreateTask(name, number); public void DeleteTask(string id) => _service.DeleteTask(id); - public TaskFullConfig GetDetail(string id) => _service.GetTaskDetail(id); - public PagedResult Search(string kw, string from, string to, int page, int size) + public ScenarioConfig GetDetail(string id) => _service.GetTaskDetail(id); + public PagedResult Search(string kw, string from, string to, int page, int size) => _service.SearchTasks(kw, from, to, page, size); - public void SaveScene(string taskId, CombatScene s) => _service.SaveScene(taskId, s); - public void SaveTarget(string taskId, TargetConfig t) => _service.SaveTarget(taskId, t); - public void SaveDeployment(string taskId, List e) => _service.SaveDeployment(taskId, e); - public void SaveCloud(string taskId, CloudDispersal c) => _service.SaveCloudDispersal(taskId, c); - public void SaveRoute(string taskId, string waveId, RoutePlan r, List w) => _service.SaveRoute(taskId, waveId, r, w); - public void UpdateStep(string taskId, int step) => _service.UpdateStep(taskId, step); + public void SaveScene(string scenarioId, CombatScene s) => _service.SaveScene(scenarioId, s); + public void SaveTarget(string scenarioId, DroneProfile t) => _service.SaveTarget(scenarioId, t); + public void SaveDeployment(string scenarioId, List e) => _service.SaveDeployment(scenarioId, e); + public void SaveCloud(string scenarioId, CloudDispersal c) => _service.SaveCloudDispersal(scenarioId, c); + public void SaveRoute(string scenarioId, string waveId, RoutePlan r, List w) => _service.SaveRoute(scenarioId, waveId, r, w); + public void UpdateStep(string scenarioId, int step) => _service.UpdateStep(scenarioId, step); [ContextMenu("Verify")] void Verify() diff --git a/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs b/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs index a11db69..e8a8495 100644 --- a/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs +++ b/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs @@ -42,12 +42,12 @@ namespace CounterDrone.Unity new RouteTemplateRepository(db)); var scenario = new ScenarioService( - new SimTaskRepository(db), new CombatSceneRepository(db), - new ControlZoneRepository(db), new TargetConfigRepository(db), + new ScenarioRepository(db), new CombatSceneRepository(db), + new ControlZoneRepository(db), new DroneProfileRepository(db), new EquipmentDeploymentRepository(db), new CloudDispersalRepository(db), new RoutePlanRepository(db), new WaypointRepository(db)); - string taskId; + string scenarioId; if (_usePreset) { @@ -58,7 +58,7 @@ namespace CounterDrone.Unity Debug.LogError("无预设想定,请确认 defaults.json 已放入 StreamingAssets"); return; } - taskId = demos.Items[0].Id; + scenarioId = demos.Items[0].Id; Debug.Log($"使用预设想定: {demos.Items[0].Name}"); } else @@ -67,17 +67,17 @@ namespace CounterDrone.Unity var defaults = DefaultData.Load(paths); var task = scenario.CreateTask("Unity Demo", ""); - taskId = task.Id; + scenarioId = task.Id; - scenario.SaveScene(taskId, defaults.Environments.First(w => w.Id == "sunny-calm").ToCombatScene()); - scenario.SaveTarget(taskId, defaults.Drones.First(p => p.Id == "shahed").ToTargetConfig()); - scenario.SaveRoute(taskId, "default", + scenario.SaveScene(scenarioId, defaults.Environments.First(w => w.Id == "sunny-calm").ToCombatScene()); + scenario.SaveTarget(scenarioId, defaults.Drones.First(p => p.Id == "shahed").ToDroneProfile()); + scenario.SaveRoute(scenarioId, "default", defaults.Formations.First(f => f.Id == "single").ToRoutePlan(), defaults.Routes.First(r => _routeLength > 6000 ? r.Id == "10km-h500" : r.Id == "5km-h500") .ToWaypoints(_droneSpeed)); // 从火力单元预设构建 FireUnit → Planner 自动生成方案 → 引擎执行 - var detail = scenario.GetTaskDetail(taskId); + var detail = scenario.GetTaskDetail(scenarioId); var ammoCatalog = db.Table().ToList(); var planner = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths)); var threats = new List @@ -96,18 +96,18 @@ namespace CounterDrone.Unity }); var plan = planner.Plan(fireUnits, threats, detail.Scene, new List()); - scenario.SaveCloudDispersal(taskId, new CloudDispersal + scenario.SaveCloudDispersal(scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = detail.Targets[0].TypicalAltitude, Source = "Algorithm", }); - scenario.SaveDeployment(taskId, new List + scenario.SaveDeployment(scenarioId, new List { defaults.FireUnits.First(f => f.Id == "ground-light") .ToEquipmentDeployment(AerosolType.InertGas, 1, _routeLength / 2f, 0, 50), }); - scenario.UpdateStep(taskId, 5); + scenario.UpdateStep(scenarioId, 5); Debug.Log($"自定义想定: {plan.Best.ThreatsEngaged} 威胁已分配, {plan.Best.MergedSchedule.Count} 发, 概率 {plan.Best.OverallProbability:P0}"); } @@ -120,7 +120,7 @@ namespace CounterDrone.Unity if (Runner == null) Runner = gameObject.AddComponent(); else Runner.enabled = true; Runner.DataService = dataService; - Runner.LoadAndStart(taskId); + Runner.LoadAndStart(scenarioId); Runner.Engine.TimeScale = _timeScale; // 定位相机 diff --git a/src/Unity/Assets/Scripts/Managers/SimulationRunner.cs b/src/Unity/Assets/Scripts/Managers/SimulationRunner.cs index 41d74c9..6527d56 100644 --- a/src/Unity/Assets/Scripts/Managers/SimulationRunner.cs +++ b/src/Unity/Assets/Scripts/Managers/SimulationRunner.cs @@ -23,7 +23,7 @@ namespace CounterDrone.Unity public FrameDataStore FrameStore => _frameStore; private IScenarioService _scenario; private IPathProvider _paths; - private string _taskId; + private string _scenarioId; private SQLite.SQLiteConnection _db; private readonly Dictionary _entityVisuals = new(); @@ -43,8 +43,8 @@ namespace CounterDrone.Unity SqliteConnectionTracker.Track(_db); _scenario = new ScenarioService( - new SimTaskRepository(_db), new CombatSceneRepository(_db), - new ControlZoneRepository(_db), new TargetConfigRepository(_db), + new ScenarioRepository(_db), new CombatSceneRepository(_db), + new ControlZoneRepository(_db), new DroneProfileRepository(_db), new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db), new RoutePlanRepository(_db), new WaypointRepository(_db)); @@ -52,13 +52,13 @@ namespace CounterDrone.Unity _engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefensePlanner(DefaultData.Load(_paths).Ammunition, PlannerConfig.Load(_paths))); } - public void LoadAndStart(string taskId) + public void LoadAndStart(string scenarioId) { - _taskId = taskId; - var detail = _scenario.GetTaskDetail(taskId); + _scenarioId = scenarioId; + var detail = _scenario.GetTaskDetail(scenarioId); if (detail == null) { Debug.LogError("Task not found"); return; } - _engine.Initialize(taskId); + _engine.Initialize(scenarioId); foreach (var drone in _engine.Drones) SpawnDroneVisual(drone); diff --git a/src/Unity/Assets/StreamingAssets/defaults.json b/src/Unity/Assets/StreamingAssets/defaults.json index 361d99f..331add0 100644 --- a/src/Unity/Assets/StreamingAssets/defaults.json +++ b/src/Unity/Assets/StreamingAssets/defaults.json @@ -116,17 +116,17 @@ "targets": [ { "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)", - "TargetType": 0, "PowerType": 0, "Wingspan": 1.2, "TypicalSpeed": 60.0, "TypicalAltitude": 300.0 }, + "DroneType": 0, "PowerType": 0, "Wingspan": 1.2, "TypicalSpeed": 60.0, "TypicalAltitude": 300.0 }, { "Id": "electric-scout", "Name": "[Demo] 电推侦察无人机", - "TargetType": 2, "PowerType": 0, "Wingspan": 1.8, "TypicalSpeed": 100.0, "TypicalAltitude": 500.0 }, + "DroneType": 1, "PowerType": 0, "Wingspan": 1.8, "TypicalSpeed": 100.0, "TypicalAltitude": 500.0 }, { "Id": "fixed-piston", "Name": "[Demo] 固定翼活塞(Orlan类)", - "TargetType": 1, "PowerType": 1, "Wingspan": 3.5, "TypicalSpeed": 150.0, "TypicalAltitude": 1000.0 }, + "DroneType": 1, "PowerType": 1, "Wingspan": 3.5, "TypicalSpeed": 150.0, "TypicalAltitude": 1000.0 }, { "Id": "shahed", "Name": "[Demo] 活塞巡飞弹(Shahed类)", - "TargetType": 3, "PowerType": 1, "Wingspan": 2.5, "TypicalSpeed": 200.0, "TypicalAltitude": 500.0 }, + "DroneType": 1, "PowerType": 1, "Wingspan": 2.5, "TypicalSpeed": 200.0, "TypicalAltitude": 500.0 }, { "Id": "tb2", "Name": "[Demo] 中空长航时(TB2类)", - "TargetType": 1, "PowerType": 1, "Wingspan": 12.0, "TypicalSpeed": 220.0, "TypicalAltitude": 5500.0 }, + "DroneType": 1, "PowerType": 1, "Wingspan": 12.0, "TypicalSpeed": 220.0, "TypicalAltitude": 5500.0 }, { "Id": "cruise-missile", "Name": "[Demo] 巡航导弹(喷气式)", - "TargetType": 4, "PowerType": 2, "Wingspan": 1.5, "TypicalSpeed": 200.0, "TypicalAltitude": 2000.0 } + "DroneType": 2, "PowerType": 2, "Wingspan": 1.5, "TypicalSpeed": 200.0, "TypicalAltitude": 2000.0 } ], "detectionEquipment": [ diff --git a/test/unit/CounterDrone.Core.Tests/DamageModelTests.cs b/test/unit/CounterDrone.Core.Tests/DamageModelTests.cs index 3a24c7f..379f888 100644 --- a/test/unit/CounterDrone.Core.Tests/DamageModelTests.cs +++ b/test/unit/CounterDrone.Core.Tests/DamageModelTests.cs @@ -12,7 +12,7 @@ namespace CounterDrone.Core.Tests var model = new InertGasDamageModel(); // 活塞发动机暴露于惰性气体 - var dmg = model.CalculateDamage(TargetType.Piston, PowerType.Piston, + var dmg = model.CalculateDamage(DroneType.FixedWing, PowerType.Piston, AerosolType.InertGas, cloudDensity: 0.1f, exposureTime: 2f, deltaTime: 1f); Assert.True(dmg > 0.1f); // 高于基础速率(0.15 × 1.5 = 0.225) @@ -23,7 +23,7 @@ namespace CounterDrone.Core.Tests { var model = new InertGasDamageModel(); - var dmg = model.CalculateDamage(TargetType.Piston, PowerType.Piston, + var dmg = model.CalculateDamage(DroneType.FixedWing, PowerType.Piston, AerosolType.ActiveMaterial, cloudDensity: 0.1f, exposureTime: 2f, deltaTime: 1f); Assert.Equal(0f, dmg); @@ -34,12 +34,12 @@ namespace CounterDrone.Core.Tests { var model = new ActiveMaterialDamageModel(); - var dmg1 = model.CalculateDamage(TargetType.FixedWing, PowerType.Jet, + var dmg1 = model.CalculateDamage(DroneType.FixedWing, PowerType.Jet, AerosolType.ActiveMaterial, cloudDensity: 0.2f, exposureTime: 1f, deltaTime: 1f); Assert.True(dmg1 >= 0.5f); // 爆发伤害 - var dmg2 = model.CalculateDamage(TargetType.FixedWing, PowerType.Jet, + var dmg2 = model.CalculateDamage(DroneType.FixedWing, PowerType.Jet, AerosolType.ActiveMaterial, cloudDensity: 0.2f, exposureTime: 2f, deltaTime: 1f); Assert.True(dmg2 < 0.1f); // 后续余伤很小 @@ -50,7 +50,7 @@ namespace CounterDrone.Core.Tests { var model = new ActiveMaterialDamageModel(); - var dmg = model.CalculateDamage(TargetType.FixedWing, PowerType.Jet, + var dmg = model.CalculateDamage(DroneType.FixedWing, PowerType.Jet, AerosolType.ActiveMaterial, cloudDensity: 0.2f, exposureTime: 0f, deltaTime: 0.1f); // 喷气发动机:0.6 × 1.3 = 0.78 @@ -62,10 +62,10 @@ namespace CounterDrone.Core.Tests { var model = new ActiveFuelDamageModel(); - var dmg1 = model.CalculateDamage(TargetType.HighSpeed, PowerType.Jet, + var dmg1 = model.CalculateDamage(DroneType.HighSpeed, PowerType.Jet, AerosolType.ActiveFuel, cloudDensity: 0.1f, exposureTime: 1f, deltaTime: 1f); - var dmg2 = model.CalculateDamage(TargetType.HighSpeed, PowerType.Jet, + var dmg2 = model.CalculateDamage(DroneType.HighSpeed, PowerType.Jet, AerosolType.ActiveFuel, cloudDensity: 0.1f, exposureTime: 5f, deltaTime: 1f); // 5 秒后的伤害应显著大于 1 秒后 @@ -77,7 +77,7 @@ namespace CounterDrone.Core.Tests { var model = new ActiveFuelDamageModel(); - var dmg = model.CalculateDamage(TargetType.HighSpeed, PowerType.Jet, + var dmg = model.CalculateDamage(DroneType.HighSpeed, PowerType.Jet, AerosolType.ActiveFuel, cloudDensity: 0.1f, exposureTime: 1f, deltaTime: 1f); Assert.True(dmg > 0.02f); // 基础速率 × 灵敏度 @@ -100,17 +100,17 @@ namespace CounterDrone.Core.Tests var router = new DamageModelRouter(); // 惰性气体 - var dmg1 = router.CalculateDamage(TargetType.Piston, PowerType.Piston, + var dmg1 = router.CalculateDamage(DroneType.FixedWing, PowerType.Piston, AerosolType.InertGas, 0.1f, 1f, 1f); Assert.True(dmg1 > 0f); // 活性材料 - var dmg2 = router.CalculateDamage(TargetType.FixedWing, PowerType.Jet, + var dmg2 = router.CalculateDamage(DroneType.FixedWing, PowerType.Jet, AerosolType.ActiveMaterial, 0.2f, 0f, 1f); Assert.True(dmg2 > 0f); // 活性燃料 - var dmg3 = router.CalculateDamage(TargetType.HighSpeed, PowerType.Jet, + var dmg3 = router.CalculateDamage(DroneType.HighSpeed, PowerType.Jet, AerosolType.ActiveFuel, 0.1f, 1f, 1f); Assert.True(dmg3 > 0f); } diff --git a/test/unit/CounterDrone.Core.Tests/DatabaseManagerTests.cs b/test/unit/CounterDrone.Core.Tests/DatabaseManagerTests.cs index b4a49c5..45690a5 100644 --- a/test/unit/CounterDrone.Core.Tests/DatabaseManagerTests.cs +++ b/test/unit/CounterDrone.Core.Tests/DatabaseManagerTests.cs @@ -34,8 +34,8 @@ namespace CounterDrone.Core.Tests // 验证所有 12 张表存在(含 Meta) var tables = new[] { - "ModelInfo", "AmmunitionSpec", "SimTask", "CombatScene", - "ControlZone", "TargetConfig", "EquipmentDeployment", + "ModelInfo", "AmmunitionSpec", "Scenario", "CombatScene", + "ControlZone", "DroneProfile", "EquipmentDeployment", "CloudDispersal", "RoutePlan", "Waypoint", "SimulationReport" }; @@ -65,13 +65,13 @@ namespace CounterDrone.Core.Tests [Fact] public void DeleteFrameDb_RemovesFile() { - var taskId = "task_del"; - var db = _dbManager.OpenFrameDb(taskId); + var scenarioId = "task_del"; + var db = _dbManager.OpenFrameDb(scenarioId); db.Close(); - _dbManager.DeleteFrameDb(taskId); + _dbManager.DeleteFrameDb(scenarioId); - var dbPath = Path.Combine(_paths.GetFramesDir(), $"{taskId}.db"); + var dbPath = Path.Combine(_paths.GetFramesDir(), $"{scenarioId}.db"); Assert.False(File.Exists(dbPath)); } diff --git a/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs b/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs index f5be091..343bd37 100644 --- a/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs +++ b/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs @@ -43,9 +43,9 @@ namespace CounterDrone.Core.Tests var t = new DroneWave { WaveId = "default", - Target = new TargetConfig + Target = new DroneProfile { - TargetType = (int)TargetType.Piston, PowerType = (int)power, + DroneType = (int)DroneType.FixedWing, PowerType = (int)power, Quantity = 1, TypicalSpeed = speed, TypicalAltitude = alt, }, Waypoints = new List @@ -378,9 +378,9 @@ namespace CounterDrone.Core.Tests var threat = new DroneWave { WaveId = "default", - Target = new TargetConfig + Target = new DroneProfile { - TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston, + DroneType = (int)DroneType.FixedWing, PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500, }, Waypoints = new List diff --git a/test/unit/CounterDrone.Core.Tests/DroneEntityTests.cs b/test/unit/CounterDrone.Core.Tests/DroneEntityTests.cs index f867f3a..2329c13 100644 --- a/test/unit/CounterDrone.Core.Tests/DroneEntityTests.cs +++ b/test/unit/CounterDrone.Core.Tests/DroneEntityTests.cs @@ -8,11 +8,11 @@ namespace CounterDrone.Core.Tests { public class DroneEntityTests { - private TargetConfig CreateConfig(float speed = 120, float altitude = 300) + private DroneProfile CreateConfig(float speed = 120, float altitude = 300) { - return new TargetConfig + return new DroneProfile { - TargetType = (int)TargetType.Piston, + DroneType = (int)DroneType.FixedWing, PowerType = (int)PowerType.Piston, TypicalSpeed = speed, TypicalAltitude = altitude, diff --git a/test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs b/test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs index ea8896e..cd0d4ba 100644 --- a/test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs +++ b/test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs @@ -17,7 +17,7 @@ namespace CounterDrone.Core.Tests private readonly string _testDir; private readonly IScenarioService _scenario; private readonly SQLite.SQLiteConnection _db; - private string _taskId = string.Empty; + private string _scenarioId = string.Empty; public EdgeCaseTests() { @@ -27,8 +27,8 @@ namespace CounterDrone.Core.Tests _db = dbm.OpenMainDb(); _scenario = new ScenarioService( - new SimTaskRepository(_db), new CombatSceneRepository(_db), - new ControlZoneRepository(_db), new TargetConfigRepository(_db), + new ScenarioRepository(_db), new CombatSceneRepository(_db), + new ControlZoneRepository(_db), new DroneProfileRepository(_db), new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db), new RoutePlanRepository(_db), new WaypointRepository(_db)); } @@ -43,20 +43,20 @@ namespace CounterDrone.Core.Tests public void EmptyDeployment_EngineRunsWithoutCrash() { var task = _scenario.CreateTask("空部署", ""); - _taskId = task.Id; + _scenarioId = task.Id; - _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 }); - _scenario.SaveTarget(_taskId, new TargetConfig + _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0 }); + _scenario.SaveTarget(_scenarioId, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.Piston, + DroneType = (int)DroneType.FixedWing, Quantity = 1, TypicalSpeed = 100, TypicalAltitude = 300, }); - _scenario.SaveDeployment(_taskId, new List()); - _scenario.SaveCloudDispersal(_taskId, new CloudDispersal()); - _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenario.SaveDeployment(_scenarioId, new List()); + _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal()); + _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0, Speed = 100 }, @@ -65,7 +65,7 @@ namespace CounterDrone.Core.Tests var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(TestData.Ammo, TestPlannerConfig.Instance)); - engine.Initialize(_taskId); + engine.Initialize(_scenarioId); engine.TimeScale = 4f; for (int i = 0; i < 500; i++) @@ -82,23 +82,23 @@ namespace CounterDrone.Core.Tests public void ExtremeWind_DroneStillFlies() { var task = _scenario.CreateTask("飓风", ""); - _taskId = task.Id; + _scenarioId = task.Id; - _scenario.SaveScene(_taskId, new CombatScene + _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 30, // 最大风速 WindDirection = (int)WindDirection.E, }); - _scenario.SaveTarget(_taskId, new TargetConfig + _scenario.SaveTarget(_scenarioId, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.Piston, + DroneType = (int)DroneType.FixedWing, Quantity = 1, TypicalSpeed = 600, // 高速对抗强风 }); - _scenario.SaveDeployment(_taskId, new List()); - _scenario.SaveCloudDispersal(_taskId, new CloudDispersal()); - _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenario.SaveDeployment(_scenarioId, new List()); + _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal()); + _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0, Speed = 600 }, @@ -107,7 +107,7 @@ namespace CounterDrone.Core.Tests var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(TestData.Ammo, TestPlannerConfig.Instance)); - engine.Initialize(_taskId); + engine.Initialize(_scenarioId); engine.TimeScale = 4f; for (int i = 0; i < 500; i++) @@ -125,21 +125,21 @@ namespace CounterDrone.Core.Tests public void LongRoute_CompletesWithoutError() { var task = _scenario.CreateTask("超长航路", ""); - _taskId = task.Id; + _scenarioId = task.Id; - _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 }); - _scenario.SaveTarget(_taskId, new TargetConfig + _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0 }); + _scenario.SaveTarget(_scenarioId, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.HighSpeed, + DroneType = (int)DroneType.HighSpeed, Quantity = 1, TypicalSpeed = 500, }); - _scenario.SaveDeployment(_taskId, new List()); - _scenario.SaveCloudDispersal(_taskId, new CloudDispersal()); + _scenario.SaveDeployment(_scenarioId, new List()); + _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal()); // 500 km/h, 100km 航程 - _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 500 }, @@ -148,7 +148,7 @@ namespace CounterDrone.Core.Tests var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(TestData.Ammo, TestPlannerConfig.Instance)); - engine.Initialize(_taskId); + engine.Initialize(_scenarioId); engine.TimeScale = 4f; for (int i = 0; i < 5000; i++) diff --git a/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs b/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs index cadcd92..a60a601 100644 --- a/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs +++ b/test/unit/CounterDrone.Core.Tests/FrameDataStoreTests.cs @@ -25,9 +25,9 @@ namespace CounterDrone.Core.Tests if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true); } - private void CreateFakeDb(string taskId) + private void CreateFakeDb(string scenarioId) { - _store.BeginRecording(taskId); + _store.BeginRecording(scenarioId); _store.RecordFrame(0, 0f, new List { new EntitySnapshot { EntityId = "d1" } }); _store.Flush(); } diff --git a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs index 4f5e4ac..4a8965f 100644 --- a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs +++ b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs @@ -21,7 +21,7 @@ namespace CounterDrone.Core.Tests private readonly FrameDataStore _frameStore; private readonly SQLiteConnection _mainDb; private List _ammoCatalog; - private string _taskId = string.Empty; + private string _scenarioId = string.Empty; public FullPipelineTests() { @@ -32,8 +32,8 @@ namespace CounterDrone.Core.Tests _ammoCatalog = new List(TestData.Ammo); _scenario = new ScenarioService( - new SimTaskRepository(_mainDb), new CombatSceneRepository(_mainDb), - new ControlZoneRepository(_mainDb), new TargetConfigRepository(_mainDb), + new ScenarioRepository(_mainDb), new CombatSceneRepository(_mainDb), + new ControlZoneRepository(_mainDb), new DroneProfileRepository(_mainDb), new EquipmentDeploymentRepository(_mainDb), new CloudDispersalRepository(_mainDb), new RoutePlanRepository(_mainDb), new WaypointRepository(_mainDb)); @@ -50,7 +50,7 @@ namespace CounterDrone.Core.Tests { var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefensePlanner(_ammoCatalog, TestPlannerConfig.Instance)); - engine.Initialize(_taskId); + engine.Initialize(_scenarioId); engine.TimeScale = timeScale; // 8倍速加速 for (int i = 0; i < maxTicks; i++) { @@ -66,22 +66,22 @@ namespace CounterDrone.Core.Tests private void VerifyAndExportReport(SimulationEngine eng, DroneEntity drone) { - var detail = _scenario.GetTaskDetail(_taskId)!; + var detail = _scenario.GetTaskDetail(_scenarioId)!; var report = new ReportGenerator().Generate(detail, eng.Events.ToList(), drone.Status, eng.SimulationTime); Assert.Contains("对抗结果", report); Assert.Contains(detail.Task.Name, report); var svc = new ReportService(_mainDb, _paths); - var r = svc.Generate(_taskId, detail, eng.Events.ToList(), drone.Status.ToString(), eng.SimulationTime); + var r = svc.Generate(_scenarioId, detail, eng.Events.ToList(), drone.Status.ToString(), eng.SimulationTime); svc.ExportToFile(r.Id, ReportOutputDir); // 持久化目录 } - private TaskFullConfig LoadPreset(string name) + private ScenarioConfig LoadPreset(string name) { var results = _scenario.SearchTasks(name, null, null, 1, 1); Assert.True(results.TotalCount > 0, $"预设想定未找到: {name}"); - _taskId = results.Items[0].Id; - return _scenario.GetTaskDetail(_taskId)!; + _scenarioId = results.Items[0].Id; + return _scenario.GetTaskDetail(_scenarioId)!; } private SimulationEngine RunPreset(string name, int maxFrames = 8000) @@ -152,7 +152,7 @@ namespace CounterDrone.Core.Tests Assert.All(eng.Events.Where(e => e.Type == SimEventType.MunitionLaunched), e => Assert.Contains("空基", e.Description)); var drone = eng.Drones[0]; - var detail = _scenario.GetTaskDetail(_taskId)!; + var detail = _scenario.GetTaskDetail(_scenarioId)!; var report = new ReportGenerator().Generate(detail, eng.Events.ToList(), drone.Status, eng.SimulationTime); Assert.True(drone.Hp < 0.1f, $"Hp={drone.Hp:F3} pos=({drone.PosX:F0},{drone.PosY:F0}) launched={eng.Events.Count(e => e.Type == SimEventType.MunitionLaunched)}\n{report}"); VerifyAndExportReport(eng, drone); @@ -183,24 +183,24 @@ namespace CounterDrone.Core.Tests { // 场景A:无探测设备(上帝视角,从航路起点算) var taskA = _scenario.CreateTask("无探测远航路", ""); - _taskId = taskA.Id; - _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0, Visibility = 10000 }); - _scenario.SaveTarget(_taskId, new TargetConfig + _scenarioId = taskA.Id; + _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0, Visibility = 10000 }); + _scenario.SaveTarget(_scenarioId, new DroneProfile { - WaveId = "default", TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston, + WaveId = "default", DroneType = (int)DroneType.FixedWing, PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500, }); - _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }, new Waypoint { PosX = 20000, PosY = 500, PosZ = 0, Speed = 200 }, }); - _scenario.SaveDeployment(_taskId, new List + _scenario.SaveDeployment(_scenarioId, new List { TestData.All.FireUnits.First(f => f.Id == "ground-light").ToEquipmentDeployment(AerosolType.InertGas, 1, 8000, 0, 50), }); - _scenario.SaveCloudDispersal(_taskId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 }); + _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 }); var engA = RunSimulation(8000); float firstFireA = engA.Events.Where(e => e.Type == SimEventType.MunitionLaunched).Min(e => e.OccurredAt); @@ -208,20 +208,20 @@ namespace CounterDrone.Core.Tests // 探测圆边界 X=4000 和 X=16000,无人机从 X=0 飞向 20000,在 X=4000 进入探测 // planner 基于探测边界 X=4000 算到达时间(而非起点 X=0) var taskB = _scenario.CreateTask("有探测远航路", ""); - _taskId = taskB.Id; - _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0, Visibility = 10000 }); - _scenario.SaveTarget(_taskId, new TargetConfig + _scenarioId = taskB.Id; + _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0, Visibility = 10000 }); + _scenario.SaveTarget(_scenarioId, new DroneProfile { - WaveId = "default", TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston, + WaveId = "default", DroneType = (int)DroneType.FixedWing, PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500, }); - _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }, new Waypoint { PosX = 20000, PosY = 500, PosZ = 0, Speed = 200 }, }); - _scenario.SaveDeployment(_taskId, new List + _scenario.SaveDeployment(_scenarioId, new List { TestData.All.FireUnits.First(f => f.Id == "ground-light").ToEquipmentDeployment(AerosolType.InertGas, 1, 8000, 0, 50), // 独立探测设备 @@ -234,7 +234,7 @@ namespace CounterDrone.Core.Tests DetectionAccuracy = 50, }, }); - _scenario.SaveCloudDispersal(_taskId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 }); + _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 }); var engB = RunSimulation(8000); float firstFireB = engB.Events.Where(e => e.Type == SimEventType.MunitionLaunched).Min(e => e.OccurredAt); diff --git a/test/unit/CounterDrone.Core.Tests/PlannerConfigTests.cs b/test/unit/CounterDrone.Core.Tests/PlannerConfigTests.cs index fe7cf4e..1227669 100644 --- a/test/unit/CounterDrone.Core.Tests/PlannerConfigTests.cs +++ b/test/unit/CounterDrone.Core.Tests/PlannerConfigTests.cs @@ -30,8 +30,8 @@ namespace CounterDrone.Core.Tests ""CriticalProbabilityThreshold"": 0.5, ""MaxInterceptProbability"": 0.95, ""TypeCoefficient"": { - ""HighSpeed"": 4.0, ""FixedWing"": 2.0, ""Piston"": 2.0, - ""Rotor"": 1.0, ""Electric"": 1.0 + ""HighSpeed"": 4.0, ""FixedWing"": 2.0, + ""Rotor"": 1.0 }, ""AmmoMatch"": { ""Electric"": ""InertGas"", ""Piston"": ""InertGas"", ""Jet"": ""ActiveMaterial"" @@ -47,7 +47,8 @@ namespace CounterDrone.Core.Tests Assert.Equal(0.2f, cfg.CloudOverlapRatio); Assert.Equal(0.5f, cfg.CriticalProbabilityThreshold); Assert.Equal(0.95f, cfg.MaxInterceptProbability); - Assert.Equal(4.0f, cfg.TypeCoefficient[TargetType.HighSpeed]); + Assert.Equal(4.0f, cfg.TypeCoefficient[DroneType.HighSpeed]); + Assert.Equal(2.0f, cfg.TypeCoefficient[DroneType.FixedWing]); Assert.Equal(AerosolType.InertGas, cfg.AmmoMatch[PowerType.Piston]); Assert.Equal(AerosolType.ActiveMaterial, cfg.AmmoMatch[PowerType.Jet]); } @@ -64,7 +65,7 @@ namespace CounterDrone.Core.Tests { // 缺 CriticalProbabilityThreshold WriteConfig(@"{ ""CloudOverlapRatio"": 0.2, ""MaxInterceptProbability"": 0.95, - ""TypeCoefficient"": {""Piston"": 2.0}, ""AmmoMatch"": {""Piston"": ""InertGas""} }"); + ""TypeCoefficient"": {""FixedWing"": 2.0}, ""AmmoMatch"": {""Piston"": ""InertGas""} }"); Assert.Throws(() => PlannerConfig.Load(_testDir)); } @@ -89,7 +90,7 @@ namespace CounterDrone.Core.Tests // 验证枚举用字符串(非数字)也能正确解析 WriteConfig(ValidJson); var cfg = PlannerConfig.Load(_testDir); - Assert.Equal(1.0f, cfg.TypeCoefficient[TargetType.Rotor]); + Assert.Equal(1.0f, cfg.TypeCoefficient[DroneType.Rotor]); Assert.Equal(AerosolType.InertGas, cfg.AmmoMatch[PowerType.Electric]); } } diff --git a/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs b/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs index b111e52..263b12d 100644 --- a/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs @@ -33,10 +33,10 @@ namespace CounterDrone.Core.Tests public void Generate_ProducesReportContent() { var gen = new ReportGenerator(); - var config = new TaskFullConfig + var config = new ScenarioConfig { - Task = new SimTask { Name = "测试任务", TaskNumber = "SIM-001" }, - Targets = new List { new TargetConfig { Quantity = 1 } }, + Task = new Scenario { Name = "测试任务", TaskNumber = "SIM-001" }, + Targets = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List { new EquipmentDeployment { EquipmentRole = (int)EquipmentRole.LaunchPlatform, Quantity = 3 }, diff --git a/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs b/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs index bd5b65a..e3f9656 100644 --- a/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs @@ -34,10 +34,10 @@ namespace CounterDrone.Core.Tests [Fact] public void Generate_And_Get_ReturnsReport() { - var config = new TaskFullConfig + var config = new ScenarioConfig { - Task = new SimTask { Name = "Test", TaskNumber = "SIM-001" }, - Targets = new List { new TargetConfig { Quantity = 1 } }, + Task = new Scenario { Name = "Test", TaskNumber = "SIM-001" }, + Targets = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List(), Cloud = new CloudDispersal(), }; @@ -56,10 +56,10 @@ namespace CounterDrone.Core.Tests [Fact] public void Delete_RemovesReport() { - var config = new TaskFullConfig + var config = new ScenarioConfig { - Task = new SimTask { Name = "Del", TaskNumber = "SIM-DEL" }, - Targets = new List { new TargetConfig { Quantity = 1 } }, + Task = new Scenario { Name = "Del", TaskNumber = "SIM-DEL" }, + Targets = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List(), Cloud = new CloudDispersal(), }; @@ -72,10 +72,10 @@ namespace CounterDrone.Core.Tests [Fact] public void SearchReports_Keyword() { - var cfg = new TaskFullConfig + var cfg = new ScenarioConfig { - Task = new SimTask { Name = "城市防御", TaskNumber = "SIM-A" }, - Targets = new List { new TargetConfig { Quantity = 1 } }, + Task = new Scenario { Name = "城市防御", TaskNumber = "SIM-A" }, + Targets = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List(), Cloud = new CloudDispersal(), }; diff --git a/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs b/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs index 85f6d77..3c98e49 100644 --- a/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs +++ b/test/unit/CounterDrone.Core.Tests/RepositoryEdgeTests.cs @@ -22,42 +22,42 @@ namespace CounterDrone.Core.Tests public void Dispose() { _db?.Close(); if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true); } [Fact] - public void TargetConfig_DeleteByTaskId_RemovesAll() + public void DroneProfile_DeleteByScenarioId_RemovesAll() { - var repo = new TargetConfigRepository(_db); - repo.Insert(new TargetConfig { Id = "t1", TaskId = "taskA", Quantity = 1 }); - repo.Insert(new TargetConfig { Id = "t2", TaskId = "taskA", Quantity = 2 }); - repo.Insert(new TargetConfig { Id = "t3", TaskId = "taskB", Quantity = 1 }); + var repo = new DroneProfileRepository(_db); + repo.Insert(new DroneProfile { Id = "t1", ScenarioId = "taskA", Quantity = 1 }); + repo.Insert(new DroneProfile { Id = "t2", ScenarioId = "taskA", Quantity = 2 }); + repo.Insert(new DroneProfile { Id = "t3", ScenarioId = "taskB", Quantity = 1 }); - repo.DeleteByTaskId("taskA"); + repo.DeleteByScenarioId("taskA"); - Assert.Empty(repo.GetByTaskId("taskA")); - Assert.Single(repo.GetByTaskId("taskB")); + Assert.Empty(repo.GetByScenarioId("taskA")); + Assert.Single(repo.GetByScenarioId("taskB")); } [Fact] - public void Waypoint_DeleteByTaskId_RemovesAll() + public void Waypoint_DeleteByScenarioId_RemovesAll() { var repo = new WaypointRepository(_db); - repo.Insert(new Waypoint { TaskId = "w1", OrderIndex = 0 }); - repo.Insert(new Waypoint { TaskId = "w1", OrderIndex = 1 }); - repo.Insert(new Waypoint { TaskId = "w2", OrderIndex = 0 }); + repo.Insert(new Waypoint { ScenarioId = "w1", OrderIndex = 0 }); + repo.Insert(new Waypoint { ScenarioId = "w1", OrderIndex = 1 }); + repo.Insert(new Waypoint { ScenarioId = "w2", OrderIndex = 0 }); - repo.DeleteByTaskId("w1"); + repo.DeleteByScenarioId("w1"); - Assert.Empty(repo.GetByTaskId("w1")); - Assert.Single(repo.GetByTaskId("w2")); + Assert.Empty(repo.GetByScenarioId("w1")); + Assert.Single(repo.GetByScenarioId("w2")); } [Fact] - public void EquipmentDeployment_DeleteByTaskId_Works() + public void EquipmentDeployment_DeleteByScenarioId_Works() { var repo = new EquipmentDeploymentRepository(_db); - repo.Insert(new EquipmentDeployment { Id = "e1", TaskId = "eqA" }); - repo.Insert(new EquipmentDeployment { Id = "e2", TaskId = "eqA" }); + repo.Insert(new EquipmentDeployment { Id = "e1", ScenarioId = "eqA" }); + repo.Insert(new EquipmentDeployment { Id = "e2", ScenarioId = "eqA" }); - repo.DeleteByTaskId("eqA"); - Assert.Empty(repo.GetByTaskId("eqA")); + repo.DeleteByScenarioId("eqA"); + Assert.Empty(repo.GetByScenarioId("eqA")); } } } diff --git a/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs b/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs index 290ea9e..07cf620 100644 --- a/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs @@ -24,10 +24,10 @@ namespace CounterDrone.Core.Tests var dbManager = new DatabaseManager(paths); _db = dbManager.OpenMainDb(); _service = new ScenarioService( - new SimTaskRepository(_db), + new ScenarioRepository(_db), new CombatSceneRepository(_db), new ControlZoneRepository(_db), - new TargetConfigRepository(_db), + new DroneProfileRepository(_db), new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db), new RoutePlanRepository(_db), @@ -101,10 +101,10 @@ namespace CounterDrone.Core.Tests Temperature = 25.0, }); - _service.SaveTarget(task.Id, new TargetConfig + _service.SaveTarget(task.Id, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.FixedWing, + DroneType = (int)DroneType.FixedWing, Quantity = 3, }); @@ -199,10 +199,10 @@ namespace CounterDrone.Core.Tests public void SaveTarget_SavesCorrectly() { var task = _service.CreateTask("Target Test", ""); - _service.SaveTarget(task.Id, new TargetConfig + _service.SaveTarget(task.Id, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.Piston, + DroneType = (int)DroneType.FixedWing, Quantity = 5, PowerType = (int)PowerType.Piston, Wingspan = 2.5, @@ -212,7 +212,7 @@ namespace CounterDrone.Core.Tests var detail = _service.GetTaskDetail(task.Id); var target = detail.Targets[0]; - Assert.Equal((int)TargetType.Piston, target.TargetType); + Assert.Equal((int)DroneType.FixedWing, target.DroneType); Assert.Equal(5, target.Quantity); Assert.Equal(120.0, target.TypicalSpeed); } @@ -392,10 +392,10 @@ namespace CounterDrone.Core.Tests }); // 4. 步骤2:目标配置 - _service.SaveTarget(task.Id, new TargetConfig + _service.SaveTarget(task.Id, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.HighSpeed, + DroneType = (int)DroneType.HighSpeed, Quantity = 2, PowerType = (int)PowerType.Jet, TypicalSpeed = 300.0, diff --git a/test/unit/CounterDrone.Core.Tests/SimulationEngineTests.cs b/test/unit/CounterDrone.Core.Tests/SimulationEngineTests.cs index 1286c26..bfe10a1 100644 --- a/test/unit/CounterDrone.Core.Tests/SimulationEngineTests.cs +++ b/test/unit/CounterDrone.Core.Tests/SimulationEngineTests.cs @@ -19,7 +19,7 @@ namespace CounterDrone.Core.Tests private readonly SimulationEngine _engine; private readonly IScenarioService _scenarioService; private readonly SQLite.SQLiteConnection _mainDb; - private string _taskId = string.Empty; + private string _scenarioId = string.Empty; public SimulationEngineTests() { @@ -29,8 +29,8 @@ namespace CounterDrone.Core.Tests _mainDb = dbManager.OpenMainDb(); _scenarioService = new ScenarioService( - new SimTaskRepository(_mainDb), new CombatSceneRepository(_mainDb), - new ControlZoneRepository(_mainDb), new TargetConfigRepository(_mainDb), + new ScenarioRepository(_mainDb), new CombatSceneRepository(_mainDb), + new ControlZoneRepository(_mainDb), new DroneProfileRepository(_mainDb), new EquipmentDeploymentRepository(_mainDb), new CloudDispersalRepository(_mainDb), new RoutePlanRepository(_mainDb), new WaypointRepository(_mainDb)); @@ -48,17 +48,17 @@ namespace CounterDrone.Core.Tests private void SetupScenario() { var task = _scenarioService.CreateTask("Test", ""); - _taskId = task.Id; - _scenarioService.SaveScene(_taskId, new CombatScene { WindSpeed = 0 }); - _scenarioService.SaveTarget(_taskId, new TargetConfig + _scenarioId = task.Id; + _scenarioService.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0 }); + _scenarioService.SaveTarget(_scenarioId, new DroneProfile { WaveId = "default", - TargetType = (int)TargetType.Piston, + DroneType = (int)DroneType.FixedWing, Quantity = 1, PowerType = (int)PowerType.Piston, TypicalSpeed = 60, }); - _scenarioService.SaveDeployment(_taskId, new List + _scenarioService.SaveDeployment(_scenarioId, new List { new EquipmentDeployment { @@ -68,7 +68,7 @@ namespace CounterDrone.Core.Tests AerosolType = (int)AerosolType.InertGas, MunitionCount = 1, Cooldown = 5, }, }); - _scenarioService.SaveCloudDispersal(_taskId, new CloudDispersal + _scenarioService.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 300, @@ -79,7 +79,7 @@ namespace CounterDrone.Core.Tests PositionZ = 0, PositionMode = (int)PositionMode.AlgorithmRecommended, }); - _scenarioService.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenarioService.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0, Altitude = 300, Speed = 60 }, @@ -91,7 +91,7 @@ namespace CounterDrone.Core.Tests public void Initialize_LoadsEntities() { SetupScenario(); - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); Assert.Single(_engine.Drones); Assert.Equal(SimulationState.Running, _engine.State); } @@ -100,7 +100,7 @@ namespace CounterDrone.Core.Tests public void Tick_DroneMoves() { SetupScenario(); - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); _engine.Tick(1f / 20f); Assert.True(_engine.Drones[0].PosX > 0); } @@ -109,7 +109,7 @@ namespace CounterDrone.Core.Tests public void PauseAndResume() { SetupScenario(); - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); _engine.Pause(); Assert.Equal(SimulationState.Paused, _engine.State); @@ -124,7 +124,7 @@ namespace CounterDrone.Core.Tests public void Stop_ClosesGracefully() { SetupScenario(); - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); _engine.Tick(1f / 20f); _engine.Stop(); Assert.Equal(SimulationState.Stopped, _engine.State); @@ -134,11 +134,11 @@ namespace CounterDrone.Core.Tests public void FrameData_IsWritten() { SetupScenario(); - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); for (int i = 0; i < 10; i++) _engine.Tick(1f / 20f); _engine.Stop(); // 触发 Flush - var framePath = Path.Combine(_testDir, "frames", $"{_taskId}.db"); + var framePath = Path.Combine(_testDir, "frames", $"{_scenarioId}.db"); Assert.True(File.Exists(framePath)); } @@ -149,19 +149,19 @@ namespace CounterDrone.Core.Tests private void SetupScenarioWithDetection() { var task = _scenarioService.CreateTask("Detect", ""); - _taskId = task.Id; - _scenarioService.SaveScene(_taskId, new CombatScene { WindSpeed = 0, Visibility = 10000 }); - _scenarioService.SaveTarget(_taskId, new TargetConfig + _scenarioId = task.Id; + _scenarioService.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0, Visibility = 10000 }); + _scenarioService.SaveTarget(_scenarioId, new DroneProfile { WaveId = "w1", - TargetType = (int)TargetType.Piston, + DroneType = (int)DroneType.FixedWing, Quantity = 1, PowerType = (int)PowerType.Piston, TypicalSpeed = 60, TypicalAltitude = 300, }); // 探测设备在 (5000, 0, 0),雷达 3000m,无角度/高度限制 - _scenarioService.SaveDeployment(_taskId, new List + _scenarioService.SaveDeployment(_scenarioId, new List { new EquipmentDeployment { @@ -177,7 +177,7 @@ namespace CounterDrone.Core.Tests AerosolType = (int)AerosolType.InertGas, MunitionCount = 1, Cooldown = 5, }, }); - _scenarioService.SaveCloudDispersal(_taskId, new CloudDispersal + _scenarioService.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 300, @@ -186,7 +186,7 @@ namespace CounterDrone.Core.Tests PositionX = 1000, PositionY = 300, PositionZ = 0, PositionMode = (int)PositionMode.AlgorithmRecommended, }); - _scenarioService.SaveRoute(_taskId, "w1", new RoutePlan { FormationMode = (int)FormationMode.Single }, + _scenarioService.SaveRoute(_scenarioId, "w1", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0, Speed = 60 }, @@ -199,7 +199,7 @@ namespace CounterDrone.Core.Tests { SetupScenarioWithDetection(); _engine.SetFireSchedule(new List()); // 不发射弹药 - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); // 无人机起点 X=0,探测设备在 X=5000 半径 3000 → 探测边界在 X=2000 // 速度 60 km/h = 16.67 m/s,到达 X=2000 约需 120 秒 @@ -224,7 +224,7 @@ namespace CounterDrone.Core.Tests // 探测设备在 X=5000 半径 1000 → 入口 X=4000,出口 X=6000 var task = _scenarioService.CreateTask("Reenter", ""); _scenarioService.SaveScene(task.Id, new CombatScene { WindSpeed = 0, Visibility = 10000 }); - _scenarioService.SaveTarget(task.Id, new TargetConfig + _scenarioService.SaveTarget(task.Id, new DroneProfile { WaveId = "w1", Quantity = 1, TypicalSpeed = 120, PowerType = (int)PowerType.Piston, TypicalAltitude = 300, }); @@ -259,7 +259,7 @@ namespace CounterDrone.Core.Tests { // 使用普通的 SetupScenario(无探测设备) SetupScenario(); - _engine.Initialize(_taskId); + _engine.Initialize(_scenarioId); Assert.Empty(_engine.DetectionEntities); @@ -275,7 +275,7 @@ namespace CounterDrone.Core.Tests // D1 边界 X=1000,D2 边界 X=3000 → D1 更早发现 var task = _scenarioService.CreateTask("Fuse", ""); _scenarioService.SaveScene(task.Id, new CombatScene { WindSpeed = 0, Visibility = 10000 }); - _scenarioService.SaveTarget(task.Id, new TargetConfig + _scenarioService.SaveTarget(task.Id, new DroneProfile { WaveId = "w1", Quantity = 1, TypicalSpeed = 60, PowerType = (int)PowerType.Piston, TypicalAltitude = 300, });