ThreatSourceLibaray/tools/Program.cs
Tian jianyong bece0866b3 - 修改了版本号格式(0.2.18 -> 1.1.18)
- 修改了日志输出格式
- 飞行全程增加重力加速度
- 完善发射段的推力加速度计算
- 修改各导弹配置文件的初始发射速度、发动机燃烧时间
- 修改集成测试中导弹的发射距离、发射高度、发射角度
2025-05-14 20:23:57 +08:00

395 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using ThreatSource.Utils;
using ThreatSource.Jammer;
using System;
using System.Threading;
using System.Diagnostics;
using System.Linq;
namespace ThreatSource.Tools.MissileSimulation
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("综合导弹模拟程序启动...");
var simulator = new ComprehensiveMissileSimulator();
// Set a default log level on startup if desired, or rely on Simulator's default
// simulator.SetLogLevel(SourceLevels.Information);
ApplicationHostLoop(simulator);
Console.WriteLine("\n程序已退出。");
}
static void ApplicationHostLoop(ComprehensiveMissileSimulator simulator)
{
bool exitProgram = false;
while (!exitProgram)
{
Console.WriteLine("\n=== 导弹仿真系统主菜单 ===");
string missileStatus = string.IsNullOrEmpty(simulator.SelectedMissileId) ? "未选择" : $"已选: {simulator.SelectedMissileDisplayName}";
string sensorStatusString = "";
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
{
var indicators = simulator.GetActiveIndicators();
var firstActiveIndicator = indicators.FirstOrDefault(ind => ind.IsActive);
if (firstActiveIndicator.Name != null) // Name is a string, check for null if tuple might not be found
{
sensorStatusString = $"(已激活: {firstActiveIndicator.Name})";
}
else
{
sensorStatusString = "(无默认激活指示器)"; // Or "(配置)" or similar
}
}
else
{
sensorStatusString = "(需先选导弹)";
}
Console.WriteLine($"1. 选择导弹 ({missileStatus})");
Console.WriteLine($"2. 配置传感器 {sensorStatusString}");
Console.WriteLine($"3. 配置干扰 {simulator.GetActiveJammingDescription()} {(string.IsNullOrEmpty(simulator.SelectedMissileId) ? "()" : "")}");
Console.WriteLine($"4. 设置日志级别 (当前级别: {simulator.CurrentLogLevel})");
Console.WriteLine($"5. 开始仿真 {(string.IsNullOrEmpty(simulator.SelectedMissileId) ? "()" : "")}");
Console.WriteLine($"6. 设置仿真步长 (当前: {simulator.TimeStep}s)");
Console.WriteLine("0. 退出程序");
Console.Write("\n请选择: ");
string choice = Console.ReadLine()?.ToLower() ?? string.Empty;
switch (choice)
{
case "1":
SelectMissile(simulator);
break;
case "2":
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
ConfigureSensors(simulator);
else
Console.WriteLine("请先选择导弹。");
break;
case "3":
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
ConfigureJamming(simulator);
else
Console.WriteLine("请先选择导弹。");
break;
case "4":
ShowLogLevelMenu(simulator);
break;
case "5":
if (!string.IsNullOrEmpty(simulator.SelectedMissileId))
{
RunSimulationInstance(simulator);
}
else
{
Console.WriteLine("请先选择导弹并完成基本配置 (选择导弹是启动仿真的最低要求)。");
}
break;
case "6":
ConfigureTimeStep(simulator);
break;
case "0":
exitProgram = true;
break;
default:
Console.WriteLine("无效选择,请重试。");
break;
}
}
}
// Placeholder for ShowLogLevelMenu - to be implemented next
static void ShowLogLevelMenu(ComprehensiveMissileSimulator simulator)
{
bool backToMainMenu = false;
while (!backToMainMenu)
{
Console.WriteLine("\n--- 设置日志级别 ---");
Console.WriteLine("1. Off (关闭所有Trace/Debug输出)");
Console.WriteLine("2. Error (仅错误信息)");
Console.WriteLine("3. Warning (警告及错误)");
Console.WriteLine("4. Information (普通信息、警告、错误)");
Console.WriteLine("5. Verbose (所有信息包括Debug.WriteLine)");
Console.WriteLine("0. 返回主菜单");
Console.Write("请选择日志级别: ");
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
SourceLevels currentLevel = simulator.CurrentLogLevel; // Use the new public property
SourceLevels selectedLevel = currentLevel; // Default to current if invalid choice
bool levelSet = false;
switch (input)
{
case "1": selectedLevel = SourceLevels.Off; levelSet = true; break;
case "2": selectedLevel = SourceLevels.Error; levelSet = true; break;
case "3": selectedLevel = SourceLevels.Warning; levelSet = true; break;
case "4": selectedLevel = SourceLevels.Information; levelSet = true; break;
case "5": selectedLevel = SourceLevels.Verbose; levelSet = true; break;
case "0": backToMainMenu = true; break;
default: Console.WriteLine("无效选择,请重试。"); break;
}
if (levelSet)
{
simulator.SetLogLevel(selectedLevel);
// Confirmation is printed by SetLogLevel in simulator
return; // Return to main menu after setting level
}
}
}
// Placeholder for RunSimulationInstance - to be implemented next
static void RunSimulationInstance(ComprehensiveMissileSimulator simulator)
{
Console.WriteLine("\n--- 开始仿真 --- ");
var simulationEndedEvent = new ManualResetEvent(false);
simulator.SimulationEnded += (sender, e) => {
simulationEndedEvent.Set();
// Unsubscribe to prevent issues if RunSimulationInstance is called again
if (sender is ComprehensiveMissileSimulator sim) // C# 7.0 pattern matching
{
sim.SimulationEnded -= (s, args) => simulationEndedEvent.Set(); // Attempt to unsubscribe, exact lambda match is tricky
}
};
var simulationThread = new Thread(simulator.Start);
simulationThread.Start();
Console.WriteLine("仿真已开始运行。在主菜单输入 '0' 可在下次返回主菜单时退出程序。");
Console.WriteLine("仿真过程中,您可以随时按 Enter 键尝试提前中止当前仿真实例并返回主菜单。");
bool simulationForceStopped = false;
while (!simulationEndedEvent.WaitOne(100)) // Check every 100ms if simulation ended naturally
{
if (Console.KeyAvailable)
{
// Read the key, but don't wait if it was just a check.
// We want to allow Enter to break, not necessarily other typed commands during active sim.
// A simple Console.ReadLine() here would block until Enter.
// If user presses Enter, ReadLine will return empty or the character if it was typed fast enough.
var keyInfo = Console.ReadKey(intercept: true); // Intercept to prevent display
if (keyInfo.Key == ConsoleKey.Enter)
{
Console.WriteLine("\n用户请求中止当前仿真实例...");
simulator.Stop(); // Request simulator to stop
simulationForceStopped = true;
break; // Exit the wait loop
}
// If other keys are pressed, we can choose to ignore them or buffer them for a potential command parser later.
// For now, only Enter is an active interrupt.
}
}
// Wait for the simulation thread to actually finish, especially if force stopped.
simulationThread.Join();
if (simulationForceStopped)
{
Console.WriteLine("当前仿真实例已被用户中止。");
}
else
{
Console.WriteLine("当前导弹仿真自然结束。");
}
Console.WriteLine("按任意键返回主菜单...");
Console.ReadKey(); // Wait for user to acknowledge before returning to main menu
}
static void SelectMissile(ComprehensiveMissileSimulator simulator)
{
var missiles = new[]
{
("LSGM_1", "激光半主动制导导弹"),
("LBRM_1", "激光驾束制导导弹"),
("TSM_1", "末敏弹"),
("ICGM_1", "红外指令制导导弹"),
("ITGM_1", "红外成像末制导导弹"),
("MMWG_1", "毫米波末制导导弹")
};
while (true)
{
Console.WriteLine("\n--- 选择导弹类型 ---");
for (int i = 0; i < missiles.Length; i++)
{
Console.WriteLine($" {i + 1}. {missiles[i].Item2}");
}
Console.WriteLine(" 0. 返回主菜单");
Console.Write("请选择: ");
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
if (input == "0")
return;
if (int.TryParse(input, out int choice) &&
choice >= 1 && choice <= missiles.Length)
{
simulator.SelectMissile(missiles[choice - 1].Item1);
Console.WriteLine($"已选择: {simulator.SelectedMissileDisplayName}");
return;
}
Console.WriteLine("无效选择,请重试。");
}
}
static void ConfigureSensors(ComprehensiveMissileSimulator simulator)
{
while (true)
{
Console.WriteLine("\n--- 配置传感器和指示器 ---");
Console.WriteLine("当前传感器状态:");
var indicators = simulator.GetActiveIndicators();
if (indicators.Length == 0)
{
Console.WriteLine("当前导弹类型没有可配置的独立传感器/指示器,或未实现获取接口。");
}
else
{
for (int i = 0; i < indicators.Length; i++)
{
Console.WriteLine($" {i + 1}. {indicators[i].Name} [{(indicators[i].IsActive ? "" : "")}]");
}
}
Console.WriteLine(" 0. 返回主菜单");
Console.Write("请选择切换状态的传感器,或返回: ");
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
if (input == "0")
return;
if (int.TryParse(input, out int choice))
{
if (choice >= 1 && choice <= indicators.Length)
{
simulator.ToggleIndicator(indicators[choice - 1].Id);
// Loop continues to show updated status
return; // Return to main menu after toggling sensor
}
else
{
Console.WriteLine("无效选择,请重试。");
}
}
else
{
Console.WriteLine("无效输入,请输入数字。");
}
}
}
static void ConfigureJamming(ComprehensiveMissileSimulator simulator)
{
var availableJammingOptions = simulator.GetAvailableJammingOptions();
var currentlyActiveJammingsFromSimulator = simulator.GetCurrentlyActiveJammings();
var jammingStatus = new bool[availableJammingOptions.Length];
for (int i = 0; i < availableJammingOptions.Length; i++)
{
var currentOptionForLoop = availableJammingOptions[i]; // Renamed to avoid conflict
if (currentlyActiveJammingsFromSimulator.Any(activeJam => activeJam.JammerId == currentOptionForLoop.JammerId && activeJam.Type == currentOptionForLoop.Type))
{
jammingStatus[i] = true;
}
else
{
jammingStatus[i] = false;
}
}
while (true)
{
Console.WriteLine("\n--- 配置干扰方式 ---");
Console.WriteLine($"当前导弹: {simulator.SelectedMissileDisplayName}");
if (availableJammingOptions.Length == 0)
{
Console.WriteLine("当前导弹类型没有可配置的干扰选项。");
}
else
{
Console.WriteLine("可用干扰方式:");
for (int i = 0; i < availableJammingOptions.Length; i++)
{
var option = availableJammingOptions[i];
// To get actual status, you'd query simulator: e.g., simulator.IsJammerActive(option.JammerId)
// For now, we use local `jammingStatus` which is temporary for this menu session.
Console.WriteLine($" {i + 1}. {option.DisplayName} [{(jammingStatus[i] ? "" : "")}] " +
$"(干扰模式: {option.Mode}, 作用对象: {option.Target})");
}
}
Console.WriteLine(" 0. 返回主菜单");
Console.Write("请选择切换状态的干扰项,或返回: ");
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
if (input == "0")
return;
if (int.TryParse(input, out int choice))
{
if (choice >= 1 && choice <= availableJammingOptions.Length)
{
var option = availableJammingOptions[choice - 1];
jammingStatus[choice - 1] = !jammingStatus[choice - 1]; // Toggle local status for display
if (jammingStatus[choice - 1])
simulator.ApplyJamming(option.Type, option.DisplayName, option.JammerId, option.Mode, option.Target);
else
simulator.ClearJamming(option.Type, option.DisplayName, option.JammerId);
// Loop continues
return; // Return to main menu after applying/clearing jamming
}
else
{
Console.WriteLine("无效选择,请重试。");
}
}
else
{
Console.WriteLine("无效输入,请输入数字。");
}
}
}
static void ConfigureTimeStep(ComprehensiveMissileSimulator simulator)
{
bool backToMainMenu = false;
while (!backToMainMenu)
{
Console.WriteLine("\n--- 设置仿真步长 ---");
Console.WriteLine($"当前步长: {simulator.TimeStep}s");
Console.WriteLine("1. 低精度 (0.02s)");
Console.WriteLine("2. 中精度 (0.01s)");
Console.WriteLine("3. 高精度 (0.005s)");
Console.WriteLine("0. 返回主菜单");
Console.Write("请选择步长: ");
string input = Console.ReadLine()?.ToLower() ?? string.Empty;
switch (input)
{
case "1":
simulator.TimeStep = 0.02;
Console.WriteLine($"仿真步长已设置为: {simulator.TimeStep}s (低精度)");
return; // 设置后返回主菜单
case "2":
simulator.TimeStep = 0.01;
Console.WriteLine($"仿真步长已设置为: {simulator.TimeStep}s (中精度)");
return; // 设置后返回主菜单
case "3":
simulator.TimeStep = 0.005;
Console.WriteLine($"仿真步长已设置为: {simulator.TimeStep}s (高精度)");
return; // 设置后返回主菜单
case "0":
backToMainMenu = true;
break;
default:
Console.WriteLine("无效选择,请重试。");
break;
}
}
}
}
}