refactor: SimulationEngine 内部调用 Planner,不再依赖外部传 SetFireSchedule

- Initialize 内建 BuildFireUnits/BuildDroneGroups
- 自动从 DB 取 AmmunitionSpec 创建 DefaultDefensePlanner
- SetFireSchedule 保留为手动覆盖(测试可用)
- fireSchedule 空时才自动生成
This commit is contained in:
tian 2026-06-13 09:53:08 +08:00
parent 4411a452dc
commit e3ea595204

View File

@ -49,15 +49,17 @@ namespace CounterDrone.Core.Simulation
private readonly List<SimEvent> _allEvents = new();
private SQLiteConnection _frameDb = null!;
private string _taskId = string.Empty;
private readonly IDefensePlanner _planner;
private int _entityCounter;
public SimulationEngine(IScenarioService scenarioService, FrameDataStore frameStore,
IDamageModel damageModel, IPathProvider paths)
IDamageModel damageModel, IPathProvider paths, IDefensePlanner? planner = null)
{
_scenarioService = scenarioService;
_frameStore = frameStore;
_damageModel = damageModel;
_paths = paths;
_planner = planner ?? new DefaultDefensePlanner(new List<AmmunitionSpec>());
}
public void SetFireSchedule(List<FireEvent> schedule)
@ -114,6 +116,26 @@ namespace CounterDrone.Core.Simulation
SimulationTime = 0;
_entityCounter = 0;
_nextFireIndex = 0;
// 自动从 Planner 生成发射计划
if (_fireSchedule.Count == 0)
{
var fireUnits = BuildFireUnits(config);
var threats = BuildDroneGroups(config);
if (fireUnits.Count > 0 && threats.Count > 0)
{
using (var ammoDb = new SQLiteConnection(_paths.GetMainDbPath()))
{
var catalog = new List<AmmunitionSpec>(ammoDb.Table<AmmunitionSpec>().ToList());
if (catalog.Count == 0)
catalog = DefaultAmmunition.GetAll();
var planner = new DefaultDefensePlanner(catalog);
var result = planner.Plan(fireUnits, threats, _scene);
SetFireSchedule(result.Best.MergedSchedule);
}
}
}
_frameDb = _frameStore.CreateOrOpen(_taskId);
State = SimulationState.Running;
}
@ -264,6 +286,50 @@ namespace CounterDrone.Core.Simulation
public void Resume() { if (State == SimulationState.Paused) State = SimulationState.Running; }
public void Stop() { State = SimulationState.Stopped; _frameDb?.Close(); }
private static List<FireUnit> BuildFireUnits(TaskFullConfig config)
{
var units = new List<FireUnit>();
int idx = 0;
foreach (var eq in config.Equipment.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform))
{
int qty = Math.Max(1, eq.Quantity);
for (int i = 0; i < qty; i++)
{
units.Add(new FireUnit
{
Id = $"fu{idx++}",
Type = (PlatformType)(eq.PlatformType ?? (int)PlatformType.GroundBased),
Position = new Algorithms.Vector3((float)eq.PositionX + i * 50, (float)eq.PositionY, (float)eq.PositionZ),
CruiseSpeed = (float)(eq.CruiseSpeed ?? 55f),
ReleaseAltitude = (float)(eq.ReleaseAltitude ?? 1000f),
MuzzleVelocity = (float)(eq.MuzzleVelocity ?? 800f),
TotalMunitions = eq.MunitionCount ?? 1,
AmmoTypes = new List<AerosolType> { (AerosolType)(eq.AerosolType ?? 0) },
Cooldown = (float)eq.Cooldown,
});
}
}
return units;
}
private static List<DroneGroup> BuildDroneGroups(TaskFullConfig config)
{
var groups = new List<DroneGroup>();
foreach (var t in config.Targets)
{
var route = config.Routes.FirstOrDefault(r => r.GroupId == t.GroupId);
var wps = config.WaypointGroups.GetValueOrDefault(t.GroupId, new List<Waypoint>());
groups.Add(new DroneGroup
{
GroupId = t.GroupId,
Target = t,
Route = route ?? new RoutePlan(),
Waypoints = wps,
});
}
return groups;
}
private List<EntitySnapshot> CollectSnapshots()
{
var list = new List<EntitySnapshot>();