单一数据源 data/defaults.json,含弹药/编队/火力单元/无人机/探测/天气六类预设 版本追踪: Meta 表 + version 字段,更新时 InsertOrReplace,不删用户数据 名称统一 [Demo] 前缀,UI 中可识别为模拟数据 删除: DefaultAmmunition.cs, DefaultFireUnits.cs, default_ammo.json, default_formations.json, TestAmmo.cs TestPathProvider 自动复制数据文件到测试目录 集成测试精简: 4个简单变体跳过,保留6个核心场景,39s
136 lines
6.3 KiB
C#
136 lines
6.3 KiB
C#
using System.Collections.Generic;
|
|
using CounterDrone.Core;
|
|
using CounterDrone.Core.Algorithms;
|
|
using CounterDrone.Core.Models;
|
|
using CounterDrone.Core.Simulation;
|
|
using UnityEngine;
|
|
using AVector3 = CounterDrone.Core.Algorithms.Vector3;
|
|
|
|
namespace CounterDrone.Unity
|
|
{
|
|
[ExecuteAlways]
|
|
public class ManagerVerification : MonoBehaviour
|
|
{
|
|
[ContextMenu("Run Full Verification")]
|
|
void Run()
|
|
{
|
|
Debug.Log("===== Manager Verification Start =====");
|
|
|
|
var paths = new UnityPathProvider();
|
|
if (System.IO.File.Exists(paths.GetMainDbPath()))
|
|
System.IO.File.Delete(paths.GetMainDbPath());
|
|
if (System.IO.Directory.Exists(paths.GetFramesDir()))
|
|
System.IO.Directory.Delete(paths.GetFramesDir(), true);
|
|
|
|
var modelMgr = gameObject.AddComponent<ModelManager>();
|
|
modelMgr.Awake();
|
|
Debug.Log("1. ModelManager OK");
|
|
|
|
var scenarioMgr = gameObject.AddComponent<ScenarioManager>();
|
|
scenarioMgr.Awake();
|
|
var task = scenarioMgr.CreateTask("Verification", "");
|
|
var taskId = task.Id;
|
|
Debug.Log($"2. ScenarioManager OK. Task: {taskId}");
|
|
|
|
scenarioMgr.SaveScene(taskId, new CombatScene { WindSpeed = 0 });
|
|
scenarioMgr.SaveTarget(taskId, new TargetConfig
|
|
{
|
|
WaveId = "default",
|
|
TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston,
|
|
Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500,
|
|
});
|
|
scenarioMgr.SaveRoute(taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
|
|
new List<Waypoint>
|
|
{
|
|
new Waypoint { PosX = 0, PosY = 500, PosZ = 0 },
|
|
new Waypoint { PosX = 10000, PosY = 500, PosZ = 0 },
|
|
});
|
|
scenarioMgr.UpdateStep(taskId, 3);
|
|
Debug.Log("3. Scenario configured");
|
|
|
|
var db = new DatabaseManager(paths).OpenMainDb();
|
|
SqliteConnectionTracker.Track(db);
|
|
foreach (var a in DefaultData.Load(paths).Ammunition) db.Insert(a);
|
|
var ammoCatalog = db.Table<AmmunitionSpec>().ToList();
|
|
|
|
var detail = scenarioMgr.GetDetail(taskId);
|
|
var droneGroup = new DroneWave
|
|
{
|
|
WaveId = "default",
|
|
Target = detail.Targets[0],
|
|
Route = detail.Routes[0],
|
|
Waypoints = detail.WaypointGroups["default"],
|
|
};
|
|
var fireUnits = new List<FireUnit>();
|
|
for (int i = 0; i < 8; i++)
|
|
fireUnits.Add(new FireUnit
|
|
{
|
|
Id = $"u{i}",
|
|
Type = PlatformType.GroundBased,
|
|
Position = new AVector3(5000 + i * 50, 0, 50),
|
|
MuzzleVelocity = 800,
|
|
TotalMunitions = 3,
|
|
AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel },
|
|
});
|
|
var result = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths)).Plan(fireUnits, new List<DroneWave> { droneGroup }, detail.Scene, new List<DetectionSource>());
|
|
scenarioMgr.SaveCloud(taskId, new CloudDispersal
|
|
{
|
|
PositionX = (droneGroup.Waypoints[0].PosX + droneGroup.Waypoints[^1].PosX) / 2,
|
|
PositionY = (droneGroup.Waypoints[0].PosY + droneGroup.Waypoints[^1].PosY) / 2,
|
|
PositionZ = (droneGroup.Waypoints[0].PosZ + droneGroup.Waypoints[^1].PosZ) / 2,
|
|
DisperseHeight = droneGroup.Target.TypicalAltitude,
|
|
});
|
|
|
|
var equips = new List<EquipmentDeployment>();
|
|
foreach (var u in fireUnits)
|
|
equips.Add(new EquipmentDeployment
|
|
{
|
|
EquipmentRole = (int)EquipmentRole.LaunchPlatform,
|
|
PlatformType = (int)u.Type, Quantity = 1,
|
|
PositionX = u.Position.X, PositionY = u.Position.Y, PositionZ = u.Position.Z,
|
|
AerosolType = (int)u.AmmoTypes[0],
|
|
MunitionCount = u.TotalMunitions, Cooldown = u.Cooldown, MuzzleVelocity = u.MuzzleVelocity,
|
|
CruiseSpeed = u.CruiseSpeed > 0 ? u.CruiseSpeed : null,
|
|
ReleaseAltitude = u.ReleaseAltitude > 0 ? u.ReleaseAltitude : null,
|
|
});
|
|
scenarioMgr.SaveDeployment(taskId, equips);
|
|
SqliteConnectionTracker.Untrack(db);
|
|
db.Dispose();
|
|
var plan = result.Best;
|
|
Debug.Log($"4. Plan: {plan.ThreatsEngaged} threats engaged, {plan.MergedSchedule.Count} rounds, prob={plan.OverallProbability:P0}");
|
|
|
|
var runner = gameObject.AddComponent<SimulationRunner>();
|
|
runner.Awake();
|
|
runner.LoadAndStart(taskId);
|
|
runner.Engine.TimeScale = 10f;
|
|
|
|
float endTime = Time.realtimeSinceStartup + 60f;
|
|
int frameCount = 0;
|
|
float tickDt = 1f / 20f;
|
|
while (runner.Engine.State == SimulationState.Running && Time.realtimeSinceStartup < endTime)
|
|
{
|
|
runner.Engine.Tick(tickDt);
|
|
frameCount++;
|
|
}
|
|
Debug.Log($"5. Simulation done. State={runner.Engine.State}, DroneStatus={runner.Engine.Drones[0].Status}, HP={runner.Engine.Drones[0].Hp:F2}, Frames={frameCount}");
|
|
runner.Stop();
|
|
|
|
var reportMgr = gameObject.AddComponent<ReportManager>();
|
|
reportMgr.Awake();
|
|
detail = scenarioMgr.GetDetail(taskId);
|
|
var simEvents = new List<SimEvent>(runner.Engine.Events);
|
|
var status = runner.Engine.Drones.Count > 0 ? runner.Engine.Drones[0].Status.ToString() : "Unknown";
|
|
var report = reportMgr.Generate(taskId, detail, simEvents, status, runner.Engine.SimulationTime);
|
|
var path = reportMgr.Export(report.Id);
|
|
Debug.Log($"6. Report OK. Exported: {path}");
|
|
|
|
var replay = gameObject.AddComponent<ReplayController>();
|
|
replay.Awake();
|
|
replay.LoadReplay(taskId);
|
|
Debug.Log($"7. Replay OK. {replay.TotalFrames} frames, {replay.CurrentFrames.Count} records");
|
|
|
|
Debug.Log("===== ALL MANAGERS VERIFIED =====");
|
|
}
|
|
}
|
|
}
|