- ScenarioDrone: 仅保留 Id/ScenarioId/DroneSpecId/WaveId/Quantity - ScenarioUnit: 仅保留 Id/ScenarioId/FireUnitSpecId/SensorSpecId/Position 等想定字段 - DroneEntity/PlatformEntity 构造函数改为接收 DroneSpec/FireUnitSpec - SimulationEngine 加载 spec 字典,build 方法通过 FK 查 spec - ReportGenerator/ReportService 通过 spec 字典取值 - DefaultLaneDivider.Divide 从 DroneWave.Quantity 取值 - Core 编译通过,测试待修复
264 lines
10 KiB
C#
264 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text.Json;
|
||
using CounterDrone.Core.Models;
|
||
|
||
namespace CounterDrone.Core
|
||
{
|
||
/// <summary>
|
||
/// 统一默认数据 — 弹药、编队、火力单元、无人机、探测设备、天气的预设库。
|
||
/// 所有默认数据集中在 data/defaults.json,通过本类统一加载。
|
||
/// </summary>
|
||
public class DefaultData
|
||
{
|
||
public string Version { get; set; } = "0";
|
||
public List<AmmunitionSpec> Ammunition { get; set; } = new();
|
||
public List<FormationTemplate> Formations { get; set; } = new();
|
||
public List<RouteTemplate> Routes { get; set; } = new();
|
||
[System.Text.Json.Serialization.JsonPropertyName("fireUnits")]
|
||
public List<FireUnitSpec> FireUnits { get; set; } = new();
|
||
[System.Text.Json.Serialization.JsonPropertyName("drones")]
|
||
public List<DroneSpec> Drones { get; set; } = new();
|
||
[System.Text.Json.Serialization.JsonPropertyName("detectionEquipment")]
|
||
public List<SensorSpec> Sensors { get; set; } = new();
|
||
[System.Text.Json.Serialization.JsonPropertyName("weather")]
|
||
public List<EnvironmentSpec> Environments { get; set; } = new();
|
||
|
||
/// <summary>从 data/defaults.json 加载。文件缺失或解析失败即抛异常。</summary>
|
||
public static DefaultData Load(IPathProvider paths)
|
||
{
|
||
var jsonPath = Path.Combine(paths.GetDataRoot(), "defaults.json");
|
||
if (!File.Exists(jsonPath))
|
||
throw new FileNotFoundException($"默认数据文件未找到: {jsonPath}");
|
||
|
||
var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||
var data = JsonSerializer.Deserialize<DefaultData>(File.ReadAllText(jsonPath), opts)
|
||
?? throw new InvalidOperationException($"默认数据文件解析失败: {jsonPath}");
|
||
|
||
Validate(data, jsonPath);
|
||
return data;
|
||
}
|
||
|
||
/// <summary>从 JSON 字符串解析(测试用)</summary>
|
||
public static DefaultData FromJson(string json)
|
||
{
|
||
var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||
var data = JsonSerializer.Deserialize<DefaultData>(json, opts)
|
||
?? throw new InvalidOperationException("默认数据 JSON 解析失败");
|
||
Validate(data, "<string>");
|
||
return data;
|
||
}
|
||
|
||
private static void Validate(DefaultData data, string source)
|
||
{
|
||
if (data.Ammunition == null || data.Ammunition.Count == 0)
|
||
throw new InvalidOperationException($"默认数据缺少 ammunition: {source}");
|
||
if (data.Formations == null || data.Formations.Count == 0)
|
||
throw new InvalidOperationException($"默认数据缺少 formations: {source}");
|
||
if (data.Routes == null || data.Routes.Count == 0)
|
||
throw new InvalidOperationException($"默认数据缺少 routes: {source}");
|
||
if (data.FireUnits == null || data.FireUnits.Count == 0)
|
||
throw new InvalidOperationException($"默认数据缺少 fireUnits: {source}");
|
||
if (data.Drones == null || data.Drones.Count == 0)
|
||
throw new InvalidOperationException($"默认数据缺少 drones: {source}");
|
||
if (data.Environments == null || data.Environments.Count == 0)
|
||
throw new InvalidOperationException($"默认数据缺少 environments: {source}");
|
||
if (data.Sensors == null)
|
||
data.Sensors = new();
|
||
}
|
||
}
|
||
|
||
/// <summary>编队模板</summary>
|
||
public class FormationTemplate
|
||
{
|
||
public string Id { get; set; } = "";
|
||
public string Name { get; set; } = "";
|
||
public int FormationMode { get; set; }
|
||
public int LateralCount { get; set; } = 1;
|
||
public int LongitudinalCount { get; set; } = 1;
|
||
public double LateralSpacing { get; set; }
|
||
public double LongitudinalSpacing { get; set; }
|
||
public int LateralAxis { get; set; } = 2; // 0=X, 1=Y, 2=Z
|
||
public int LongitudinalAxis { get; set; } = 0; // 0=X, 1=Y, 2=Z
|
||
|
||
public RoutePlan ToRoutePlan()
|
||
{
|
||
return new RoutePlan
|
||
{
|
||
FormationMode = FormationMode,
|
||
LateralCount = LateralCount,
|
||
LongitudinalCount = LongitudinalCount,
|
||
LateralSpacing = LateralSpacing,
|
||
LongitudinalSpacing = LongitudinalSpacing,
|
||
LateralAxis = LateralAxis,
|
||
LongitudinalAxis = LongitudinalAxis,
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>火力单元规格(基础数据模板)</summary>
|
||
[SQLite.Table("FireUnitSpec")]
|
||
public class FireUnitSpec
|
||
{
|
||
[SQLite.PrimaryKey]
|
||
public string Id { get; set; } = "";
|
||
public string Name { 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; }
|
||
[SQLite.Ignore]
|
||
public List<int> AmmoTypes { get; set; } = new();
|
||
public double RadarRange { get; set; }
|
||
public double EORange { get; set; }
|
||
public double IRRange { get; set; }
|
||
// 3D 球冠几何(缺失时退化 2D)
|
||
public double? MinElevation { get; set; }
|
||
public double? MaxElevation { get; set; }
|
||
public double? MinDetectAlt { get; set; }
|
||
public double? MaxDetectAlt { get; set; }
|
||
|
||
public ScenarioUnit ToScenarioUnit(AerosolType ammoType, int quantity,
|
||
double posX, double posY, double posZ)
|
||
{
|
||
return new ScenarioUnit
|
||
{
|
||
FireUnitSpecId = Id,
|
||
EquipmentRole = (int)Models.EquipmentRole.LaunchPlatform,
|
||
Quantity = quantity,
|
||
PositionX = posX,
|
||
PositionY = posY,
|
||
PositionZ = posZ,
|
||
AerosolType = (int)ammoType,
|
||
MunitionCount = GunCount * ChannelsPerGun * quantity,
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>无人机规格(基础数据模板)</summary>
|
||
[SQLite.Table("DroneSpec")]
|
||
public class DroneSpec
|
||
{
|
||
[SQLite.PrimaryKey]
|
||
public string Id { get; set; } = "";
|
||
public string Name { get; set; } = "";
|
||
public int DroneType { get; set; }
|
||
public string Model { get; set; } = "";
|
||
public string Description { get; set; } = "";
|
||
public int PowerType { get; set; }
|
||
public double Wingspan { get; set; }
|
||
public double TypicalSpeed { get; set; }
|
||
public double TypicalAltitude { get; set; }
|
||
|
||
public ScenarioDrone ToScenarioDrone(string waveId = "default")
|
||
{
|
||
return new ScenarioDrone
|
||
{
|
||
DroneSpecId = Id,
|
||
WaveId = waveId,
|
||
Quantity = 1,
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>传感器规格(基础数据模板)</summary>
|
||
[SQLite.Table("SensorSpec")]
|
||
public class SensorSpec
|
||
{
|
||
[SQLite.PrimaryKey]
|
||
public string Id { get; set; } = "";
|
||
public string Name { get; set; } = "";
|
||
public double RadarRange { get; set; }
|
||
public double EORange { get; set; }
|
||
public double IRRange { get; set; }
|
||
public double Accuracy { get; set; } = 50.0;
|
||
// 3D 球冠几何(缺失时退化 2D)
|
||
public double? MinElevation { get; set; }
|
||
public double? MaxElevation { get; set; }
|
||
public double? MinDetectAlt { get; set; }
|
||
public double? MaxDetectAlt { get; set; }
|
||
|
||
public ScenarioUnit ToScenarioUnit(double posX, double posY, double posZ)
|
||
{
|
||
return new ScenarioUnit
|
||
{
|
||
SensorSpecId = Id,
|
||
EquipmentRole = (int)Models.EquipmentRole.Detection,
|
||
Quantity = 1,
|
||
PositionX = posX,
|
||
PositionY = posY,
|
||
PositionZ = posZ,
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>环境规格(基础数据模板)</summary>
|
||
[SQLite.Table("EnvironmentSpec")]
|
||
public class EnvironmentSpec
|
||
{
|
||
[SQLite.PrimaryKey]
|
||
public string Id { get; set; } = "";
|
||
public string Name { get; set; } = "";
|
||
public int WeatherType { get; set; }
|
||
public double WindSpeed { get; set; }
|
||
public int WindDirection { get; set; }
|
||
public double Temperature { get; set; } = 20.0;
|
||
public double Humidity { get; set; } = 60.0;
|
||
public double Pressure { get; set; } = 1013.0;
|
||
public double Visibility { get; set; } = 5000.0;
|
||
|
||
public CombatScene ToCombatScene()
|
||
{
|
||
return new CombatScene
|
||
{
|
||
WeatherType = WeatherType,
|
||
WindSpeed = WindSpeed,
|
||
WindDirection = WindDirection,
|
||
Temperature = Temperature,
|
||
Humidity = Humidity,
|
||
Pressure = Pressure,
|
||
Visibility = Visibility,
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>航线模板(基础数据模板)</summary>
|
||
[SQLite.Table("RouteTemplate")]
|
||
public class RouteTemplate
|
||
{
|
||
[SQLite.PrimaryKey]
|
||
public string Id { get; set; } = "";
|
||
public string Name { get; set; } = "";
|
||
/// <summary>航路点 JSON(WaypointCoord 序列化),SQLite 存储用</summary>
|
||
public string WaypointsJson { get; set; } = "[]";
|
||
[SQLite.Ignore]
|
||
public List<WaypointCoord> Waypoints { get; set; } = new();
|
||
|
||
public List<Waypoint> ToWaypoints(double speed)
|
||
{
|
||
var list = new List<Waypoint>();
|
||
foreach (var w in Waypoints)
|
||
list.Add(new Waypoint
|
||
{
|
||
PosX = w.X, PosY = w.Y, PosZ = w.Z,
|
||
Altitude = w.Y, Speed = speed,
|
||
});
|
||
return list;
|
||
}
|
||
}
|
||
|
||
public class WaypointCoord
|
||
{
|
||
public double X { get; set; }
|
||
public double Y { get; set; }
|
||
public double Z { get; set; }
|
||
}
|
||
}
|