123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- using System.Collections;
- using System.Collections.Generic;
- using System.Threading;
- using UnityEngine;
- using CSVReader;
- using Processor;
- using ConfigReader;
- using Logger;
- using Networkreader;
- using System.Diagnostics;
- using System;
- namespace ObjectScripts
- {
- public class ManagerWithProzessor : AbstractManager
- {
- ///<summary>
- /// File to Read
- ///</summary>
- [SerializeField] public string EntityFilename;
- ///<summary>
- ///
- ///</summary>
- [SerializeField] public double starttime;
- ///<summary>
- ///
- ///</summary>
- [SerializeField] public bool UseStream;
- ///<summary>
- ///
- ///</summary>
- [SerializeField] public string ipAddress;
- ///<summary>
- ///
- ///</summary>
- [SerializeField] public AbstractSensorHandler SensorHandler;
- ///<summary>
- ///
- ///</summary>
- [SerializeField] public AbstractEventHandler EventHandler;
- ///<summary>
- ///
- ///</summary>
- [SerializeField] public string EventFilename;
- ///<summary>
- /// ObjectHandler that handles InputObjects
- ///</summary>
- [SerializeField] public ObjectHandler Handler;
- ///<summary>
- /// InputProzessor to read from
- ///</summary>
- private IProcessor InputProzessor;
- ///<summary>
- ///
- ///</summary>
- private float StopedGameVeloctiy;
- ///<summary>
- ///
- ///</summary>
- private float StepSizeGameVelocity;
- ///<summary>
- ///
- ///</summary>
- private int NumberDigitsGameVelocity;
- ///<summary>
- ///
- ///</summary>
- private int NumberDigitsTimeStamps;
- ///<summary>
- ///
- ///</summary>
- private InputObject NewestGameInputObject;
- ///<summary>
- /// boolean for coroutines
- ///</summary>
- private bool IsRunning;
- ///<summary>
- ///
- ///</summary>
- private IMapSensor MapSensor;
- ///<summary>
- ///
- ///</summary>
- EventCSVReader EventCSV;
- ///<summary>
- ///
- ///</summary>
- EventObject[] Events;
- ///<summary>
- ///
- ///</summary>
- private NWEventReader NWEventReader;
- ///<summary>
- ///
- ///</summary>
- private void Start()
- {
- MapSensor = new MapSensor();
- if (!ConfigParser.ParseConfig())
- CityLogger.LogWarning("Unable to parse config");
- IsRunning = true;
- this.UpdateRateInSeconds = 1 / this.UpdateRate;
- this.GameVelocity = 1f;
- StepSizeGameVelocity = 0.1f;
- NumberDigitsGameVelocity = 1;
- NumberDigitsTimeStamps = 2;
- forward = true;
- NewestTimestamp = 0;
- EarliestTimestamp = 0;
- GameTimestamp = starttime;
- ProzessorSetup();
- }
- ///<summary>
- /// Setup the InputProzessor.
- /// Starts InputProzessor and NetworkEventReader with ipAddress and port: 13000,13001
- ///
- ///</summary>
- void ProzessorSetup()
- {
- //Create InputProzessor and start streaming/reading.
- if (UseStream)
- {
- InputProzessor = new Processor.Processor(ipAddress, 13000);
- NWEventReader = new NWEventReader(ipAddress, 13001);
- InputProzessor.StartStreaming();
- this.EventFilename = NWEventReader.StartNWRead();
- }
- else
- {
- if (!EntityFilename.Equals(string.Empty))
- InputProzessor = new Processor.Processor(EntityFilename);
- InputProzessor.StartStreaming();
- }
- Stopwatch watch = new Stopwatch();
- double starttime = double.NaN;
- //Try to start stream
- watch.Start();
- while (double.IsNaN(starttime))
- {
- starttime = InputProzessor.GetOldestTimeStamp();
- Thread.Sleep(10);
- if (watch.ElapsedMilliseconds > 5000)
- {
- CityLogger.LogError("Starting stream on " + ipAddress + ":" + 13000 + " has timed out.");
- InputProzessor.StopStreaming();
- CriticalError();
- }
- }
- watch.Stop();
- EarliestTimestamp = starttime;
- if (InputProzessor.JumpToTimestamp(starttime, out _))
- {
- CityLogger.Log("Stream started", LogLevel.INFO);
- StartCoroutine(ReadData());
- }
- else
- {
- CityLogger.LogWarning("Unable to do initial jump on timestamp: " + starttime);
- InputProzessor.StopStreaming();
- CriticalError();
- }
- }
- ///<summary>
- /// Coroutine to read from InputProzessor every (1/updateRate)*Velocity seconds.
- ///</summary>
- IEnumerator ReadData()
- {
- float gv;
- //Get Event CSV Reader for reading Events
- EventCSV = new EventCSVReader(EventFilename);
- CityLogger.Log("EventFileName " + EventFilename, 0);
- MapSensor.SetSensorList(SensorHandler.SensorList);
- CityLogger.Log("Start ReadingData", LogLevel.INFO);
- endChunk = InputProzessor.GetChunkEndtimestamp();
- startChunk = InputProzessor.GetChunkStarttimestamp();
- //Start EventHandler
- EventHandler.SetUp(EventCSV, MapSensor);
- //Start Coroutine which runs every 1/UpdateRate seconds
- StartCoroutine(UpdateWithProzessorUpdateRate());
- Stopwatch watch = new Stopwatch();
- //Start Reading InputObjects
- while (this.IsRunning)
- {
- //Only read data if simulation is running
- if (this.GameVelocity > 0)
- {
- gv = this.GameVelocity;
- watch.Restart();
- HandleNextInput();
- watch.Stop();
- float updateTime = this.UpdateRateInSeconds / gv;
- float waittime = updateTime - (watch.ElapsedMilliseconds / 1000.0f);
- if (waittime < 0)
- {
- CityLogger.LogWarning("Unable to stick to update timing. Program is behind by: " + waittime * (-1));
- waittime = 0;
- }
- yield return new WaitForSecondsRealtime(waittime);
- }
- else
- {
- yield return null;
- }
- }
- }
- ///<summary>
- /// Reads values from the next timestamp
- ///</summary>
- void HandleNextInput()
- {
- List<InputObject> inputBuffer;
- inputBuffer = InputProzessor.ReadNextValues();
- if (inputBuffer.Count > 0)
- {
- //GameTimestamp is the newest read Timestamp
- this.NewestGameInputObject = inputBuffer[inputBuffer.Count - 1];
- this.GameTimestamp = this.NewestGameInputObject.Time;
- Handler.SensorList = SensorHandler.SensorList;
- if (double.IsNaN(startChunk))
- {
- startChunk = EarliestTimestamp;
- }
- if (!double.IsNaN(endChunk) && this.GameTimestamp >= endChunk)
- {
- //if next timestamp is greater then endchunk or is the last value in the Intervall [startChunk,endChunk]
- //stop the Simulation and jump to the end of the Intervall
- StopPressed();
- this.JumpToTimestamp(endChunk);
- }
- else if (this.GameTimestamp >= NewestTimestamp)
- {
- //if the simulation reads faster than it gets updates
- //set the GameVelocity to 1 and handle the input
- this.GameVelocity = 1;
- this.Handler.Handle(inputBuffer);
- }
- else if (!forward && this.GameTimestamp <= startChunk)
- {
- //if the simulation runs backwards and the next timestamp is smaller or the first value in the intervall [startChunk,endChunk]
- //stop the Simulation and jump to the start of the intervall
- StopPressed();
- this.JumpToTimestamp(startChunk);
- }
- else
- {
- //if next timestamp is in the invall handle the input
- Handler.Handle(inputBuffer);
- }
- }
- }
- ///<summary>
- /// Sets the starttime of the timeintervall the Simulation is running in.
- ///<remarks>
- /// Also sets the starttime in the Inputprozessor
- ///</remarks>
- ///</summary>
- public override void SetChunkStarttimestamp(double time)
- {
- InputProzessor.SetChunkStarttimestamp(time);
- double newTime = InputProzessor.GetChunkStarttimestamp();
- startChunk = newTime;
- }
- ///<summary>
- /// Sets the endtime of the timeintervall the Simulation is running in.
- ///<remarks>
- /// Also sets the endtime in the Inputprozessor
- ///</remarks>
- ///</summary>
- public override void SetChunkEndtimestamp(double time)
- {
- InputProzessor.SetChunkEndtimestamp(time);
- double newTime = InputProzessor.GetChunkEndtimestamp();
- endChunk = newTime;
- }
- ///<summary>
- /// coroutine which runs every 1/UpdateRate seconds
- ///</summary>
- IEnumerator UpdateWithProzessorUpdateRate()
- {
- while (this.IsRunning)
- {
- this.NewestTimestamp = this.InputProzessor.GetNewestTimeStamp();
- yield return new WaitForSecondsRealtime(this.UpdateRateInSeconds);
- }
- }
- ///<summary>
- /// Jump to timestamp.Start JumpToTimestampRoutine
- ///</summary>
- public override void JumpToTimestamp(double timestamp)
- {
- if (!double.IsNaN(timestamp))
- {
- if (this.InputProzessor != null)
- {
- StartCoroutine(JumpToTimestampRoutine(timestamp));
- }
- }
- }
- ///<summary>
- /// Start to timestamp by calling InputProzessor.JumpToTimestamp
- ///</summary>
- private IEnumerator JumpToTimestampRoutine(double timestamp)
- {
- if (this.InputProzessor.JumpToTimestamp(timestamp, out double x))
- {
- //Clear the scene
- //Destroying an objects needs 1 frame
- this.Handler.ClearAll();
- yield return null;
- //InputProzessor needs some time to jump to the timestamp
- yield return new WaitForSecondsRealtime(0.25f);
- if (x != -1)
- this.GameTimestamp = x;
- //Handle the next Input.
- HandleNextInput();
- CityLogger.Log(string.Format("Timestamp returned from Prozessor {0}, timestamp Parameter {1}, InputBufferTimestamp{2}", x, timestamp, this.NewestGameInputObject.Time), LogLevel.DEBUG);
- }
- else CityLogger.Log("Couldn't Jump " + timestamp, LogLevel.INFO);
- yield return null;
- }
- ///<summary>
- /// Reverse Simulation
- ///</summary>
- public void ReverseTime()
- {
- this.forward = !this.forward;
- this.InputProzessor.ReverseTime();
- }
- private void OnDestroy()
- {
- //if the GameObject gets destroyed
- //stop streaming
- if (InputProzessor != null)
- {
- InputProzessor.StopStreaming();
- }
- if (NWEventReader != null)
- {
- NWEventReader.StopReading();
- }
- IsRunning = false;
- }
- private void CriticalError()
- {
- CityLogger.LogError("Encountered critical error. Shutting down application...");
- #if UNITY_EDITOR
- UnityEditor.EditorApplication.isPlaying = false;
- UnityEditor.EditorApplication.Exit(0);
- #else
- Application.Quit();
- #endif
- Environment.Exit(0);
- }
- ///<summary>
- /// Set Velocity to the last Velocity known before stop was pressed
- ///</summary>
- public override void PlayPressed()
- {
- if (this.GameVelocity == 0)
- {
- //if the GameVelocity is 0
- //change the GameVelocity to the savedGameVelocity
- //if the GameVeloctiy was changed to 0 by using the plus and minus button
- //the saved GameVelocity will be the velocity from the last StopPressed()
- this.GameVelocity = this.StopedGameVeloctiy;
- CityLogger.Log("PlayPressed" + this.GameVelocity.ToString(), LogLevel.DEBUG);
- }
- }
- ///<summary>
- /// Save Veloctiy and set velocity to 0.
- ///</summary>
- public override void StopPressed()
- {
- if (this.GameVelocity > 0)
- {
- // if the GameVelocity is greater 0
- // save the current GameVelocity and change the GameVelocity to 0
- this.StopedGameVeloctiy = this.GameVelocity;
- this.GameVelocity = 0;
- CityLogger.Log("StopPressed" + this.StopedGameVeloctiy.ToString(), LogLevel.DEBUG);
- }
- }
- ///<summary>
- /// Reverse Simulation
- ///</summary>
- public override void ReversePressed()
- {
- this.ReverseTime();
- CityLogger.Log("ReversePressed", LogLevel.DEBUG);
- }
- ///<summary>
- /// Increase velocity by StepSizeGameVelocity
- ///</summary>
- public override void PlusPressed()
- {
- //Increase GameVelocity
- //no limit
- this.GameVelocity = this.RoundWithDigits(this.GameVelocity + this.StepSizeGameVelocity, this.NumberDigitsGameVelocity);
- CityLogger.Log("PlusPressed" + this.GameVelocity.ToString(), LogLevel.DEBUG);
- }
- ///<summary>
- /// Decrease velocity by StepSizeGameVelocity.
- ///</summary>
- public override void MinusPressed()
- {
- //Decrease GameVelocity
- // always greater 0
- this.GameVelocity = this.RoundWithDigits(this.GameVelocity - this.StepSizeGameVelocity, this.NumberDigitsGameVelocity);
- if (this.GameVelocity < 0)
- {
- this.GameVelocity = 0;
- }
- CityLogger.Log("MinusPressed" + this.GameVelocity.ToString(), LogLevel.DEBUG);
- }
- ///<summary>
- /// Rounds number
- ///</summary>
- private float RoundWithDigits(float value, int NumberDigits)
- {
- //try to prevent round errors
- //for example 0.1 - 0.1 returned a extrem small number and
- //yield return new WaitForSecondsRealtime(1 / (this.UpdateRate * this.GameVelocity));
- // would be a very long time.
- return Mathf.Round(value * Mathf.Pow(10, NumberDigits)) / (Mathf.Pow(10, NumberDigits));
- }
- ///<summary>
- /// Rounds number
- ///</summary>
- private double RoundWithDigits(double value, int NumberDigits)
- {
- return (double)Mathf.Round((float)value * Mathf.Pow(10, NumberDigits)) / (Mathf.Pow(10, NumberDigits));
- }
- }
- }
|