< Summary

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

Metrics

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

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
 033  public static SimMonitor Instance { get; private set; }
 34
 035  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
 049  private bool _isLoggingDestroyed = false;
 50
 051  private void Awake() {
 052    if (Instance != null && Instance != this) {
 053      Destroy(gameObject);
 054      return;
 55    }
 056    Instance = this;
 057    DontDestroyOnLoad(gameObject);
 058  }
 59
 060  private void Start() {
 061    SimManager.Instance.OnSimulationStarted += RegisterSimulationStarted;
 062    SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
 063    SimManager.Instance.OnNewThreat += RegisterNewThreat;
 064    SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
 065  }
 66
 067  private void OnDestroy() {
 068    DestroyLogging();
 069  }
 70
 071  private void RegisterSimulationStarted() {
 072    _isLoggingDestroyed = false;
 073    Timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
 074    InitializeSessionDirectory();
 075    if (SimManager.Instance.SimulatorConfig.EnableTelemetryLogging) {
 076      InitializeTelemetryLogging();
 077      _monitorRoutine = StartCoroutine(MonitorRoutine());
 078    }
 079    if (SimManager.Instance.SimulatorConfig.EnableEventLogging) {
 080      InitializeEventLogging();
 081    }
 082  }
 83
 084  private void RegisterSimulationEnded() {
 085    DestroyLogging();
 086  }
 87
 088  private void RegisterNewInterceptor(IInterceptor interceptor) {
 089    RegisterAgentEvent(interceptor, EventTypes.NewInterceptor);
 090    interceptor.OnHit += RegisterInterceptorHit;
 091    interceptor.OnMiss += RegisterInterceptorMiss;
 092    interceptor.OnDestroyed += RegisterInterceptorDestroyed;
 093  }
 94
 095  private void RegisterNewThreat(IThreat threat) {
 096    RegisterAgentEvent(threat, EventTypes.NewThreat);
 097    threat.OnHit += RegisterThreatHit;
 098    threat.OnDestroyed += RegisterThreatDestroyed;
 099  }
 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
 0121  private void RegisterAgentEvent(IAgent agent, string eventType) {
 0122    if (SimManager.Instance.SimulatorConfig.EnableEventLogging) {
 0123      float time = SimManager.Instance.ElapsedTime;
 0124      Vector3 position = agent.Position;
 0125      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      };
 0134      _eventLog.Add(record);
 0135    }
 0136  }
 137
 0138  private void InitializeSessionDirectory() {
 0139    if (RunWorker.IsWorkerMode) {
 0140      _sessionDirectory = RunWorker.OutputDirectory;
 0141    } else {
 0142      _sessionDirectory = Path.Combine(Application.persistentDataPath, "Logs",
 143                                       $"run_{SimManager.Instance.Timestamp}");
 0144    }
 0145    Directory.CreateDirectory(_sessionDirectory);
 0146    Debug.Log($"Monitoring simulation logs to {_sessionDirectory}.");
 0147  }
 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
 0158  private void InitializeEventLogging() {
 0159    string eventLog = $"sim_events_{Timestamp}.csv";
 0160    _eventLogPath = Path.Combine(_sessionDirectory, eventLog);
 0161    _eventLog = new List<EventRecord>();
 0162    Debug.Log($"Event log initialized successfully: {eventLog}.");
 0163  }
 164
 0165  private void DestroyLogging() {
 0166    if (_isLoggingDestroyed) {
 0167      return;
 168    }
 0169    _isLoggingDestroyed = true;
 170
 0171    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    }
 0181    if (SimManager.Instance.SimulatorConfig.EnableEventLogging) {
 0182      WriteEventsToFile();
 0183    }
 0184  }
 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
 0270  private void WriteEventsToFile() {
 0271    using (var writer = new StreamWriter(_eventLogPath, append: false)) {
 272      // Write the CSV header.
 0273      writer.WriteLine("Time,Event,AgentType,AgentID,PositionX,PositionY,PositionZ");
 274
 0275      foreach (var record in _eventLog) {
 0276        writer.WriteLine(
 277            $"{record.Time:F2},{record.EventType},{record.AgentType},{record.AgentID}," +
 278            $"{record.PositionX:F2},{record.PositionY:F2},{record.PositionZ:F2}");
 0279      }
 0280    }
 0281  }
 282}