From 67cea1490d269e36a444a72248985754d58d05e7 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 18 Jun 2026 15:37:25 +0800 Subject: [PATCH] =?UTF-8?q?Target=E2=86=92Profile=20/=20Targets=E2=86=92Dr?= =?UTF-8?q?oneProfiles=20=E9=87=8D=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DroneWave.Target → Profile - ScenarioConfig.Targets → DroneProfiles - DefensePlanner / SimulationEngine / ReportService 全部引用同步 - 更新 Unity DLL + defaults.json - 238 测试全过 --- data/defaults.json | 2 +- .../Algorithms/AlgorithmTypes.cs | 2 +- .../Algorithms/DefaultLaneDivider.cs | 6 +++--- .../Algorithms/DefensePlanner.cs | 20 +++++++++--------- src/CounterDrone.Core/DefaultData.cs | 2 +- .../Models/ScenarioConfig.cs | 2 +- .../Repository/DroneProfileRepository.cs | 4 ++-- .../Services/ReportGenerator.cs | 4 ++-- .../Services/ReportService.cs | 2 +- .../Services/ScenarioService.cs | 2 +- .../Simulation/SimulationEngine.cs | 6 +++--- .../CounterDrone.Core.deps.json | 2 +- .../CounterDrone.Core/CounterDrone.Core.dll | Bin 177664 -> 177664 bytes .../Scripts/Managers/ManagerVerification.cs | 6 +++--- .../Scripts/Managers/SimulationBootstrap.cs | 4 ++-- .../Assets/StreamingAssets/defaults.json | 2 +- .../DefensePlannerTests.cs | 6 +++--- .../ReportGeneratorTests.cs | 2 +- .../ReportServiceTests.cs | 6 +++--- .../ScenarioServiceTests.cs | 10 ++++----- unity_plugins/CounterDrone.Core.dll | Bin 177664 -> 177664 bytes 21 files changed, 45 insertions(+), 45 deletions(-) diff --git a/data/defaults.json b/data/defaults.json index 331add0..a5a2ac0 100644 --- a/data/defaults.json +++ b/data/defaults.json @@ -114,7 +114,7 @@ } ], - "targets": [ + "drones": [ { "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)", "DroneType": 0, "PowerType": 0, "Wingspan": 1.2, "TypicalSpeed": 60.0, "TypicalAltitude": 300.0 }, { "Id": "electric-scout", "Name": "[Demo] 电推侦察无人机", diff --git a/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs b/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs index a355956..8bc0c70 100644 --- a/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs +++ b/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs @@ -51,7 +51,7 @@ namespace CounterDrone.Core.Algorithms public class DroneWave { public string WaveId { get; set; } = string.Empty; - public DroneProfile Target { get; set; } = new(); + public DroneProfile Profile { get; set; } = new(); public RoutePlan Route { get; set; } = new(); public List Waypoints { get; set; } = new(); diff --git a/src/CounterDrone.Core/Algorithms/DefaultLaneDivider.cs b/src/CounterDrone.Core/Algorithms/DefaultLaneDivider.cs index b4c4422..7915ee6 100644 --- a/src/CounterDrone.Core/Algorithms/DefaultLaneDivider.cs +++ b/src/CounterDrone.Core/Algorithms/DefaultLaneDivider.cs @@ -7,14 +7,14 @@ namespace CounterDrone.Core.Algorithms { public (int laneCount, float laneSpacing) Divide(DroneWave wave, float cloudRadius) { - if (wave.Route == null || wave.Target.Quantity <= 1) + if (wave.Route == null || wave.Profile.Quantity <= 1) return (1, 0); var mode = (FormationMode)wave.Route.FormationMode; if (mode != FormationMode.Formation) return (1, 0); - int latCount = wave.Route.LateralCount ?? wave.Target.Quantity; + int latCount = wave.Route.LateralCount ?? wave.Profile.Quantity; int longCount = wave.Route.LongitudinalCount ?? 1; float latWidth = (latCount - 1) * (float)wave.Route.LateralSpacing; float longDepth = (longCount - 1) * (float)wave.Route.LongitudinalSpacing; @@ -22,7 +22,7 @@ namespace CounterDrone.Core.Algorithms // 任一维度超过云团半径,则无法一个云团覆盖 if (latWidth > cloudRadius || longDepth > cloudRadius) - return (wave.Target.Quantity, (float)wave.Route.LateralSpacing); + return (wave.Profile.Quantity, (float)wave.Route.LateralSpacing); return (1, 0); } diff --git a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs index 4f95688..e182b24 100644 --- a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs @@ -62,14 +62,14 @@ namespace CounterDrone.Core.Algorithms foreach (var t in threats) { t.ArrivalTime = t.GetArrivalTime(); - t.ThreatIndex = CalcThreatIndex(_config, t.Target); + t.ThreatIndex = CalcThreatIndex(_config, t.Profile); } var sorted = threats.OrderByDescending(t => t.Priority).ToList(); // Step 2-4: 贪心分配求解 // 预先检查:所有需要的弹药类型都在目录中 var neededTypes = sorted - .Select(t => MatchAmmo(_config, (PowerType)t.Target.PowerType)) + .Select(t => MatchAmmo(_config, (PowerType)t.Profile.PowerType)) .Distinct() .ToList(); foreach (var t in neededTypes) @@ -132,7 +132,7 @@ namespace CounterDrone.Core.Algorithms } // 计算总弹药需求 - var neededAmmo = MatchAmmo(_config, (PowerType)threat.Target.PowerType); + var neededAmmo = MatchAmmo(_config, (PowerType)threat.Profile.PowerType); var ammo = _ammoCatalog.First(a => a.AerosolType == (int)neededAmmo); // 单机需求 @@ -234,7 +234,7 @@ namespace CounterDrone.Core.Algorithms foreach (var threat in sortedThreats) { var a2 = _ammoCatalog.FirstOrDefault(s => - s.AerosolType == (int)MatchAmmo(_config, (PowerType)threat.Target.PowerType)); + s.AerosolType == (int)MatchAmmo(_config, (PowerType)threat.Profile.PowerType)); int totalRounds = plan.Assignments .Where(a => a.DroneWaveId == threat.WaveId) .Sum(a => a.RoundsFired); @@ -249,7 +249,7 @@ namespace CounterDrone.Core.Algorithms { bool engaged = plan.Assignments.Any(a => a.DroneWaveId == threat.WaveId); if (engaged) continue; - var ammo = MatchAmmo(_config, (PowerType)threat.Target.PowerType); + var ammo = MatchAmmo(_config, (PowerType)threat.Profile.PowerType); var matching = fireUnits.Where(u => u.AmmoTypes.Contains(ammo)).ToList(); if (matching.Count == 0) reasons.Add($"威胁 {threat.WaveId}: 无火力单元装载 {ammo} 弹药"); @@ -323,7 +323,7 @@ namespace CounterDrone.Core.Algorithms List availableUnits, CombatScene env) { var candidates = new List(); - var neededAmmo = MatchAmmo(_config, (PowerType)threat.Target.PowerType); + var neededAmmo = MatchAmmo(_config, (PowerType)threat.Profile.PowerType); var ammo = _ammoCatalog.First(a => a.AerosolType == (int)neededAmmo); var (ammoEff, expansionTime, _) = ComputeEffectiveRadius(ammo, env); @@ -359,7 +359,7 @@ namespace CounterDrone.Core.Algorithms if (!HasInterceptWindow(threat, midArc, expansionTime, deliveryTime)) return null; float avgSpeed = GetDroneSpeedMs(threat); - float neededExposure = _damageModel.RequiredExposureSeconds((DroneType)threat.Target.DroneType, (PowerType)threat.Target.PowerType, ammoType); + float neededExposure = _damageModel.RequiredExposureSeconds((DroneType)threat.Profile.DroneType, (PowerType)threat.Profile.PowerType, ammoType); float actualExposure = effectiveR * 2f / avgSpeed; float prob = Math.Min(_config.MaxInterceptProbability, actualExposure / neededExposure); @@ -394,7 +394,7 @@ namespace CounterDrone.Core.Algorithms var cloudModel = new CloudExpansionModel(ammo, env); float avgSpeed = GetDroneSpeedMs(threat); float neededExposure = _damageModel.RequiredExposureSeconds( - (DroneType)threat.Target.DroneType, (PowerType)threat.Target.PowerType, (AerosolType)ammo.AerosolType); + (DroneType)threat.Profile.DroneType, (PowerType)threat.Profile.PowerType, (AerosolType)ammo.AerosolType); float requiredCoverage = neededExposure * avgSpeed; // 间距由配置的重叠比例驱动,公式在 CloudExpansionModel(共享) float spacing = 2f * turbulentRadius * (1f - _config.CloudOverlapRatio); @@ -411,7 +411,7 @@ namespace CounterDrone.Core.Algorithms float actualExposure = actualCoverage / avgSpeed; var aerosolType = (AerosolType)ammo.AerosolType; - float neededExposure = _damageModel.RequiredExposureSeconds((DroneType)threat.Target.DroneType, (PowerType)threat.Target.PowerType, aerosolType); + float neededExposure = _damageModel.RequiredExposureSeconds((DroneType)threat.Profile.DroneType, (PowerType)threat.Profile.PowerType, aerosolType); return Math.Min(_config.MaxInterceptProbability, actualExposure / neededExposure); } @@ -571,7 +571,7 @@ namespace CounterDrone.Core.Algorithms private static Vector3 ThreatMidpoint(DroneWave threat) { if (threat.Waypoints.Count < 2) - return new Vector3(0, (float)threat.Target.TypicalAltitude, 0); + return new Vector3(0, (float)threat.Profile.TypicalAltitude, 0); var s = threat.Waypoints[0]; var e = threat.Waypoints[^1]; return new Vector3( diff --git a/src/CounterDrone.Core/DefaultData.cs b/src/CounterDrone.Core/DefaultData.cs index 2130bf9..6f54dd1 100644 --- a/src/CounterDrone.Core/DefaultData.cs +++ b/src/CounterDrone.Core/DefaultData.cs @@ -19,7 +19,7 @@ namespace CounterDrone.Core public List Routes { get; set; } = new(); [System.Text.Json.Serialization.JsonPropertyName("fireUnits")] public List FireUnits { get; set; } = new(); - [System.Text.Json.Serialization.JsonPropertyName("targets")] + [System.Text.Json.Serialization.JsonPropertyName("drones")] public List Drones { get; set; } = new(); [System.Text.Json.Serialization.JsonPropertyName("detectionEquipment")] public List Sensors { get; set; } = new(); diff --git a/src/CounterDrone.Core/Models/ScenarioConfig.cs b/src/CounterDrone.Core/Models/ScenarioConfig.cs index 8ea9275..a7e9200 100644 --- a/src/CounterDrone.Core/Models/ScenarioConfig.cs +++ b/src/CounterDrone.Core/Models/ScenarioConfig.cs @@ -8,7 +8,7 @@ namespace CounterDrone.Core.Models public Scenario Info { get; set; } = new(); public CombatScene Scene { get; set; } = new(); public List ControlZones { get; set; } = new(); - public List Targets { get; set; } = new(); + public List Drones { get; set; } = new(); public List Equipment { get; set; } = new(); public CloudDispersal Cloud { get; set; } = new(); /// 多批次航路(多批次支持) diff --git a/src/CounterDrone.Core/Repository/DroneProfileRepository.cs b/src/CounterDrone.Core/Repository/DroneProfileRepository.cs index e6f2985..5ba539b 100644 --- a/src/CounterDrone.Core/Repository/DroneProfileRepository.cs +++ b/src/CounterDrone.Core/Repository/DroneProfileRepository.cs @@ -16,8 +16,8 @@ namespace CounterDrone.Core.Repository public void DeleteByScenarioId(string scenarioId) { - var targets = GetByScenarioId(scenarioId); - foreach (var t in targets) + var drones = GetByScenarioId(scenarioId); + foreach (var t in drones) Db.Delete(t); } } diff --git a/src/CounterDrone.Core/Services/ReportGenerator.cs b/src/CounterDrone.Core/Services/ReportGenerator.cs index 1cc311d..926d227 100644 --- a/src/CounterDrone.Core/Services/ReportGenerator.cs +++ b/src/CounterDrone.Core/Services/ReportGenerator.cs @@ -14,12 +14,12 @@ namespace CounterDrone.Core.Services { var sb = new StringBuilder(); var platforms = config.Equipment.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform).ToList(); - var target = config.Targets.FirstOrDefault(); + var target = config.Drones.FirstOrDefault(); var scene = config.Scene; var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed); var reached = events.Count(e => e.Type == SimEventType.DroneReachedTarget); var intruded = events.Count(e => e.Type == SimEventType.ZoneIntruded); - var totalDrones = config.Targets.Sum(t => t.Quantity); + var totalDrones = config.Drones.Sum(t => t.Quantity); var result = DetermineInterceptResult(destroyed, reached + intruded, totalDrones); sb.AppendLine("# 仿真评估报告"); diff --git a/src/CounterDrone.Core/Services/ReportService.cs b/src/CounterDrone.Core/Services/ReportService.cs index 5dd73a7..d45f199 100644 --- a/src/CounterDrone.Core/Services/ReportService.cs +++ b/src/CounterDrone.Core/Services/ReportService.cs @@ -26,7 +26,7 @@ namespace CounterDrone.Core.Services var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed); var reached = events.Count(e => e.Type == SimEventType.DroneReachedTarget); var intruded = events.Count(e => e.Type == SimEventType.ZoneIntruded); - var total = config.Targets.Sum(t => t.Quantity); + var total = config.Drones.Sum(t => t.Quantity); var result = _generator.DetermineInterceptResult(destroyed, reached + intruded, total); var report = new SimulationReport diff --git a/src/CounterDrone.Core/Services/ScenarioService.cs b/src/CounterDrone.Core/Services/ScenarioService.cs index 64b95cf..713a8e4 100644 --- a/src/CounterDrone.Core/Services/ScenarioService.cs +++ b/src/CounterDrone.Core/Services/ScenarioService.cs @@ -96,7 +96,7 @@ namespace CounterDrone.Core.Services Info = scenario, Scene = _sceneRepo.GetById(id) ?? new CombatScene { ScenarioId = id }, ControlZones = _zoneRepo.GetByScenarioId(id), - Targets = _targetRepo.GetByScenarioId(id), + Drones = _targetRepo.GetByScenarioId(id), Equipment = _equipRepo.GetByScenarioId(id), Cloud = _cloudRepo.GetById(id) ?? new CloudDispersal { ScenarioId = id }, Routes = _routeRepo.GetByScenarioId(id), diff --git a/src/CounterDrone.Core/Simulation/SimulationEngine.cs b/src/CounterDrone.Core/Simulation/SimulationEngine.cs index 2d8bb39..4e539be 100644 --- a/src/CounterDrone.Core/Simulation/SimulationEngine.cs +++ b/src/CounterDrone.Core/Simulation/SimulationEngine.cs @@ -103,7 +103,7 @@ namespace CounterDrone.Core.Simulation .First(a => a.AerosolType == config.Cloud.AerosolType); _drones.Clear(); - foreach (var target in config.Targets) + foreach (var target in config.Drones) { var route = config.Routes.FirstOrDefault(r => r.WaveId == target.WaveId); var wps = config.WaypointGroups.GetValueOrDefault(target.WaveId, new List()); @@ -496,14 +496,14 @@ namespace CounterDrone.Core.Simulation private static List BuildDroneWaves(ScenarioConfig config) { var groups = new List(); - foreach (var t in config.Targets) + foreach (var t in config.Drones) { var route = config.Routes.FirstOrDefault(r => r.WaveId == t.WaveId); var wps = config.WaypointGroups.GetValueOrDefault(t.WaveId, new List()); groups.Add(new DroneWave { WaveId = t.WaveId, - Target = t, + Profile = t, Route = route ?? new RoutePlan(), Waypoints = wps, }); diff --git a/src/Unity/Assets/Plugins/CounterDrone.Core/CounterDrone.Core.deps.json b/src/Unity/Assets/Plugins/CounterDrone.Core/CounterDrone.Core.deps.json index 5a510c9..39dda84 100644 --- a/src/Unity/Assets/Plugins/CounterDrone.Core/CounterDrone.Core.deps.json +++ b/src/Unity/Assets/Plugins/CounterDrone.Core/CounterDrone.Core.deps.json @@ -4,7 +4,7 @@ "signature": "" }, "compilationOptions": {}, - "targets": { + "drones": { ".NETStandard,Version=v2.1": {}, ".NETStandard,Version=v2.1/": { "CounterDrone.Core/1.0.0": { diff --git a/src/Unity/Assets/Plugins/CounterDrone.Core/CounterDrone.Core.dll b/src/Unity/Assets/Plugins/CounterDrone.Core/CounterDrone.Core.dll index ed054376edb7957e5fcb5a3c78a12b69100fb09e..23a37bf4224a009b1b6cc3931667f85167126e73 100644 GIT binary patch delta 13873 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 delta 13880 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 diff --git a/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs b/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs index 28eb6e3..448dacf 100644 --- a/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs +++ b/src/Unity/Assets/Scripts/Managers/SimulationBootstrap.cs @@ -82,7 +82,7 @@ namespace CounterDrone.Unity 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"] } + new DroneWave { WaveId = "default", Drone = detail.Drones[0], Route = detail.Routes[0], Waypoints = detail.WaypointGroups["default"] } }; var fireUnits = new List(); for (int i = 0; i < 4; i++) @@ -99,7 +99,7 @@ namespace CounterDrone.Unity scenario.SaveCloudDispersal(scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, - DisperseHeight = detail.Targets[0].TypicalAltitude, + DisperseHeight = detail.Drones[0].TypicalAltitude, Source = "Algorithm", }); scenario.SaveDeployment(scenarioId, new List diff --git a/src/Unity/Assets/StreamingAssets/defaults.json b/src/Unity/Assets/StreamingAssets/defaults.json index 331add0..a5a2ac0 100644 --- a/src/Unity/Assets/StreamingAssets/defaults.json +++ b/src/Unity/Assets/StreamingAssets/defaults.json @@ -114,7 +114,7 @@ } ], - "targets": [ + "drones": [ { "Id": "quadcopter", "Name": "[Demo] 小型四旋翼(DJI类)", "DroneType": 0, "PowerType": 0, "Wingspan": 1.2, "TypicalSpeed": 60.0, "TypicalAltitude": 300.0 }, { "Id": "electric-scout", "Name": "[Demo] 电推侦察无人机", diff --git a/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs b/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs index 343bd37..0be1670 100644 --- a/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs +++ b/test/unit/CounterDrone.Core.Tests/DefensePlannerTests.cs @@ -43,7 +43,7 @@ namespace CounterDrone.Core.Tests var t = new DroneWave { WaveId = "default", - Target = new DroneProfile + Profile = new DroneProfile { DroneType = (int)DroneType.FixedWing, PowerType = (int)power, Quantity = 1, TypicalSpeed = speed, TypicalAltitude = alt, @@ -130,7 +130,7 @@ namespace CounterDrone.Core.Tests public void MultiLane_3Drones_3Lanes_ExactOutput() { var threat = MakeThreat(speed: 200); - threat.Target.Quantity = 3; + threat.Profile.Quantity = 3; threat.Route = new RoutePlan { FormationMode = (int)Models.FormationMode.Formation, LateralSpacing = 50 }; threat.Waypoints.Clear(); threat.Waypoints.Add(new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }); @@ -378,7 +378,7 @@ namespace CounterDrone.Core.Tests var threat = new DroneWave { WaveId = "default", - Target = new DroneProfile + Profile = new DroneProfile { DroneType = (int)DroneType.FixedWing, PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500, diff --git a/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs b/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs index 14bf667..b227b6b 100644 --- a/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs @@ -36,7 +36,7 @@ namespace CounterDrone.Core.Tests var config = new ScenarioConfig { Info = new Scenario { Name = "测试任务", ScenarioNumber = "SIM-001" }, - Targets = new List { new DroneProfile { Quantity = 1 } }, + Drones = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List { new EquipmentDeployment { EquipmentRole = (int)EquipmentRole.LaunchPlatform, Quantity = 3 }, diff --git a/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs b/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs index 5915532..bc48058 100644 --- a/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ReportServiceTests.cs @@ -37,7 +37,7 @@ namespace CounterDrone.Core.Tests var config = new ScenarioConfig { Info = new Scenario { Name = "Test", ScenarioNumber = "SIM-001" }, - Targets = new List { new DroneProfile { Quantity = 1 } }, + Drones = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List(), Cloud = new CloudDispersal(), }; @@ -59,7 +59,7 @@ namespace CounterDrone.Core.Tests var config = new ScenarioConfig { Info = new Scenario { Name = "Del", ScenarioNumber = "SIM-DEL" }, - Targets = new List { new DroneProfile { Quantity = 1 } }, + Drones = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List(), Cloud = new CloudDispersal(), }; @@ -75,7 +75,7 @@ namespace CounterDrone.Core.Tests var cfg = new ScenarioConfig { Info = new Scenario { Name = "城市防御", ScenarioNumber = "SIM-A" }, - Targets = new List { new DroneProfile { Quantity = 1 } }, + Drones = new List { new DroneProfile { Quantity = 1 } }, Equipment = new List(), Cloud = new CloudDispersal(), }; diff --git a/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs b/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs index 0b786d9..b334ea1 100644 --- a/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs @@ -123,7 +123,7 @@ namespace CounterDrone.Core.Tests Assert.Equal(4, detail.Info.CurrentStep); Assert.Equal((int)SceneType.Mountain, detail.Scene.SceneType); Assert.Equal(10.0, detail.Scene.WindSpeed); - Assert.Equal(3, detail.Targets[0].Quantity); + Assert.Equal(3, detail.Drones[0].Quantity); Assert.Equal((int)AerosolType.ActiveMaterial, detail.Cloud.AerosolType); } @@ -211,7 +211,7 @@ namespace CounterDrone.Core.Tests }); var detail = _service.GetScenarioDetail(scenario.Id); - var target = detail.Targets[0]; + var target = detail.Drones[0]; Assert.Equal((int)DroneType.FixedWing, target.DroneType); Assert.Equal(5, target.Quantity); Assert.Equal(120.0, target.TypicalSpeed); @@ -464,9 +464,9 @@ namespace CounterDrone.Core.Tests Assert.Equal("核心区", detail.ControlZones[0].Name); // 目标 - Assert.Single(detail.Targets); - Assert.Equal(2, detail.Targets[0].Quantity); - Assert.Equal(300.0, detail.Targets[0].TypicalSpeed); + Assert.Single(detail.Drones); + Assert.Equal(2, detail.Drones[0].Quantity); + Assert.Equal(300.0, detail.Drones[0].TypicalSpeed); // 装备 Assert.Equal(2, detail.Equipment.Count); diff --git a/unity_plugins/CounterDrone.Core.dll b/unity_plugins/CounterDrone.Core.dll index ed054376edb7957e5fcb5a3c78a12b69100fb09e..23a37bf4224a009b1b6cc3931667f85167126e73 100644 GIT binary patch delta 13873 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 delta 13880 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