using System.Collections.Generic;
using System.Linq;
using CounterDrone.Core;
using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;
using CounterDrone.Core.Repository;
using CounterDrone.Core.Services;
using UnityEngine;
using UVector3 = UnityEngine.Vector3;
using AVector3 = CounterDrone.Core.Algorithms.Vector3;
namespace CounterDrone.Unity
{
///
/// 前端参考模板 — 展示两种运行方式:
/// 1. 预设模式:直接运行数据库中的 [Demo] 想定(最简单)
/// 2. 自定义模式:用 DefaultData 预设快速组装新想定 → Planner → 仿真
///
public class SimulationBootstrap : MonoBehaviour
{
[Header("Mode")]
[SerializeField] private bool _usePreset = true; // true=预设想定, false=自定义
[Header("Custom Settings")]
[SerializeField] private float _droneSpeed = 200f;
[SerializeField] private float _routeLength = 5000f;
[SerializeField] private float _timeScale = 4f;
public SimulationRunner Runner { get; private set; }
void Start()
{
var paths = new UnityPathProvider();
var dbm = new DatabaseManager(paths);
var db = dbm.OpenMainDb(); // 自动种子弹药 + 6个[Demo]想定 + 基础数据
SqliteConnectionTracker.Track(db);
var dataService = new DataService(
new AmmunitionSpecRepository(db), new FireUnitSpecRepository(db),
new DroneSpecRepository(db), new SensorSpecRepository(db),
new EnvironmentSpecRepository(db), new FormationTemplateRepository(db),
new RouteTemplateRepository(db));
var scenario = new ScenarioService(
new SimTaskRepository(db), new CombatSceneRepository(db),
new ControlZoneRepository(db), new TargetConfigRepository(db),
new EquipmentDeploymentRepository(db), new CloudDispersalRepository(db),
new RoutePlanRepository(db), new WaypointRepository(db));
string taskId;
if (_usePreset)
{
// 方式1:直接使用预设想定(最简单)
var demos = scenario.SearchTasks("Demo", null, null, 1, 1);
if (demos.TotalCount == 0)
{
Debug.LogError("无预设想定,请确认 defaults.json 已放入 StreamingAssets");
return;
}
taskId = demos.Items[0].Id;
Debug.Log($"使用预设想定: {demos.Items[0].Name}");
}
else
{
// 方式2:用 DefaultData 预设组装自定义想定
var defaults = DefaultData.Load(paths);
var task = scenario.CreateTask("Unity Demo", "");
taskId = 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",
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 ammoCatalog = db.Table().ToList();
var planner = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths));
var threats = new List
{
new DroneWave { WaveId = "default", Target = detail.Targets[0], Route = detail.Routes[0], Waypoints = detail.WaypointGroups["default"] }
};
var fireUnits = new List();
for (int i = 0; i < 4; i++)
fireUnits.Add(new FireUnit
{
Id = $"fu{i}",
Type = PlatformType.GroundBased,
Position = new AVector3(_routeLength / 2f + i * 50, 0, 50),
MuzzleVelocity = 800, TotalMunitions = 3,
AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel },
});
var plan = planner.Plan(fireUnits, threats, detail.Scene, new List());
scenario.SaveCloudDispersal(taskId, new CloudDispersal
{
AerosolType = (int)AerosolType.InertGas,
DisperseHeight = detail.Targets[0].TypicalAltitude,
Source = "Algorithm",
});
scenario.SaveDeployment(taskId, new List
{
defaults.FireUnits.First(f => f.Id == "ground-light")
.ToEquipmentDeployment(AerosolType.InertGas, 1, _routeLength / 2f, 0, 50),
});
scenario.UpdateStep(taskId, 5);
Debug.Log($"自定义想定: {plan.Best.ThreatsEngaged} 威胁已分配, {plan.Best.MergedSchedule.Count} 发, 概率 {plan.Best.OverallProbability:P0}");
}
SqliteConnectionTracker.Untrack(db);
db.Dispose();
// 运行仿真
Runner = GetComponent();
if (Runner == null) Runner = gameObject.AddComponent();
else Runner.enabled = true;
Runner.DataService = dataService;
Runner.LoadAndStart(taskId);
Runner.Engine.TimeScale = _timeScale;
// 定位相机
var cam = Camera.main;
if (cam == null) { cam = new GameObject("MainCamera").AddComponent(); cam.tag = "MainCamera"; }
float midX = _usePreset ? 2500f : _routeLength / 2f;
cam.transform.position = new UVector3(midX, 2000, -3000);
cam.transform.LookAt(new UVector3(midX, 500, 0));
}
}
}