# 后端对接文档(Unity 前端) > **版本**:V2.0 > **日期**:2026-06-20 > **Unity 版本**:2022.3.62f3c1 --- ## 一、交付物与部署 ### 1.1 需要取的文件 ``` src/Unity/Assets/Plugins/CounterDrone.Core/ ← 22 个 DLL(拖入 Unity 项目的 Plugins 目录) src/Unity/Assets/Scripts/Managers/ ← 9 个桥接脚本 ``` StreamingAssets 资源文件(放到 Unity 项目 `Assets/StreamingAssets/` 下): ``` StreamingAssets/ defaults.json ← 默认数据(首次运行自动复制到 persistentDataPath) planner_config.json ← 规划器配置 fonts/CJK-Font.ttf ← PDF 导出用的中文字体(仅 PDF 导出需要) ``` > 以上资源文件可在仓库的 `data/` 目录找到。字体文件名硬编码为 `CJK-Font.ttf`,可替换为任意 CJK TrueType 字体但不可改名。 ### 1.2 DLL 清单(22 个) 全部为纯托管 DLL,无原生库依赖,Unity IL2CPP/Mono 全平台兼容。 | DLL | 用途 | |-----|------| | `CounterDrone.Core.dll` | 核心库 | | `SQLite-net.dll` | SQLite ORM | | `SQLitePCLRaw.core.dll` / `batteries_v2.dll` / `provider.e_sqlite3.dll` | SQLite 原生提供程序 | | `System.Text.Json.dll` / `Encodings.Web.dll` / `Microsoft.Bcl.AsyncInterfaces.dll` | JSON 序列化 | | `System.Memory.dll` / `Buffers.dll` / `Numerics.Vectors.dll` / `Runtime.CompilerServices.Unsafe.dll` / `IO.Pipelines.dll` / `Threading.Tasks.Extensions.dll` | 基础库传递依赖 | | `PdfSharpCore.dll` | PDF 生成 | | `ICSharpCode.SharpZipLib.dll` | PdfSharpCore 依赖(ZIP) | | `SixLabors.Fonts.dll` / `SixLabors.ImageSharp.dll` | PdfSharpCore 依赖(字体/图像) | | `System.Collections.Concurrent.dll` / `IO.UnmanagedMemoryStream.dll` / `Threading.Tasks.Parallel.dll` / `Threading.dll` / `IO.FileSystem.Primitives.dll` | SixLabors 传递依赖 | ### 1.3 DLL 导入设置 DLL 拖入 `Assets/Plugins/CounterDrone.Core/` 后,在 Inspector 中确认所有 DLL 的平台勾选:**Editor + Standalone + Android + iOS 全部勾选**(所有 DLL 均全平台兼容)。 > **IL2CPP 注意**:若遇 `TypeLoadException`,检查 `Player Settings → Managed Stripping Level`,建议设为 **Low** 或 **Medium**。 ### 1.4 更新后端 DLL ```bash # 方式 A:一键脚本(自动编译 + 复制 DLL + Unity 编译验证) pwsh scripts/check_unity_build.ps1 # 方式 B:手动 cd src/CounterDrone.Core dotnet publish -c Release -o ../../unity_plugins # 然后将 unity_plugins/*.dll 全部复制到 src/Unity/Assets/Plugins/CounterDrone.Core/ ``` > **重要**:更新 DLL 后首次运行 Unity 会重建数据库,**历史仿真报告会丢失**(基础数据和预设想定自动重新种子)。这是预期行为。 --- ## 二、快速开始 1. 按 1.1 部署 DLL、脚本和 StreamingAssets 资源 2. 创建空 GameObject,挂 `SimulationBootstrap` 3. 运行 — 自动种子数据库,选一个 `[Demo]` 想定,启动仿真 > `SimulationBootstrap` 是参考模板,展示预设模式(一行代码)和自定义模式两种路径。Inspector 勾选 `_usePreset` 切换。 --- ## 三、完整工作流(5 步) ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │ 基础数据 CRUD │ → │ 创建想定 │ → │ 运行仿真 │ → │ 生成报告 │ → │ 回放 │ │ DataService │ │ ScenarioMgr │ │ SimRunner │ │ ReportMgr │ │ Replay │ └─────────────┘ └─────────────┘ └─────────────┘ └──────────┘ └──────────┘ ``` ### 3.1 管理基础数据 ```csharp var ds = GetComponent().DataService; var drones = ds.GetAllDrones(); ds.SaveDrone(new DroneSpec { Id = "custom", Name = "自定义", TypicalSpeed = 100, ... }); ds.DeleteDrone("custom"); // 7 类基础数据均提供 GetAll/Get/Save/Delete 四个方法 ``` ### 3.2 创建想定 ```csharp var scenario = GetComponent(); // 方式 A:预设想定 var demos = scenario.Search("Demo", null, null, 1, 100); var scenarioId = demos.Items[0].Id; // 方式 B:自定义(5 步配置) var sc = scenario.CreateScenario("我的想定", ""); scenario.SaveScene(sc.Id, new CombatScene { WindSpeed = 5, WindDirection = (int)WindDirection.E }); scenario.SaveScenarioDrone(sc.Id, new ScenarioDrone { DroneSpecId = "shahed", WaveId = "w1", Quantity = 3 }); scenario.SaveDeployment(sc.Id, new List { new() { FireUnitSpecId = "ground-light", Quantity = 2, PositionX = 5000, PositionY = 0, PositionZ = 50, AerosolType = 0, MunitionCount = 8 } }); scenario.SaveRoute(sc.Id, "w1", new RoutePlan(), new List { new() { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }, new() { PosX = 10000, PosY = 500, PosZ = 0, Speed = 200 } }); scenario.SaveCloud(sc.Id, new CloudDispersal { AerosolType = 0, DisperseHeight = 500 }); scenario.UpdateStep(sc.Id, 5); ``` ### 3.3 运行仿真 ```csharp var runner = GetComponent(); runner.LoadAndStart(scenarioId); runner.Engine.TimeScale = 4f; // 事件订阅 runner.Engine.OnMunitionLaunched += m => { }; runner.Engine.OnCloudGenerated += c => { }; runner.Engine.OnDroneDestroyed += d => { }; runner.Engine.OnSimulationEnded += () => { }; // 逐帧驱动(在 Update 中调用) void Update() { var result = runner.Engine.Tick(Time.deltaTime); foreach (var snap in result.EntitySnapshots) { // snap.EntityType, PosX/Y/Z, VelX/Y/Z, Hp, CloudRadius... } } runner.Stop(); ``` ### 3.4 生成报告 ```csharp var rm = GetComponent(); var detail = scenario.GetDetail(scenarioId); var report = rm.Generate(scenarioId, detail, runner.Engine.Events.ToList(), runner.Engine.Drones[0].Status.ToString(), runner.Engine.SimulationTime); // Generate() 自动导出 .md 文件到 {persistentDataPath}/reports/ // PDF 按需导出: byte[] pdf = rm.ExportReport(report.Id, "pdf"); // → byte[] string path = rm.Export(report.Id, dir, "pdf"); // → 文件路径 ``` **Generate 参数**: | 参数 | 类型 | 来源 | |------|------|------| | `scenarioId` | string | 创建想定时获得 | | `config` | ScenarioConfig | `scenario.GetDetail(id)` | | `events` | List\ | `runner.Engine.Events.ToList()`(必须 `.ToList()` 拷贝) | | `finalDroneStatus` | string | `runner.Engine.Drones[0].Status.ToString()` | | `duration` | float | `runner.Engine.SimulationTime`(秒) | **导出方法**: - `ExportReport(id, "pdf")` → `byte[]`,实时渲染 PDF,需字体文件 - `ExportReport(id, "md")` → `byte[]`,从数据库直接读取,快 - `Export(id, dir, "pdf"/"md")` → 文件路径,自动创建目录 - `Export(id)` → 默认导出 MD 到 `{persistentDataPath}/reports/` > PDF 导出依赖 `StreamingAssets/fonts/CJK-Font.ttf`,缺失抛 `FileNotFoundException`。PDF 渲染同步阻塞主线程(小报告 ~100ms,大报告可达 2s),UI 建议显示 loading。 ### 3.5 回放 ```csharp var replay = GetComponent(); replay.LoadReplay(scenarioId); for (int i = 0; i < replay.TotalFrames; i++) { var frame = replay.GetFrame(i); // frame.SimulationTime, frame.EntitySnapshots... } ``` --- ## 四、坐标系与 3D 可视化 ### 4.1 坐标系约定 | 项目 | 约定 | |------|------| | **向上轴** | **Y 轴 = 高度**(与 Unity 默认一致) | | **水平面** | X 轴 = 纵深(航路方向),Z 轴 = 横向 | | **单位** | 米(m) | | **原点** | 场景一角(非中心),航路通常从 X=0 沿 X 正方向延伸 | | **典型场景尺寸** | 4000m × 10000m × 1000m(W × L × H,见 `CombatScene.SceneWidth/Length/Height`) | | **典型无人机高度** | 300~500m(PosY = 500 即 500m 高空) | | **速度单位** | 航路点 `Waypoint.Speed` = **km/h**;平台 `CruiseSpeed` = **m/s**(引擎内部自动换算) | > `SimulationRunner` 直接 `transform.position = new Vector3(snap.PosX, snap.PosY, snap.PosZ)`,无需轴变换。 ### 4.2 Prefab 搭建 `SimulationRunner` 有 3 个 `[SerializeField]` prefab 字段,Inspector 中拖入: | 字段 | 用途 | null 时回退 | 建议缩放 | |------|------|------------|---------| | `_dronePrefab` | 无人机 | Cube | Runner 自动设 `localScale = Vector3.one * 50f` | | `_cloudPrefab` | 云团 | Sphere | Runner 按云团半径动态设 `localScale = Vector3.one * CloudRadius` | | `_platformPrefab` | 发射平台 | Capsule | Runner 自动设 `localScale = (30, 80, 30)` | | —(无字段) | 弹药 | Cylinder | Runner 自动设 `localScale = (2, 10, 2)` | **Prefab 组件要求**: | 组件 | 必需 | 说明 | |------|------|------| | `Renderer` | ✅ | Runner 通过 `GetComponent().material` 设置颜色 | | `Collider` | 可选 | Runner 不依赖 Collider | | 脚本组件 | 不需要 | 位置由 Runner 每帧驱动,prefab 不需要自带移动脚本 | **云团可视化建议**:prefab 用 Sphere 即可(Runner 设红色半透明材质)。如需粒子效果,可自行扩展——Runner 每帧更新 `CloudRadius`(缩放)和 `CloudOpacity`(材质 alpha),粒子系统可读取这两个值驱动参数。 ### 4.3 SimulationRunner 可视化机制 Runner 的 `Update()` 每帧执行: 1. 调用 `engine.Tick(Time.deltaTime)` → 获取 `SimulationFrameResult` 2. 遍历 `result.EntitySnapshots`: - 新实体(EntityId 未见过)→ Instantiate prefab - 已有实体 → 更新 `transform.position` - Cloud 类型 → 更新 `localScale`(按 `CloudRadius`)和材质 alpha(按 `CloudOpacity`) 3. 遍历 `engine.Munitions` 同步炮弹位置,清理已消失的弹药 GameObject **实体颜色约定**(Runner 硬编码,可自行修改): - 无人机:prefab 原始材质 - 云团:红色半透明 `(1, 0, 0, CloudOpacity)` - 平台:蓝色半透明 `(0.2, 0.5, 1, 0.8)` - 弹药:黄色 `(1, 0.92, 0.016, 1)` ### 4.4 相机定位参考 `SimulationBootstrap` 中的相机设置(可供参考): ```csharp // 俯瞰视角 cam.transform.position = new Vector3(midX, 2000, -3000); // midX = 场景中点 cam.transform.LookAt(new Vector3(midX, 500, 0)); // 看向 500m 高度 ``` ### 4.5 探测范围可视化 `DetectionEntity` 提供 `IsInRange(x, y, z, visibility, out effectiveRange)` 方法。如需绘制 3D 球冠范围,可从 `SensorSpec` 读取 `RadarRange`/`EORange`/`IRRange` 和 `MinElevation`/`MaxElevation`/`MinDetectAlt`/`MaxDetectAlt`,用 wireframe sphere 或 mesh 表示。 ### 4.6 管控区域可视化 `ControlZone` 的 `VerticesJson` 存储多边形顶点 JSON:`[{"x":0,"y":0,"z":0},...]`。配合 `MinAltitude`/`MaxAltitude` 构成 3D 棱柱区域。前端可用 `LineRenderer` 画底面多边形 + 垂直线段表示高度范围。 --- ## 五、Manager API 完整签名 所有 Manager 继承 `MonoBehaviour`,在 `Awake()` 中初始化内部服务。**必须在 `Awake` 之后(如 `Start`)才能调用**,`OnDisable` 后不可调用。 ### ScenarioManager ```csharp public IScenarioService Service { get; } public IDataService DataService { get; } // 基础数据 CRUD(7 类) // Scenario CRUD public Scenario CreateScenario(string name, string number); public Scenario UpdateScenario(Scenario s); public void DeleteScenario(string id); public ScenarioConfig GetDetail(string id); public PagedResult Search(string kw, string from, string to, int page, int size); // CombatScene public void SaveScene(string scenarioId, CombatScene s); public CombatScene GetScene(string scenarioId); // ControlZone public void SaveControlZones(string scenarioId, List z); public List GetControlZones(string scenarioId); public void DeleteControlZone(string id); // ScenarioDrone public ScenarioDrone SaveScenarioDrone(string scenarioId, ScenarioDrone d); public ScenarioDrone AddScenarioDrone(string scenarioId, ScenarioDrone d); public void UpdateScenarioDrone(ScenarioDrone d); public void DeleteScenarioDrone(string id); public List GetScenarioDrones(string scenarioId); // ScenarioUnit(部署) public void SaveDeployment(string scenarioId, List e); public ScenarioUnit AddDeploymentUnit(string scenarioId, ScenarioUnit u); public void UpdateDeploymentUnit(ScenarioUnit u); public void DeleteDeploymentUnit(string id); public List GetDeploymentUnits(string scenarioId); // Detection(探测设备,复用 ScenarioUnit) public void AddDetection(string scenarioId, ScenarioUnit d); public void DeleteDetection(string id); public List GetDetections(string scenarioId); // CloudDispersal public void SaveCloud(string scenarioId, CloudDispersal c); public CloudDispersal GetCloud(string scenarioId); public void DeleteCloud(string scenarioId); // Route & Waypoint public void SaveRoute(string scenarioId, string waveId, RoutePlan r, List w); public List GetRoutes(string scenarioId); public void DeleteRoute(string id); public List GetWaypoints(string scenarioId); public List GetWaypointsByWave(string scenarioId, string waveId); public void DeleteWaypoint(string id); // Misc public void UpdateStep(string scenarioId, int step); public EnumMetadata GetEnums(); // 枚举中英文对照(下拉框数据源) ``` ### IDataService(通过 `ScenarioManager.DataService` 访问) 7 类基础数据,每类 4 个方法(`GetAll*` / `Get*(id)` / `Save*(spec)` / `Delete*(id)`): | 基础数据类型 | 方法前缀 | 模型类 | |---|---|---| | 弹药 | `Ammo` | `AmmunitionSpec` | | 火力单元 | `FireUnit` | `FireUnitSpec` | | 无人机 | `Drone` | `DroneSpec` | | 传感器 | `Sensor` | `SensorSpec` | | 环境 | `Environment` | `EnvironmentSpec` | | 编队 | `Formation` | `FormationTemplate` | | 航线 | `Route` | `RouteTemplate` | ```csharp List GetAllDrones(); DroneSpec GetDrone(string id); void SaveDrone(DroneSpec spec); void DeleteDrone(string id); // 其余 6 类签名相同,替换前缀即可 ``` ### SimulationRunner ```csharp public FrameDataStore FrameStore { get; } public SimulationEngine Engine { get; } // 核心引擎 public IDataService DataService { get; set; } public void LoadAndStart(string scenarioId); public void Stop(); ``` 通过 `runner.Engine` 访问的成员: ```csharp // ── 状态 ── runner.Engine.State // SimulationState: Idle/Running/Paused/Stopped/Completed runner.Engine.TimeScale // float,时间倍率(默认 1,设 4 = 4 倍速) runner.Engine.SimulationTime // float,仿真累计时间(秒) runner.Engine.FrameIndex // int,当前帧序号 runner.Engine.RecordFrames // bool,是否录制帧数据(回放用),默认 true // ── 实体列表(IReadOnlyList,只读) ── runner.Engine.Drones // IReadOnlyList runner.Engine.Clouds // IReadOnlyList runner.Engine.Munitions // IReadOnlyList runner.Engine.Platforms // IReadOnlyList runner.Engine.DetectionEntities // IReadOnlyList runner.Engine.Events // IReadOnlyList(仿真期间持续追加) // ── 方法 ── runner.Engine.Tick(float dt) // → SimulationFrameResult(推进一帧) runner.Engine.Pause() // Running → Paused runner.Engine.Resume() // Paused → Running runner.Engine.Stop() // → Stopped + Flush 帧数据到数据库 // ── 事件(Action 委托) ── runner.Engine.OnMunitionLaunched // Action runner.Engine.OnCloudGenerated // Action runner.Engine.OnDroneDestroyed // Action runner.Engine.OnDroneReachedTarget // Action runner.Engine.OnZoneIntruded // Action runner.Engine.OnTargetDetected // Action runner.Engine.OnSimulationEnded // Action ``` ### ReportManager ```csharp public IReportService Service { get; } public SimulationReport Generate(string scenarioId, ScenarioConfig cfg, List events, string status, float duration); public SimulationReport Get(string id); public void Delete(string id); public PagedResult Search(string kw, string from, string to, int page, int size); public byte[] ExportReport(string reportId, string format); // "pdf" | "md" public string Export(string reportId, string outputDir, string format); // "pdf" | "md" public string Export(string reportId); // 默认 MD 到 reports 目录 ``` ### ReplayController ```csharp public int TotalFrames { get; } public int CurrentFrameIndex { get; } public List CurrentFrames { get; } public void LoadReplay(string scenarioId, FrameDataStore frameStore = null); public List GetFrame(int frameIndex); ``` > `LoadReplay` 优先用内存帧数据(仿真刚结束),无则从 SQLite 帧库加载(历史回放)。 ### ModelManager ```csharp public IModelService Service { get; } public ModelInfo Import(string filePath, string name); public ModelInfo Import(string filePath, string name, int entityType, string desc); public ModelInfo Add(ModelInfo model); public ModelInfo UpdateModel(ModelInfo model); public void Delete(string id); public List GetAll(); public ModelInfo Get(string id); ``` --- ## 六、枚举值清单 ### 6.1 有官方中文翻译的枚举(GetEnums() 返回) 这 11 个枚举通过 `scenario.GetEnums()` 获取中英文对照,可直接用于下拉框: ```csharp var enums = scenario.GetEnums(); // enums.DroneTypes → List { Name="Rotor", ChineseName="旋翼", Value=0 }, ... // enums.PowerTypes, enums.PlatformTypes, enums.AerosolTypes, // enums.WeatherTypes, enums.WindDirections, enums.SceneTypes, // enums.FormationModes, enums.TriggerModes, enums.ReleaseModes, enums.EquipmentRoles ``` | 枚举 | 成员 = 值 | 中文 | |------|----------|------| | **DroneType** | Rotor=0, FixedWing=1, HighSpeed=2 | 旋翼/固定翼/高速目标 | | **PowerType** | Electric=0, Piston=1, Jet=2 | 电推/活塞/喷气 | | **PlatformType** | AirBased=0, GroundBased=1 | 空基/地基 | | **AerosolType** | InertGas=0, ActiveMaterial=1, ActiveFuel=2 | 惰性气体(吸入式灭火)/活性材料(爆燃式)/活性燃料(吸入式爆炸) | | **WeatherType** | Sunny=0, Overcast=1, Fog=2, Rain=3, Night=4 | 晴/阴/雾/雨/夜 | | **WindDirection** | N=0, NE=1, E=2, SE=3, S=4, SW=5, W=6, NW=7 | 北/东北/东/东南/南/西南/西/西北 | | **SceneType** | Urban=0, Plain=1, Mountain=2, Coast=3 | 城市/平原/山区/海岸 | | **FormationMode** | Single=0, Formation=1, Swarm=2 | 单机/编队/蜂群 | | **TriggerMode** | Time=0, Area=1, Manual=2 | 时间触发/区域触发/手动触发 | | **ReleaseMode** | Single=0, Continuous=1, Pulse=2 | 单次齐射/连续释放/脉冲释放 | | **EquipmentRole** | Detection=0, LaunchPlatform=1 | 探测设备/发射平台 | ### 6.2 无官方翻译的枚举(前端需自行映射中文) | 枚举 | 命名空间 | 成员 = 值 | 含义 | |------|---------|----------|------| | **SimulationState** | `Simulation` | Idle=0, Running=1, Paused=2, Stopped=3, Completed=4 | 空闲/运行/暂停/停止/完成 | | **DroneStatus** | `Simulation` | Flying=0, Destroyed=1, ReachedTarget=2, ZoneIntruded=3 | 飞行中/已摧毁/到达目标/侵入管控区 | | **PlatformState** | `Simulation` | Idle=0, FlyingToTarget=1, ReadyToRelease=2 | 空闲/飞向目标/准备投放 | | **EntityType** | `Models` | Drone=0, Platform=1, DetectionEquip=2, Cloud=3, Munition=4 | 无人机/平台/探测设备/云团/弹药 | | **SimEventType** | `Models` | TargetDetected=0, MunitionLaunched=1, CloudGenerated=2, DroneEnteredCloud=3, DroneDestroyed=4, DroneReachedTarget=5, ZoneIntruded=6, WaypointReached=7, SimulationEnd=8, PlanningFailed=9 | 目标发现/弹药发射/云团生成/进入云团/摧毁/到达目标/侵入管控区/到达航点/仿真结束/规划失败 | | **InterceptResult** | `Models` | Success=0, Partial=1, Failed=2 | 成功拦截/部分拦截/拦截失败 | | **DamageStage** | `Models` | Normal=0, EngineAnomaly=1, AttitudeLoss=2, Destroyed=3 | 正常/引擎异常/姿态丧失/摧毁 | | **ScenarioStatus** | `Models` | Draft=0, Configuring=1, Completed=2 | 草稿/配置中/已完成 | > **EntitySnapshot.EntityType** 用的是 `EntityType` 枚举(int),判断实体类型时用 `(EntityType)snap.EntityType` 或直接比较 int 值。 --- ## 七、关键数据结构 ### EntitySnapshot(每帧推送) | 字段 | 类型 | 说明 | |------|------|------| | `EntityId` | string | 实体唯一 ID(属性) | | `EntityType` | EntityType | Drone=0/Platform=1/DetectionEquip=2/Cloud=3/Munition=4(属性) | | `PosX/Y/Z` | float | 三维位置(Y=高度,米) | | `RotX/Y/Z` | float | 旋转 | | `VelX/Y/Z` | float | 瞬时速度 (m/s) | | `Hp` | float | 无人机血量 (0~1) | | `DamageStage` | int | 毁伤阶段(0正常/1引擎异常/2姿态丧失/3摧毁) | | `PlatformStateStr` | string? | 平台状态:Idle/FlyingToTarget/ReadyToRelease | | `CloudRadius` | float | 云团有效半径(米) | | `CloudOpacity` | float | 不透明度 (0~1) | | `CloudPhase` | int | 扩散阶段 (1/2/3) | | `CloudElapsed` | float | 云团已存在时间 (s) | | `ModelId` | string? | 3D 模型 ID(Unity 实例化用) | > 除 `EntityId`/`EntityType` 是属性外,其余均为**公共字段**(非属性)。 ### SimEvent(仿真事件) ```csharp public class SimEvent { public SimEventType Type { get; set; } // 事件类型(见枚举表) public float OccurredAt { get; set; } // 发生时刻(仿真秒) public string SourceId { get; set; } // 触发实体 ID public string TargetId { get; set; } // 目标实体 ID public string DataJson { get; set; } // 扩展数据(JSON) public string Description { get; set; } // 人类可读描述 } ``` ### SimulationFrameResult(Tick 返回值) ```csharp public class SimulationFrameResult { public List EntitySnapshots { get; set; } // 本帧所有实体快照 public List NewEvents { get; set; } // 本帧新事件 public SimulationState State { get; set; } // 当前仿真状态 public int FrameIndex { get; set; } // 帧序号 public float SimulationTime { get; set; } // 仿真累计时间 } ``` ### PagedResult<T>(分页查询返回值) ```csharp public class PagedResult { public List Items { get; set; } // 当前页数据 public int TotalCount { get; set; } // 总记录数 public int Page { get; set; } // 当前页码(从 1 开始) public int PageSize { get; set; } // 每页条数 public int TotalPages { get; } // 总页数(计算属性) } ``` ### EnumMetadata / EnumItem(GetEnums 返回值) ```csharp public class EnumItem { public string Name { get; set; } // 英文名 public string ChineseName { get; set; } // 中文名 public int Value { get; set; } // 枚举值 } public class EnumMetadata { public List DroneType { get; set; } public List PowerType { get; set; } public List PlatformType { get; set; } public List AerosolType { get; set; } public List WeatherType { get; set; } public List WindDirection { get; set; } public List SceneType { get; set; } public List FormationMode { get; set; } public List TriggerMode { get; set; } public List ReleaseMode { get; set; } public List EquipmentRole { get; set; } } ``` ### SimulationReport | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 报告 ID(主键) | | `ScenarioId` | string | 想定 ID | | `ScenarioName` | string | 想定名称 | | `ScenarioNumber` | string | 想定编号 | | `CompletedAt` | string | 完成时间(UTC ISO 8601) | | `DroneCount` | int | 无人机总数 | | `UnitCount` | int | 装备总数 | | `InterceptResult` | int | 拦截结果(0成功/1部分/2失败) | | `Content` | string | Markdown 报告文本(快速展示用) | | `ReportDataJson` | string? | 结构化数据 JSON(PDF 导出用) | --- ## 八、运行时实体属性 仿真运行时通过 `runner.Engine.Drones` / `Clouds` / `Munitions` / `Platforms` / `DetectionEntities` 直接访问。 | 实体 | 关键属性 | |------|---------| | **DroneEntity** | Id, PosX/Y/Z, Hp, Status(DroneStatus), DroneType, PowerType, Wingspan, CruiseSpeed, Route, TraveledArc, TotalArc, Progress, ModelId | | **CloudEntity** | Id, PosX/Y/Z, Radius, Density, Phase(1/2/3), Elapsed, IsDissipated, AerosolType | | **MunitionEntity** | Id, PosX/Y/Z, Velocity(Vx,Vy,Vz), StartX/Y/Z, LaunchTime, ElapsedTime, LaunchAngle, Azimuth, MuzzleVelocity, FlightDuration, TargetX/Y/Z, HasArrived | | **PlatformEntity** | Id, PosX/Y/Z, CurrentVelocity, State(PlatformState), MunitionCount, CooldownRemaining, MuzzleVelocity, CruiseSpeed, ReleaseAltitude, TargetX/Y/Z, FlightDistance, Ready, CanRelease | | **DetectionEntity** | Id, PosX/Y/Z, Source, IsInRange(x,y,z,visibility,out range), IsDetected(droneId), ModelId | | **ControlZoneEntity** | Id, Name, Vertices(List\), MinAltitude, MaxAltitude, ContainsPoint(x,y,z) | --- ## 九、核心模型完整字段 ### 9.1 ScenarioConfig(想定配置聚合根 — GetDetail 返回值) ``` ScenarioConfig Info: Scenario // 想定主表 Scene: CombatScene // 步骤1:作战环境 ControlZones: List // 步骤1:管控区域 Drones: List // 步骤2:威胁目标 Units: List // 步骤3:我方部署(含探测+发射平台) Cloud: CloudDispersal // 步骤4:云团抛撒配置 Routes: List // 步骤5:航路规划(多批次) WaypointGroups: Dictionary> // 按 WaveId 分组的航路点 ``` ### 9.2 Scenario(想定主表) | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `Id` | string | GUID | 主键 | | `Name` | string | "" | 想定名称 | | `ScenarioNumber` | string | "" | 想定编号(唯一) | | `Description` | string | "" | 描述 | | `Status` | int | 0 | 0=草稿 1=配置中 2=已完成 | | `CurrentStep` | int | 1 | 当前配置步骤(1~5) | | `TickRate` | int | 20 | 仿真帧率 | | `CreatedAt` | string | UTC ISO | 创建时间 | | `UpdatedAt` | string | UTC ISO | 更新时间 | ### 9.3 CombatScene(步骤 1:作战环境) | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `ScenarioId` | string | "" | 主键 = 想定 ID | | `SceneType` | int | 1(Plain) | 0=城市 1=平原 2=山区 3=海岸 | | `TimeOfDay` | string | "12:00" | 时间段 | | `WeatherType` | int | 0(Sunny) | 0=晴 1=阴 2=雾 3=雨 4=夜 | | `WindSpeed` | double | 5.0 | 风速 m/s | | `WindDirection` | int | 0(N) | 0~7 = N/NE/E/SE/S/SW/W/NW | | `Temperature` | double | 20.0 | 温度 °C | | `Humidity` | double | 60.0 | 湿度 %RH | | `Pressure` | double | 1013.0 | 气压 hPa | | `Visibility` | double | 5000.0 | 能见度 m | | `SceneWidth` | double | 4000.0 | 场景宽 m | | `SceneLength` | double | 10000.0 | 场景长 m | | `SceneHeight` | double | 1000.0 | 场景高 m | ### 9.4 ControlZone(管控区域) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `ScenarioId` | string | 想定 ID | | `Name` | string | 区域名称 | | `VerticesJson` | string | 多边形顶点 JSON:`[{"x":0,"y":0,"z":0},...]` | | `MinAltitude` | double | 高度下限 m | | `MaxAltitude` | double | 高度上限 m | | `OrderIndex` | int | 排序序号 | ### 9.5 ScenarioDrone(步骤 2:威胁目标) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `ScenarioId` | string | 想定 ID | | `DroneSpecId` | string | FK → DroneSpec | | `WaveId` | string | 批次 ID(如 "w1") | | `Quantity` | int | 数量 | ### 9.6 ScenarioUnit(步骤 3:我方部署) | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `Id` | string | GUID | 主键 | | `ScenarioId` | string | "" | 想定 ID | | `EquipmentRole` | int | 1 | 0=探测设备 1=发射平台 | | `LaunchPlatformSpecId` | string | "" | FK → LaunchPlatformSpec(发射平台时填) | | `SensorSpecId` | string | "" | FK → SensorSpec(探测设备时填) | | `Quantity` | int | 1 | 数量 | | `PositionX/Y/Z` | double | 0 | 部署位置(Y=高度,米) | | `AerosolType` | int? | null | 挂载弹药类型(0/1/2) | | `MunitionCount` | int? | null | 弹药数量 | | `WaveId` | string | "" | 关联批次 | | `Description` | string | "" | 备注 | | `Source` | int | 0 | 0=手动 1=算法推荐 | ### 9.7 CloudDispersal(步骤 4:云团抛撒配置) | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `ScenarioId` | string | "" | 主键 = 想定 ID | | `AerosolType` | int | 0 | 0=惰性气体 1=活性材料 2=活性燃料 | | `DisperseHeight` | double | 300.0 | 抛撒高度 m | | `TriggerMode` | int | 0 | 0=时间 1=区域 2=手动 | | `SpreadAngle` | double | 0 | 扩散方向 ° | | `ReleaseMode` | int | 0 | 0=单次 1=连续 2=脉冲 | | `InitialScale` | double | 1000.0 | 初始规模 m³ | | `Duration` | double | 60.0 | 持续时间 s | | `ReleaseInterval` | double | 5.0 | 释放间隔 s | | `TotalAmount` | double | 50.0 | 释放总量 kg | | `PositionX/Y/Z` | double | 0 | 抛撒位置 | | `PositionMode` | int | 1 | 0=点选 1=手动输入 2=算法推荐 | | `Source` | string | "Manual" | "Manual" 或 "Algorithm" | | `SalvoRounds` | int | 0 | 推荐弹药数(算法填充) | | `SalvoSpacing` | double | 0 | 云团间距 m(算法填充) | | `EstimatedProbability` | double? | null | 算法估计拦截概率 | | `RecommendedTiming` | double? | null | 推荐抛撒时机 s | | `RecommendedPosX/Y/Z` | double? | null | 推荐抛撒位置 | | `CriticalPosX/Y/Z` | double? | null | 关键拦截位置 | | `CriticalTiming` | double? | null | 关键拦截时机 s | ### 9.8 RoutePlan(步骤 5:航路规划) | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `Id` | string | GUID | 主键 | | `ScenarioId` | string | "" | 想定 ID | | `WaveId` | string | "" | 批次 ID | | `FormationMode` | int | 0 | 0=单机 1=编队 2=蜂群 | | `LateralSpacing` | double | 50.0 | 横向间距 m | | `LateralCount` | int? | null | 横向架数(null=全部) | | `LongitudinalCount` | int? | null | 纵深架数(null=1) | | `LongitudinalSpacing` | double | 50.0 | 纵向间距 m | | `LateralAxis` | int | 2 | 横向展开轴:0=X 1=Y(垂直) 2=Z(默认) | | `LongitudinalAxis` | int | 0 | 纵向串列轴:0=X(默认) 1=Y 2=Z | | `ETA` | string | "" | 预计到达时间 | ### 9.9 Waypoint(航路点) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `ScenarioId` | string | 想定 ID | | `WaveId` | string | 批次 ID | | `OrderIndex` | int | 顺序索引(从 0 开始) | | `PosX` | double | X 坐标 m | | `PosY` | double | Y 坐标 = 高度 m | | `PosZ` | double | Z 坐标 m | | `Altitude` | double | 高度 m(与 PosY 冗余) | | `Speed` | double | 该段速度 **km/h** | --- ## 十、基础数据模型完整字段 ### 10.1 DroneSpec(无人机模板) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `Name` | string | 名称 | | `DroneType` | int | 0=旋翼 1=固定翼 2=高速 | | `Model` | string | 型号名称 | | `Description` | string | 描述 | | `PowerType` | int | 0=电推 1=活塞 2=喷气 | | `Wingspan` | double | 翼展 m | | `TypicalSpeed` | double | 典型速度 km/h | | `TypicalAltitude` | double | 典型高度 m | | `ModelId` | string | 3D 模型 ID(FK → ModelInfo) | ### 10.2 LaunchPlatformSpec(发射平台模板) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `Name` | string | 名称 | | `Description` | string | 描述 | | `PlatformType` | int | 0=空基 1=地基 | | `GunCount` | int | 火炮数量 | | `ChannelsPerGun` | int | 每炮通道数 | | `ChannelInterval` | double | 同通道发射间隔 s | | `Cooldown` | double | 射击冷却 s | | `AmmoChangeTime` | double | 换弹时间 s | | `MuzzleVelocity` | double | 初速 m/s | | `CruiseSpeed` | double | 巡航速度 m/s(空基) | | `ReleaseAltitude` | double | 释放高度 m(空基) | | `ModelId` | string | 3D 模型 ID | ### 10.3 SensorSpec(传感器模板) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `Name` | string | 名称 | | `RadarRange` | double | 雷达探测距离 m(0=无) | | `EORange` | double | 光电探测距离 m | | `IRRange` | double | 红外探测距离 m | | `Accuracy` | double | 探测精度(位置误差 m) | | `MinElevation` | double? | 最小仰角 | | `MaxElevation` | double? | 最大仰角 | | `MinDetectAlt` | double? | 最小可探测高度 m | | `MaxDetectAlt` | double? | 最大可探测高度 m | | `ModelId` | string | 3D 模型 ID | ### 10.4 AmmunitionSpec(弹药模板) | 字段 | 类型 | 说明 | |------|------|------| | `Id` | string | 主键 | | `AerosolType` | int | 0=惰性气体 1=活性材料 2=活性燃料 | | `Name` | string | 名称 | | `InitialRadius` | double | 初始半径 m | | `InitialVolume` | double | 初始体积 m³ | | `CoreDensity` | double | 核心密度 | | `EdgeDensity` | double | 边缘密度 | | `InitialTemperature` | double | 初始温度 | | `BuoyancyFactor` | double | 浮力系数 | | `EffectiveConcentration` | double | 有效浓度 | | `SourceStrength` | double | 源强 Q (kg) | | `DispersionRateBase` | double | 基础扩散速率 m/s | | `BurstChargeKg` | double | 爆发药 TNT 当量 kg | | `TurbulentExpansionK` | double | 湍流扩散系数 | | `Phase2Duration` | double | Phase 2 持续时间 s | | `MaxRadius` | double | 最大半径 m | | `MaxDuration` | double | 最大持续时间 s | | `ParticlesJson` | string | 粒子渲染参数 JSON | ### 10.5 EnvironmentSpec / FormationTemplate / RouteTemplate / ModelInfo | 模型 | 关键字段 | |------|---------| | **EnvironmentSpec** | Id, Name, WeatherType, WindSpeed, WindDirection, Temperature, Humidity, Pressure, Visibility | | **FormationTemplate** | Id, Name, FormationMode, LateralCount, LongitudinalCount, LateralSpacing, LongitudinalSpacing, LateralAxis, LongitudinalAxis | | **RouteTemplate** | Id, Name, WaypointsJson(`[{"x":0,"y":0,"z":0},...]`) | | **ModelInfo** | Id, Name, EntityType(0=Drone/1=Platform/2=DetectionEquip), Description, FilePath, FileSize, PreviewPath, HasHighResTexture, CreatedAt | --- ## 十一、默认数据 首次运行自动种子,含 6 个 `[Demo]` 预设想定: | 类别 | 示例 ID | |------|---------| | 弹药 | `inert` / `active` / `fuel` | | 编队 | `single` / `line-3` / `swarm-10` | | 航线 | `5km-h500` / `10km-h500` / `20km-h500` | | 火力单元 | `ground-light` / `air-standard` | | 无人机 | `shahed` / `quadcopter` / `cruise-missile` | | 传感器 | `radar-mr` / `eo-station` | | 环境 | `sunny-calm` / `fog` / `night` | --- ## 十二、参考 | 文档 | 位置 | |------|------| | 架构设计 | `docs/design/architecture/总体架构设计.md` | | 实体事件映射 | `docs/design/technical/仿真器实体与事件映射.md` | | 测试状态 | **262 测试,15 秒(全部通过)** |