< Summary

Class:SimMonitor
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Monitors/SimMonitor.cs
Covered lines:75
Uncovered lines:104
Coverable lines:179
Total lines:282
Line coverage:41.8% (75 of 179)
Covered branches:0
Total branches:0
Covered methods:16
Total methods:27
Method coverage:59.2% (16 of 27)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
SimMonitor()0%110100%
Awake()0%3.473062.5%
Start()0%110100%
OnDestroy()0%2100%
RegisterSimulationStarted()0%3.213071.43%
RegisterSimulationEnded()0%110100%
RegisterNewInterceptor(...)0%110100%
RegisterNewThreat(...)0%110100%
RegisterInterceptorHit(...)0%2100%
RegisterInterceptorMiss(...)0%2100%
RegisterInterceptorDestroyed(...)0%2100%
RegisterThreatHit(...)0%2100%
RegisterThreatDestroyed(...)0%2100%
RegisterAgentEvent(...)0%220100%
InitializeSessionDirectory()0%2.082072.73%
InitializeTelemetryLogging()0%2100%
InitializeEventLogging()0%110100%
DestroyLogging()0%9.665042.86%
DestroyTelemetryLogging()0%12300%
MonitorRoutine()0%12300%
RecordTelemetry()0%42600%
ConvertTelemetryBinaryToCsv(...)0%30500%
WriteEventsToFile()0%330100%

File(s)

/github/workspace/Assets/Scripts/Monitors/SimMonitor.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.IO;
 5using System.Linq;
 6using UnityEngine;
 7
 8public class SimMonitor : MonoBehaviour {
 9  private static class EventTypes {
 10    public const string NewInterceptor = "NEW_INTERCEPTOR";
 11    public const string NewThreat = "NEW_THREAT";
 12    public const string InterceptorHit = "INTERCEPTOR_HIT";
 13    public const string InterceptorMiss = "INTERCEPTOR_MISS";
 14    public const string InterceptorDestroyed = "INTERCEPTOR_DESTROYED";
 15    public const string ThreatHit = "THREAT_HIT";
 16    public const string ThreatDestroyed = "THREAT_DESTROYED";
 17  }
 18
 19  [Serializable]
 20  private class EventRecord {
 21    public float Time;
 22    public string EventType;
 23    public string AgentType;
 24    public string AgentID;
 25    public float PositionX;
 26    public float PositionY;
 27    public float PositionZ;
 28  }
 29
 30  // Telemetry update period in seconds.
 31  private const float _updatePeriod = 0.1f;  // 10 Hz
 32
 233  public static SimMonitor Instance { get; private set; }
 34
 2635  public string Timestamp { get; private set; } = "";
 36
 37  private Coroutine _monitorRoutine;
 38
 39  private string _sessionDirectory;
 40
 41  private string _telemetryBinPath;
 42  private FileStream _telemetryFileStream;
 43  private BinaryWriter _telemetryBinaryWriter;
 44
 45  private string _eventLogPath;
 46  [SerializeField]
 47  private List<EventRecord> _eventLog;
 48
 249  private bool _isLoggingDestroyed = false;
 50
 151  private void Awake() {
 152    if (Instance != null && Instance != this) {
 053      Destroy(gameObject);
 054      return;
 55    }
 156    Instance = this;
 157    DontDestroyOnLoad(gameObject);
 158  }
 59
 160  private void Start() {
 161    SimManager.Instance.OnSimulationStarted += RegisterSimulationStarted;
 162    SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
 163    SimManager.Instance.OnNewThreat += RegisterNewThreat;
 164    SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
 165  }
 66
 067  private void OnDestroy() {
 068    DestroyLogging();
 069  }
 70
 1271  private void RegisterSimulationStarted() {
 1272    _isLoggingDestroyed = false;
 1273    Timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
 1274    InitializeSessionDirectory();
 1275    if (SimManager.Instance.SimulatorConfig.EnableTelemetryLogging) {
 076      InitializeTelemetryLogging();
 077      _monitorRoutine = StartCoroutine(MonitorRoutine());
 078    }
 2479    if (SimManager.Instance.SimulatorConfig.EnableEventLogging) {
 1280      InitializeEventLogging();
 1281    }
 1282  }
 83
 1184  private void RegisterSimulationEnded() {
 1185    DestroyLogging();
 1186  }
 87
 2688  private void RegisterNewInterceptor(IInterceptor interceptor) {
 2689    RegisterAgentEvent(interceptor, EventTypes.NewInterceptor);
 2690    interceptor.OnHit += RegisterInterceptorHit;
 2691    interceptor.OnMiss += RegisterInterceptorMiss;
 2692    interceptor.OnDestroyed += RegisterInterceptorDestroyed;
 2693  }
 94
 95595  private void RegisterNewThreat(IThreat threat) {
 95596    RegisterAgentEvent(threat, EventTypes.NewThreat);
 95597    threat.OnHit += RegisterThreatHit;
 95598    threat.OnDestroyed += RegisterThreatDestroyed;
 95599  }
 100
 0101  private void RegisterInterceptorHit(IInterceptor interceptor) {
 0102    RegisterAgentEvent(interceptor, EventTypes.InterceptorHit);
 0103  }
 104
 0105  private void RegisterInterceptorMiss(IInterceptor interceptor) {
 0106    RegisterAgentEvent(interceptor, EventTypes.InterceptorMiss);
 0107  }
 108
 0109  private void RegisterInterceptorDestroyed(IInterceptor interceptor) {
 0110    RegisterAgentEvent(interceptor, EventTypes.InterceptorDestroyed);
 0111  }
 112
 0113  private void RegisterThreatHit(IThreat threat) {
 0114    RegisterAgentEvent(threat, EventTypes.ThreatHit);
 0115  }
 116
 0117  private void RegisterThreatDestroyed(IThreat threat) {
 0118    RegisterAgentEvent(threat, EventTypes.ThreatDestroyed);
 0119  }
 120
 981121  private void RegisterAgentEvent(IAgent agent, string eventType) {
 1962122    if (SimManager.Instance.SimulatorConfig.EnableEventLogging) {
 981123      float time = SimManager.Instance.ElapsedTime;
 981124      Vector3 position = agent.Position;
 981125      var record = new EventRecord {
 126        Time = time,
 127        EventType = eventType,
 128        AgentType = agent.StaticConfig.AgentType.ToString(),
 129        AgentID = agent.gameObject.name,
 130        PositionX = position.x,
 131        PositionY = position.y,
 132        PositionZ = position.z,
 133      };
 981134      _eventLog.Add(record);
 981135    }
 981136  }
 137
 12138  private void InitializeSessionDirectory() {
 12139    if (RunWorker.IsWorkerMode) {
 0140      _sessionDirectory = RunWorker.OutputDirectory;
 12141    } else {
 12142      _sessionDirectory = Path.Combine(Application.persistentDataPath, "Logs",
 143                                       $"run_{SimManager.Instance.Timestamp}");
 12144    }
 12145    Directory.CreateDirectory(_sessionDirectory);
 12146    Debug.Log($"Monitoring simulation logs to {_sessionDirectory}.");
 12147  }
 148
 0149  private void InitializeTelemetryLogging() {
 0150    string telemetryFile = $"sim_telemetry_{Timestamp}.bin";
 0151    _telemetryBinPath = Path.Combine(_sessionDirectory, telemetryFile);
 0152    _telemetryFileStream =
 153        new FileStream(_telemetryBinPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
 0154    _telemetryBinaryWriter = new BinaryWriter(_telemetryFileStream);
 0155    Debug.Log($"Telemetry file initialized successfully: {telemetryFile}.");
 0156  }
 157
 12158  private void InitializeEventLogging() {
 12159    string eventLog = $"sim_events_{Timestamp}.csv";
 12160    _eventLogPath = Path.Combine(_sessionDirectory, eventLog);
 12161    _eventLog = new List<EventRecord>();
 12162    Debug.Log($"Event log initialized successfully: {eventLog}.");
 12163  }
 164
 11165  private void DestroyLogging() {
 11166    if (_isLoggingDestroyed) {
 0167      return;
 168    }
 11169    _isLoggingDestroyed = true;
 170
 11171    if (SimManager.Instance.SimulatorConfig.EnableTelemetryLogging) {
 0172      if (_monitorRoutine != null) {
 0173        StopCoroutine(_monitorRoutine);
 0174        _monitorRoutine = null;
 0175      }
 0176      RecordTelemetry();
 0177      DestroyTelemetryLogging();
 0178      ConvertTelemetryBinaryToCsv(_telemetryBinPath,
 179                                  Path.ChangeExtension(_telemetryBinPath, ".csv"));
 0180    }
 22181    if (SimManager.Instance.SimulatorConfig.EnableEventLogging) {
 11182      WriteEventsToFile();
 11183    }
 11184  }
 185
 0186  private void DestroyTelemetryLogging() {
 0187    if (_telemetryBinaryWriter != null) {
 0188      _telemetryBinaryWriter.Flush();
 0189      _telemetryBinaryWriter.Close();
 0190      _telemetryBinaryWriter = null;
 0191    }
 192
 0193    if (_telemetryFileStream != null) {
 0194      _telemetryFileStream.Close();
 0195      _telemetryFileStream = null;
 0196    }
 0197  }
 198
 0199  private IEnumerator MonitorRoutine() {
 0200    while (true) {
 0201      RecordTelemetry();
 0202      yield return new WaitForSeconds(_updatePeriod);
 0203    }
 204  }
 205
 0206  private void RecordTelemetry() {
 0207    if (_telemetryBinaryWriter == null) {
 0208      Debug.LogWarning("Telemetry binary writer is null.");
 0209      return;
 210    }
 211
 0212    float time = SimManager.Instance.ElapsedTime;
 0213    var agents = SimManager.Instance.Agents.OfType<AgentBase>().Where(
 0214        agent => agent != null && !agent.IsTerminated && agent.gameObject.activeInHierarchy);
 0215    foreach (var agent in agents) {
 0216      Vector3 position = agent.Position;
 0217      if (position == Vector3.zero) {
 0218        continue;
 219      }
 0220      Vector3 velocity = agent.Velocity;
 221
 222      // Write telemetry data directly to the binary file.
 0223      _telemetryBinaryWriter.Write(time);
 0224      _telemetryBinaryWriter.Write((int)agent.StaticConfig.AgentType);
 0225      _telemetryBinaryWriter.Write(agent.gameObject.name);
 0226      _telemetryBinaryWriter.Write(position.x);
 0227      _telemetryBinaryWriter.Write(position.y);
 0228      _telemetryBinaryWriter.Write(position.z);
 0229      _telemetryBinaryWriter.Write(velocity.x);
 0230      _telemetryBinaryWriter.Write(velocity.y);
 0231      _telemetryBinaryWriter.Write(velocity.z);
 0232    }
 0233  }
 234
 0235  private void ConvertTelemetryBinaryToCsv(string binaryFilePath, string csvFilePath) {
 0236    try {
 0237      using var fs =
 238          new FileStream(binaryFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
 0239      using var reader = new BinaryReader(fs);
 0240      using var writer = new StreamWriter(csvFilePath, false);
 0241      {
 242        // Write the CSV header.
 0243        writer.WriteLine(
 244            "Time,AgentType,AgentID,PositionX,PositionY,PositionZ,VelocityX,VelocityY,VelocityZ");
 245
 0246        while (reader.BaseStream.Position != reader.BaseStream.Length) {
 0247          float time = reader.ReadSingle();
 0248          var agentType = (Configs.AgentType)reader.ReadInt32();
 0249          string agentID = reader.ReadString();
 0250          float positionX = reader.ReadSingle();
 0251          float positionY = reader.ReadSingle();
 0252          float positionZ = reader.ReadSingle();
 0253          float velocityX = reader.ReadSingle();
 0254          float velocityY = reader.ReadSingle();
 0255          float velocityZ = reader.ReadSingle();
 256
 257          // Write the data to CSV.
 0258          writer.WriteLine($"{time:F2},{agentType.ToString()},{agentID}," +
 259                           $"{positionX:F2},{positionY:F2},{positionZ:F2}," +
 260                           $"{velocityX:F2},{velocityY:F2},{velocityZ:F2}");
 0261        }
 0262        Debug.Log($"Telemetry CSV file converted successfully: {csvFilePath}.");
 0263      }
 0264    } catch (IOException e) {
 0265      Debug.LogWarning(
 266          $"An IO error occurred while converting binary telemetry file to CSV format: {e.Message}.");
 0267    }
 0268  }
 269
 11270  private void WriteEventsToFile() {
 22271    using (var writer = new StreamWriter(_eventLogPath, append: false)) {
 272      // Write the CSV header.
 11273      writer.WriteLine("Time,Event,AgentType,AgentID,PositionX,PositionY,PositionZ");
 274
 2949275      foreach (var record in _eventLog) {
 972276        writer.WriteLine(
 277            $"{record.Time:F2},{record.EventType},{record.AgentType},{record.AgentID}," +
 278            $"{record.PositionX:F2},{record.PositionY:F2},{record.PositionZ:F2}");
 972279      }
 11280    }
 11281  }
 282}