新增 LaunchPlatformSpec:发射平台与探测设备分离
- LaunchPlatformSpec(纯发射参数,无探测字段) - ScenarioUnit.FireUnitSpecId → LaunchPlatformSpecId - PlatformEntity/BuildFireUnits/BuildDetectionSources 适配 - ReportGenerator/ReportService 适配 - FireUnitSpec 保留但不使用 - 243/250 通过,7 个待修
This commit is contained in:
parent
8abaf0bf87
commit
8a198a27a0
@ -118,6 +118,38 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"launchPlatforms": [
|
||||||
|
{
|
||||||
|
"Id": "ground-light", "Name": "[Demo] 轻型地基发射平台",
|
||||||
|
"Description": "4通道轻型平台,800m/s初速",
|
||||||
|
"PlatformType": 1, "GunCount": 4, "ChannelsPerGun": 4, "ChannelInterval": 0.1,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0, "MuzzleVelocity": 800.0,
|
||||||
|
"AmmoTypes": [0, 1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "ground-standard", "Name": "[Demo] 标准地基发射平台",
|
||||||
|
"Description": "4通道标准平台,800m/s初速",
|
||||||
|
"PlatformType": 1, "GunCount": 4, "ChannelsPerGun": 4, "ChannelInterval": 0.1,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0, "MuzzleVelocity": 800.0,
|
||||||
|
"AmmoTypes": [0, 1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "ground-heavy", "Name": "[Demo] 重型地基发射平台",
|
||||||
|
"Description": "6通道重型平台,600m/s初速,支持全弹种",
|
||||||
|
"PlatformType": 1, "GunCount": 6, "ChannelsPerGun": 4, "ChannelInterval": 1.0,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0, "MuzzleVelocity": 600.0,
|
||||||
|
"AmmoTypes": [0, 1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "air-standard", "Name": "[Demo] 标准空基发射平台",
|
||||||
|
"Description": "8通道空基平台,80m/s巡航",
|
||||||
|
"PlatformType": 0, "GunCount": 1, "ChannelsPerGun": 8, "ChannelInterval": 1.0,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0,
|
||||||
|
"MuzzleVelocity": 80.0, "CruiseSpeed": 80.0, "ReleaseAltitude": 1000.0,
|
||||||
|
"AmmoTypes": [0, 1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
"drones": [
|
"drones": [
|
||||||
{ "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)",
|
{ "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)",
|
||||||
"Model": "DJI Mavic 类", "Description": "小型四旋翼,低空侦察",
|
"Model": "DJI Mavic 类", "Description": "小型四旋翼,低空侦察",
|
||||||
|
|||||||
@ -63,6 +63,7 @@ namespace CounterDrone.Core
|
|||||||
// 插入或更新默认数据(按 Id 覆盖,不删除用户自建数据)
|
// 插入或更新默认数据(按 Id 覆盖,不删除用户自建数据)
|
||||||
foreach (var a in defaults.Ammunition) db.InsertOrReplace(a);
|
foreach (var a in defaults.Ammunition) db.InsertOrReplace(a);
|
||||||
foreach (var f in defaults.FireUnits) db.InsertOrReplace(f);
|
foreach (var f in defaults.FireUnits) db.InsertOrReplace(f);
|
||||||
|
foreach (var l in defaults.LaunchPlatforms) db.InsertOrReplace(l);
|
||||||
foreach (var d in defaults.Drones) db.InsertOrReplace(d);
|
foreach (var d in defaults.Drones) db.InsertOrReplace(d);
|
||||||
foreach (var s in defaults.Sensors) db.InsertOrReplace(s);
|
foreach (var s in defaults.Sensors) db.InsertOrReplace(s);
|
||||||
foreach (var e in defaults.Environments) db.InsertOrReplace(e);
|
foreach (var e in defaults.Environments) db.InsertOrReplace(e);
|
||||||
@ -118,6 +119,7 @@ namespace CounterDrone.Core
|
|||||||
db.CreateTable<Waypoint>();
|
db.CreateTable<Waypoint>();
|
||||||
db.CreateTable<SimulationReport>();
|
db.CreateTable<SimulationReport>();
|
||||||
db.CreateTable<FireUnitSpec>();
|
db.CreateTable<FireUnitSpec>();
|
||||||
|
db.CreateTable<LaunchPlatformSpec>();
|
||||||
db.CreateTable<DroneSpec>();
|
db.CreateTable<DroneSpec>();
|
||||||
db.CreateTable<SensorSpec>();
|
db.CreateTable<SensorSpec>();
|
||||||
db.CreateTable<EnvironmentSpec>();
|
db.CreateTable<EnvironmentSpec>();
|
||||||
|
|||||||
@ -19,6 +19,8 @@ namespace CounterDrone.Core
|
|||||||
public List<RouteTemplate> Routes { get; set; } = new();
|
public List<RouteTemplate> Routes { get; set; } = new();
|
||||||
[System.Text.Json.Serialization.JsonPropertyName("fireUnits")]
|
[System.Text.Json.Serialization.JsonPropertyName("fireUnits")]
|
||||||
public List<FireUnitSpec> FireUnits { get; set; } = new();
|
public List<FireUnitSpec> FireUnits { get; set; } = new();
|
||||||
|
[System.Text.Json.Serialization.JsonPropertyName("launchPlatforms")]
|
||||||
|
public List<LaunchPlatformSpec> LaunchPlatforms { get; set; } = new();
|
||||||
[System.Text.Json.Serialization.JsonPropertyName("drones")]
|
[System.Text.Json.Serialization.JsonPropertyName("drones")]
|
||||||
public List<DroneSpec> Drones { get; set; } = new();
|
public List<DroneSpec> Drones { get; set; } = new();
|
||||||
[System.Text.Json.Serialization.JsonPropertyName("detectionEquipment")]
|
[System.Text.Json.Serialization.JsonPropertyName("detectionEquipment")]
|
||||||
@ -59,6 +61,8 @@ namespace CounterDrone.Core
|
|||||||
throw new InvalidOperationException($"默认数据缺少 routes: {source}");
|
throw new InvalidOperationException($"默认数据缺少 routes: {source}");
|
||||||
if (data.FireUnits == null || data.FireUnits.Count == 0)
|
if (data.FireUnits == null || data.FireUnits.Count == 0)
|
||||||
throw new InvalidOperationException($"默认数据缺少 fireUnits: {source}");
|
throw new InvalidOperationException($"默认数据缺少 fireUnits: {source}");
|
||||||
|
if (data.LaunchPlatforms == null || data.LaunchPlatforms.Count == 0)
|
||||||
|
throw new InvalidOperationException($"默认数据缺少 launchPlatforms: {source}");
|
||||||
if (data.Drones == null || data.Drones.Count == 0)
|
if (data.Drones == null || data.Drones.Count == 0)
|
||||||
throw new InvalidOperationException($"默认数据缺少 drones: {source}");
|
throw new InvalidOperationException($"默认数据缺少 drones: {source}");
|
||||||
if (data.Environments == null || data.Environments.Count == 0)
|
if (data.Environments == null || data.Environments.Count == 0)
|
||||||
|
|||||||
@ -38,7 +38,7 @@ namespace CounterDrone.Core.Models
|
|||||||
{
|
{
|
||||||
return new ScenarioUnit
|
return new ScenarioUnit
|
||||||
{
|
{
|
||||||
FireUnitSpecId = Id,
|
LaunchPlatformSpecId = Id,
|
||||||
EquipmentRole = (int)Models.EquipmentRole.LaunchPlatform,
|
EquipmentRole = (int)Models.EquipmentRole.LaunchPlatform,
|
||||||
Quantity = quantity,
|
Quantity = quantity,
|
||||||
PositionX = posX,
|
PositionX = posX,
|
||||||
|
|||||||
44
src/CounterDrone.Core/Models/LaunchPlatformSpec.cs
Normal file
44
src/CounterDrone.Core/Models/LaunchPlatformSpec.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using CounterDrone.Core.Models;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace CounterDrone.Core.Models
|
||||||
|
{
|
||||||
|
/// <summary>搭载/发射平台规格(基础数据模板)</summary>
|
||||||
|
[Table("LaunchPlatformSpec")]
|
||||||
|
public class LaunchPlatformSpec
|
||||||
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
public string Id { get; set; } = "";
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public int PlatformType { get; set; }
|
||||||
|
public int GunCount { get; set; } = 1;
|
||||||
|
public int ChannelsPerGun { get; set; } = 1;
|
||||||
|
public double ChannelInterval { get; set; } = 1.0;
|
||||||
|
public double Cooldown { get; set; } = 5.0;
|
||||||
|
public double AmmoChangeTime { get; set; } = 30.0;
|
||||||
|
public double MuzzleVelocity { get; set; }
|
||||||
|
public double CruiseSpeed { get; set; }
|
||||||
|
public double ReleaseAltitude { get; set; }
|
||||||
|
public string ModelId { get; set; } = "";
|
||||||
|
[Ignore]
|
||||||
|
public List<int> AmmoTypes { get; set; } = new();
|
||||||
|
|
||||||
|
public ScenarioUnit ToScenarioUnit(AerosolType ammoType, int quantity,
|
||||||
|
double posX, double posY, double posZ)
|
||||||
|
{
|
||||||
|
return new ScenarioUnit
|
||||||
|
{
|
||||||
|
LaunchPlatformSpecId = Id,
|
||||||
|
EquipmentRole = (int)Models.EquipmentRole.LaunchPlatform,
|
||||||
|
Quantity = quantity,
|
||||||
|
PositionX = posX,
|
||||||
|
PositionY = posY,
|
||||||
|
PositionZ = posZ,
|
||||||
|
AerosolType = (int)ammoType,
|
||||||
|
MunitionCount = GunCount * ChannelsPerGun * quantity,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,8 +14,8 @@ namespace CounterDrone.Core.Models
|
|||||||
[Indexed]
|
[Indexed]
|
||||||
public string ScenarioId { get; set; } = string.Empty;
|
public string ScenarioId { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>外键 → FireUnitSpec(发射平台)</summary>
|
/// <summary>外键 → LaunchPlatformSpec(发射平台)</summary>
|
||||||
public string FireUnitSpecId { get; set; } = string.Empty;
|
public string LaunchPlatformSpecId { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>外键 → SensorSpec(探测设备)</summary>
|
/// <summary>外键 → SensorSpec(探测设备)</summary>
|
||||||
public string SensorSpecId { get; set; } = string.Empty;
|
public string SensorSpecId { get; set; } = string.Empty;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -13,7 +13,7 @@ namespace CounterDrone.Core.Services
|
|||||||
public string Generate(ScenarioConfig config, List<SimEvent> events,
|
public string Generate(ScenarioConfig config, List<SimEvent> events,
|
||||||
Simulation.DroneStatus finalDroneStatus, float simulationDuration,
|
Simulation.DroneStatus finalDroneStatus, float simulationDuration,
|
||||||
Dictionary<string, DroneSpec> droneSpecs,
|
Dictionary<string, DroneSpec> droneSpecs,
|
||||||
Dictionary<string, FireUnitSpec> fireUnitSpecs,
|
Dictionary<string, LaunchPlatformSpec> fireUnitSpecs,
|
||||||
Dictionary<string, SensorSpec> sensorSpecs)
|
Dictionary<string, SensorSpec> sensorSpecs)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
@ -116,7 +116,7 @@ namespace CounterDrone.Core.Services
|
|||||||
{
|
{
|
||||||
var eq = config.Units[ei];
|
var eq = config.Units[ei];
|
||||||
if (eq.EquipmentRole != (int)EquipmentRole.LaunchPlatform) continue;
|
if (eq.EquipmentRole != (int)EquipmentRole.LaunchPlatform) continue;
|
||||||
fireUnitSpecs.TryGetValue(eq.FireUnitSpecId, out var fuSpec);
|
fireUnitSpecs.TryGetValue(eq.LaunchPlatformSpecId, out var fuSpec);
|
||||||
int channels = (fuSpec?.GunCount ?? 1) * (fuSpec?.ChannelsPerGun ?? 1);
|
int channels = (fuSpec?.GunCount ?? 1) * (fuSpec?.ChannelsPerGun ?? 1);
|
||||||
for (int j = 0; j < eq.Quantity; j++)
|
for (int j = 0; j < eq.Quantity; j++)
|
||||||
{
|
{
|
||||||
@ -141,7 +141,7 @@ namespace CounterDrone.Core.Services
|
|||||||
int unitNum2 = 0;
|
int unitNum2 = 0;
|
||||||
foreach (var eq in config.Units.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform))
|
foreach (var eq in config.Units.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform))
|
||||||
{
|
{
|
||||||
fireUnitSpecs.TryGetValue(eq.FireUnitSpecId, out var fuSpec);
|
fireUnitSpecs.TryGetValue(eq.LaunchPlatformSpecId, out var fuSpec);
|
||||||
int channels = (fuSpec?.GunCount ?? 1) * (fuSpec?.ChannelsPerGun ?? 1);
|
int channels = (fuSpec?.GunCount ?? 1) * (fuSpec?.ChannelsPerGun ?? 1);
|
||||||
for (int j = 0; j < eq.Quantity; j++)
|
for (int j = 0; j < eq.Quantity; j++)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -24,7 +24,7 @@ namespace CounterDrone.Core.Services
|
|||||||
List<SimEvent> events, string finalDroneStatus, float duration)
|
List<SimEvent> events, string finalDroneStatus, float duration)
|
||||||
{
|
{
|
||||||
var droneSpecs = _db.Table<DroneSpec>().ToDictionary(d => d.Id);
|
var droneSpecs = _db.Table<DroneSpec>().ToDictionary(d => d.Id);
|
||||||
var fireUnitSpecs = _db.Table<FireUnitSpec>().ToDictionary(f => f.Id);
|
var fireUnitSpecs = _db.Table<LaunchPlatformSpec>().ToDictionary(f => f.Id);
|
||||||
var sensorSpecs = _db.Table<SensorSpec>().ToDictionary(s => s.Id);
|
var sensorSpecs = _db.Table<SensorSpec>().ToDictionary(s => s.Id);
|
||||||
|
|
||||||
var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed);
|
var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed);
|
||||||
|
|||||||
@ -49,7 +49,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
/// <summary>Ready 包含:冷却就绪 + 有弹药 + 非飞行中</summary>
|
/// <summary>Ready 包含:冷却就绪 + 有弹药 + 非飞行中</summary>
|
||||||
public bool Ready => CooldownRemaining <= 0 && MunitionCount > 0 && State != PlatformState.FlyingToTarget;
|
public bool Ready => CooldownRemaining <= 0 && MunitionCount > 0 && State != PlatformState.FlyingToTarget;
|
||||||
|
|
||||||
public PlatformEntity(string id, FireUnitSpec spec, ScenarioUnit deployment)
|
public PlatformEntity(string id, LaunchPlatformSpec spec, ScenarioUnit deployment)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
Role = (EquipmentRole)deployment.EquipmentRole;
|
Role = (EquipmentRole)deployment.EquipmentRole;
|
||||||
|
|||||||
@ -50,7 +50,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
private float _disperseHeight;
|
private float _disperseHeight;
|
||||||
private AmmunitionSpec _ammoSpec = new();
|
private AmmunitionSpec _ammoSpec = new();
|
||||||
private Dictionary<string, DroneSpec> _droneSpecs = new();
|
private Dictionary<string, DroneSpec> _droneSpecs = new();
|
||||||
private Dictionary<string, FireUnitSpec> _fireUnitSpecs = new();
|
private Dictionary<string, LaunchPlatformSpec> _launchPlatformSpecs = new();
|
||||||
private Dictionary<string, SensorSpec> _sensorSpecs = new();
|
private Dictionary<string, SensorSpec> _sensorSpecs = new();
|
||||||
private int _tickRate = 20;
|
private int _tickRate = 20;
|
||||||
private readonly List<FireEvent> _fireSchedule = new();
|
private readonly List<FireEvent> _fireSchedule = new();
|
||||||
@ -102,7 +102,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
_ammoSpec = specDb.Table<AmmunitionSpec>()
|
_ammoSpec = specDb.Table<AmmunitionSpec>()
|
||||||
.FirstOrDefault(a => a.AerosolType == config.Cloud.AerosolType);
|
.FirstOrDefault(a => a.AerosolType == config.Cloud.AerosolType);
|
||||||
_droneSpecs = specDb.Table<DroneSpec>().ToDictionary(d => d.Id);
|
_droneSpecs = specDb.Table<DroneSpec>().ToDictionary(d => d.Id);
|
||||||
_fireUnitSpecs = specDb.Table<FireUnitSpec>().ToDictionary(f => f.Id);
|
_launchPlatformSpecs = specDb.Table<LaunchPlatformSpec>().ToDictionary(f => f.Id);
|
||||||
_sensorSpecs = specDb.Table<SensorSpec>().ToDictionary(s => s.Id);
|
_sensorSpecs = specDb.Table<SensorSpec>().ToDictionary(s => s.Id);
|
||||||
}
|
}
|
||||||
if (_ammoSpec == null || _ammoSpec.Id == null)
|
if (_ammoSpec == null || _ammoSpec.Id == null)
|
||||||
@ -139,7 +139,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
{
|
{
|
||||||
if (equip.EquipmentRole != (int)EquipmentRole.Detection)
|
if (equip.EquipmentRole != (int)EquipmentRole.Detection)
|
||||||
{
|
{
|
||||||
if (!_fireUnitSpecs.TryGetValue(equip.FireUnitSpecId, out var fuSpec)) continue;
|
if (!_launchPlatformSpecs.TryGetValue(equip.LaunchPlatformSpecId, out var fuSpec)) continue;
|
||||||
for (int i = 0; i < equip.Quantity; i++)
|
for (int i = 0; i < equip.Quantity; i++)
|
||||||
{
|
{
|
||||||
int gunCount = fuSpec.GunCount;
|
int gunCount = fuSpec.GunCount;
|
||||||
@ -158,7 +158,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
|
|
||||||
// 探测设备运行时实体
|
// 探测设备运行时实体
|
||||||
_detectionEntities.Clear();
|
_detectionEntities.Clear();
|
||||||
var detectionSrcs = BuildDetectionSources(config, _fireUnitSpecs, _sensorSpecs);
|
var detectionSrcs = BuildDetectionSources(config, _sensorSpecs);
|
||||||
int detIdx = 0;
|
int detIdx = 0;
|
||||||
foreach (var src in detectionSrcs)
|
foreach (var src in detectionSrcs)
|
||||||
_detectionEntities.Add(new DetectionEntity($"det_{++detIdx}", src, src.ModelId));
|
_detectionEntities.Add(new DetectionEntity($"det_{++detIdx}", src, src.ModelId));
|
||||||
@ -174,11 +174,11 @@ namespace CounterDrone.Core.Simulation
|
|||||||
// 自动从 Planner 生成发射计划
|
// 自动从 Planner 生成发射计划
|
||||||
if (_fireSchedule.Count == 0)
|
if (_fireSchedule.Count == 0)
|
||||||
{
|
{
|
||||||
var fireUnits = BuildFireUnits(config, _fireUnitSpecs);
|
var fireUnits = BuildFireUnits(config, _launchPlatformSpecs);
|
||||||
var threats = BuildDroneWaves(config, _droneSpecs);
|
var threats = BuildDroneWaves(config, _droneSpecs);
|
||||||
if (fireUnits.Count > 0 && threats.Count > 0)
|
if (fireUnits.Count > 0 && threats.Count > 0)
|
||||||
{
|
{
|
||||||
var detectionSources = BuildDetectionSources(config, _fireUnitSpecs, _sensorSpecs);
|
var detectionSources = BuildDetectionSources(config, _sensorSpecs);
|
||||||
var result = _planner.Plan(fireUnits, threats, _scene, detectionSources);
|
var result = _planner.Plan(fireUnits, threats, _scene, detectionSources);
|
||||||
SetFireSchedule(result.Best.MergedSchedule);
|
SetFireSchedule(result.Best.MergedSchedule);
|
||||||
if (_fireSchedule.Count == 0)
|
if (_fireSchedule.Count == 0)
|
||||||
@ -440,12 +440,12 @@ namespace CounterDrone.Core.Simulation
|
|||||||
public void Resume() { if (State == SimulationState.Paused) State = SimulationState.Running; }
|
public void Resume() { if (State == SimulationState.Paused) State = SimulationState.Running; }
|
||||||
public void Stop() { State = SimulationState.Stopped; _frameStore.Flush(); }
|
public void Stop() { State = SimulationState.Stopped; _frameStore.Flush(); }
|
||||||
|
|
||||||
private List<FireUnit> BuildFireUnits(ScenarioConfig config, Dictionary<string, FireUnitSpec> specs)
|
private List<FireUnit> BuildFireUnits(ScenarioConfig config, Dictionary<string, LaunchPlatformSpec> specs)
|
||||||
{
|
{
|
||||||
var units = new List<FireUnit>();
|
var units = new List<FireUnit>();
|
||||||
foreach (var eq in config.Units.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform))
|
foreach (var eq in config.Units.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform))
|
||||||
{
|
{
|
||||||
if (!specs.TryGetValue(eq.FireUnitSpecId, out var spec)) continue;
|
if (!specs.TryGetValue(eq.LaunchPlatformSpecId, out var spec)) continue;
|
||||||
int qty = Math.Max(1, eq.Quantity);
|
int qty = Math.Max(1, eq.Quantity);
|
||||||
for (int i = 0; i < qty; i++)
|
for (int i = 0; i < qty; i++)
|
||||||
{
|
{
|
||||||
@ -463,66 +463,37 @@ namespace CounterDrone.Core.Simulation
|
|||||||
TotalMunitions = eq.MunitionCount ?? spec.GunCount * spec.ChannelsPerGun,
|
TotalMunitions = eq.MunitionCount ?? spec.GunCount * spec.ChannelsPerGun,
|
||||||
AmmoTypes = new List<AerosolType> { (AerosolType)(eq.AerosolType ?? 0) },
|
AmmoTypes = new List<AerosolType> { (AerosolType)(eq.AerosolType ?? 0) },
|
||||||
Cooldown = (float)spec.Cooldown,
|
Cooldown = (float)spec.Cooldown,
|
||||||
RadarRange = (float)spec.RadarRange,
|
|
||||||
EORange = (float)spec.EORange,
|
|
||||||
IRRange = (float)spec.IRRange,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return units;
|
return units;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<DetectionSource> BuildDetectionSources(ScenarioConfig config, Dictionary<string, FireUnitSpec> fuSpecs, Dictionary<string, SensorSpec> sensorSpecs)
|
private static List<DetectionSource> BuildDetectionSources(ScenarioConfig config, Dictionary<string, SensorSpec> sensorSpecs)
|
||||||
{
|
{
|
||||||
var sources = new List<DetectionSource>();
|
var sources = new List<DetectionSource>();
|
||||||
foreach (var eq in config.Units)
|
foreach (var eq in config.Units)
|
||||||
{
|
{
|
||||||
// Launch platform: get detection from FireUnitSpec
|
if (string.IsNullOrEmpty(eq.SensorSpecId)) continue;
|
||||||
if (eq.EquipmentRole == (int)EquipmentRole.LaunchPlatform)
|
if (!sensorSpecs.TryGetValue(eq.SensorSpecId, out var sensor)) continue;
|
||||||
|
bool hasDetection = sensor.RadarRange > 0 || sensor.EORange > 0 || sensor.IRRange > 0;
|
||||||
|
if (!hasDetection) continue;
|
||||||
|
int qty = Math.Max(1, eq.Quantity);
|
||||||
|
for (int i = 0; i < qty; i++)
|
||||||
{
|
{
|
||||||
if (!fuSpecs.TryGetValue(eq.FireUnitSpecId, out var spec)) continue;
|
sources.Add(new DetectionSource
|
||||||
bool hasDetection = spec.RadarRange > 0 || spec.EORange > 0 || spec.IRRange > 0;
|
|
||||||
if (!hasDetection) continue;
|
|
||||||
int qty = Math.Max(1, eq.Quantity);
|
|
||||||
for (int i = 0; i < qty; i++)
|
|
||||||
{
|
{
|
||||||
sources.Add(new DetectionSource
|
Position = new Algorithms.Vector3((float)eq.PositionX + i * 50, (float)eq.PositionY, (float)eq.PositionZ),
|
||||||
{
|
RadarRange = (float)sensor.RadarRange,
|
||||||
Position = new Algorithms.Vector3((float)eq.PositionX + i * 50, (float)eq.PositionY, (float)eq.PositionZ),
|
EORange = (float)sensor.EORange,
|
||||||
RadarRange = (float)spec.RadarRange,
|
IRRange = (float)sensor.IRRange,
|
||||||
EORange = (float)spec.EORange,
|
Accuracy = (float)sensor.Accuracy,
|
||||||
IRRange = (float)spec.IRRange,
|
MinElevation = (float)(sensor.MinElevation ?? float.MaxValue),
|
||||||
Accuracy = (float)(spec.MinElevation.HasValue ? 50f : 50f),
|
MaxElevation = (float)(sensor.MaxElevation ?? float.MaxValue),
|
||||||
MinElevation = (float)(spec.MinElevation ?? float.MaxValue),
|
MinDetectAlt = (float)(sensor.MinDetectAlt ?? float.MaxValue),
|
||||||
MaxElevation = (float)(spec.MaxElevation ?? float.MaxValue),
|
MaxDetectAlt = (float)(sensor.MaxDetectAlt ?? float.MaxValue),
|
||||||
MinDetectAlt = (float)(spec.MinDetectAlt ?? float.MaxValue),
|
ModelId = string.IsNullOrEmpty(sensor.ModelId) ? null : sensor.ModelId,
|
||||||
MaxDetectAlt = (float)(spec.MaxDetectAlt ?? float.MaxValue),
|
});
|
||||||
ModelId = string.IsNullOrEmpty(spec.ModelId) ? null : spec.ModelId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Detection equipment: get from SensorSpec
|
|
||||||
{
|
|
||||||
if (!sensorSpecs.TryGetValue(eq.SensorSpecId, out var sensor)) continue;
|
|
||||||
bool hasDetection = sensor.RadarRange > 0 || sensor.EORange > 0 || sensor.IRRange > 0;
|
|
||||||
if (!hasDetection) continue;
|
|
||||||
int qty = Math.Max(1, eq.Quantity);
|
|
||||||
for (int i = 0; i < qty; i++)
|
|
||||||
{
|
|
||||||
sources.Add(new DetectionSource
|
|
||||||
{
|
|
||||||
Position = new Algorithms.Vector3((float)eq.PositionX + i * 50, (float)eq.PositionY, (float)eq.PositionZ),
|
|
||||||
RadarRange = (float)sensor.RadarRange,
|
|
||||||
EORange = (float)sensor.EORange,
|
|
||||||
IRRange = (float)sensor.IRRange,
|
|
||||||
Accuracy = (float)sensor.Accuracy,
|
|
||||||
MinElevation = (float)(sensor.MinElevation ?? float.MaxValue),
|
|
||||||
MaxElevation = (float)(sensor.MaxElevation ?? float.MaxValue),
|
|
||||||
MinDetectAlt = (float)(sensor.MinDetectAlt ?? float.MaxValue),
|
|
||||||
MaxDetectAlt = (float)(sensor.MaxDetectAlt ?? float.MaxValue),
|
|
||||||
ModelId = string.IsNullOrEmpty(sensor.ModelId) ? null : sensor.ModelId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sources;
|
return sources;
|
||||||
|
|||||||
Binary file not shown.
@ -118,6 +118,38 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"launchPlatforms": [
|
||||||
|
{
|
||||||
|
"Id": "ground-light", "Name": "[Demo] 轻型地基发射平台",
|
||||||
|
"Description": "4通道轻型平台,800m/s初速",
|
||||||
|
"PlatformType": 1, "GunCount": 4, "ChannelsPerGun": 4, "ChannelInterval": 0.1,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0, "MuzzleVelocity": 800.0,
|
||||||
|
"AmmoTypes": [0, 1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "ground-standard", "Name": "[Demo] 标准地基发射平台",
|
||||||
|
"Description": "4通道标准平台,800m/s初速",
|
||||||
|
"PlatformType": 1, "GunCount": 4, "ChannelsPerGun": 4, "ChannelInterval": 0.1,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0, "MuzzleVelocity": 800.0,
|
||||||
|
"AmmoTypes": [0, 1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "ground-heavy", "Name": "[Demo] 重型地基发射平台",
|
||||||
|
"Description": "6通道重型平台,600m/s初速,支持全弹种",
|
||||||
|
"PlatformType": 1, "GunCount": 6, "ChannelsPerGun": 4, "ChannelInterval": 1.0,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0, "MuzzleVelocity": 600.0,
|
||||||
|
"AmmoTypes": [0, 1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "air-standard", "Name": "[Demo] 标准空基发射平台",
|
||||||
|
"Description": "8通道空基平台,80m/s巡航",
|
||||||
|
"PlatformType": 0, "GunCount": 1, "ChannelsPerGun": 8, "ChannelInterval": 1.0,
|
||||||
|
"Cooldown": 5.0, "AmmoChangeTime": 30.0,
|
||||||
|
"MuzzleVelocity": 80.0, "CruiseSpeed": 80.0, "ReleaseAltitude": 1000.0,
|
||||||
|
"AmmoTypes": [0, 1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
"drones": [
|
"drones": [
|
||||||
{ "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)",
|
{ "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)",
|
||||||
"Model": "DJI Mavic 类", "Description": "小型四旋翼,低空侦察",
|
"Model": "DJI Mavic 类", "Description": "小型四旋翼,低空侦察",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using CounterDrone.Core;
|
using CounterDrone.Core;
|
||||||
@ -28,8 +28,8 @@ namespace CounterDrone.Core.Tests
|
|||||||
private static DroneSpec? _droneSpec;
|
private static DroneSpec? _droneSpec;
|
||||||
public static DroneSpec DefaultDroneSpec => _droneSpec ??= _db.Table<DroneSpec>().First(d => d.Id == "shahed");
|
public static DroneSpec DefaultDroneSpec => _droneSpec ??= _db.Table<DroneSpec>().First(d => d.Id == "shahed");
|
||||||
|
|
||||||
private static FireUnitSpec? _groundSpec;
|
private static LaunchPlatformSpec? _groundSpec;
|
||||||
public static FireUnitSpec GroundSpec => _groundSpec ??= _db.Table<FireUnitSpec>().First(f => f.Id == "ground-light");
|
public static LaunchPlatformSpec GroundSpec => _groundSpec ??= _db.Table<LaunchPlatformSpec>().First(f => f.Id == "ground-light");
|
||||||
|
|
||||||
public static ScenarioDrone CreateScenarioDrone(string waveId = "w1", int quantity = 1)
|
public static ScenarioDrone CreateScenarioDrone(string waveId = "w1", int quantity = 1)
|
||||||
=> new() { DroneSpecId = DefaultDroneSpec.Id, WaveId = waveId, Quantity = quantity };
|
=> new() { DroneSpecId = DefaultDroneSpec.Id, WaveId = waveId, Quantity = quantity };
|
||||||
@ -39,16 +39,15 @@ namespace CounterDrone.Core.Tests
|
|||||||
|
|
||||||
public static ScenarioUnit CreateScenarioUnit(double px, double py, double pz,
|
public static ScenarioUnit CreateScenarioUnit(double px, double py, double pz,
|
||||||
int ammoType = 0, int? munitionCount = null)
|
int ammoType = 0, int? munitionCount = null)
|
||||||
=> new() { FireUnitSpecId = "ground-light", PositionX = px, PositionY = py, PositionZ = pz,
|
=> new() { LaunchPlatformSpecId = "ground-light", PositionX = px, PositionY = py, PositionZ = pz,
|
||||||
AerosolType = ammoType, MunitionCount = munitionCount ?? 8, Quantity = 1 };
|
AerosolType = ammoType, MunitionCount = munitionCount ?? 8, Quantity = 1 };
|
||||||
|
|
||||||
private static FireUnitSpec? _defaultFuSpec;
|
private static LaunchPlatformSpec? _defaultFuSpec;
|
||||||
public static FireUnitSpec DefaultFuSpec => _defaultFuSpec ??= new FireUnitSpec
|
public static LaunchPlatformSpec DefaultFuSpec => _defaultFuSpec ??= new LaunchPlatformSpec
|
||||||
{
|
{
|
||||||
Id = "test-fu", PlatformType = (int)PlatformType.GroundBased,
|
Id = "test-fu", PlatformType = (int)PlatformType.GroundBased,
|
||||||
GunCount = 1, ChannelsPerGun = 8, ChannelInterval = 1,
|
GunCount = 1, ChannelsPerGun = 8, ChannelInterval = 1,
|
||||||
MuzzleVelocity = 800, Cooldown = 5, AmmoChangeTime = 30,
|
MuzzleVelocity = 800, Cooldown = 5, AmmoChangeTime = 30,
|
||||||
RadarRange = 5000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static SensorSpec? _sensorSpec;
|
private static SensorSpec? _sensorSpec;
|
||||||
@ -66,7 +65,7 @@ namespace CounterDrone.Core.Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static Dictionary<string, DroneSpec> EmptyDroneSpecs => new();
|
public static Dictionary<string, DroneSpec> EmptyDroneSpecs => new();
|
||||||
public static Dictionary<string, FireUnitSpec> EmptyFuSpecs => new();
|
public static Dictionary<string, LaunchPlatformSpec> EmptyFuSpecs => new();
|
||||||
public static Dictionary<string, SensorSpec> EmptySensorSpecs => new();
|
public static Dictionary<string, SensorSpec> EmptySensorSpecs => new();
|
||||||
|
|
||||||
private static DefaultData? _all;
|
private static DefaultData? _all;
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user