ManagerWithProzessor.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using UnityEngine;
  5. using CSVReader;
  6. using Processor;
  7. using ConfigReader;
  8. using Logger;
  9. using Networkreader;
  10. using System.Diagnostics;
  11. using System;
  12. namespace ObjectScripts
  13. {
  14. public class ManagerWithProzessor : AbstractManager
  15. {
  16. ///<summary>
  17. /// File to Read
  18. ///</summary>
  19. [SerializeField] public string EntityFilename;
  20. ///<summary>
  21. ///
  22. ///</summary>
  23. [SerializeField] public double starttime;
  24. ///<summary>
  25. ///
  26. ///</summary>
  27. [SerializeField] public bool UseStream;
  28. ///<summary>
  29. ///
  30. ///</summary>
  31. [SerializeField] public string ipAddress;
  32. ///<summary>
  33. ///
  34. ///</summary>
  35. [SerializeField] public AbstractSensorHandler SensorHandler;
  36. ///<summary>
  37. ///
  38. ///</summary>
  39. [SerializeField] public AbstractEventHandler EventHandler;
  40. ///<summary>
  41. ///
  42. ///</summary>
  43. [SerializeField] public string EventFilename;
  44. ///<summary>
  45. /// ObjectHandler that handles InputObjects
  46. ///</summary>
  47. [SerializeField] public ObjectHandler Handler;
  48. ///<summary>
  49. /// InputProzessor to read from
  50. ///</summary>
  51. private IProcessor InputProzessor;
  52. ///<summary>
  53. ///
  54. ///</summary>
  55. private float StopedGameVeloctiy;
  56. ///<summary>
  57. ///
  58. ///</summary>
  59. private float StepSizeGameVelocity;
  60. ///<summary>
  61. ///
  62. ///</summary>
  63. private int NumberDigitsGameVelocity;
  64. ///<summary>
  65. ///
  66. ///</summary>
  67. private int NumberDigitsTimeStamps;
  68. ///<summary>
  69. ///
  70. ///</summary>
  71. private InputObject NewestGameInputObject;
  72. ///<summary>
  73. /// boolean for coroutines
  74. ///</summary>
  75. private bool IsRunning;
  76. ///<summary>
  77. ///
  78. ///</summary>
  79. private IMapSensor MapSensor;
  80. ///<summary>
  81. ///
  82. ///</summary>
  83. EventCSVReader EventCSV;
  84. ///<summary>
  85. ///
  86. ///</summary>
  87. EventObject[] Events;
  88. ///<summary>
  89. ///
  90. ///</summary>
  91. private NWEventReader NWEventReader;
  92. ///<summary>
  93. ///
  94. ///</summary>
  95. private void Start()
  96. {
  97. MapSensor = new MapSensor();
  98. if (!ConfigParser.ParseConfig())
  99. CityLogger.LogWarning("Unable to parse config");
  100. IsRunning = true;
  101. this.UpdateRateInSeconds = 1 / this.UpdateRate;
  102. this.GameVelocity = 1f;
  103. StepSizeGameVelocity = 0.1f;
  104. NumberDigitsGameVelocity = 1;
  105. NumberDigitsTimeStamps = 2;
  106. forward = true;
  107. NewestTimestamp = 0;
  108. EarliestTimestamp = 0;
  109. GameTimestamp = starttime;
  110. ProzessorSetup();
  111. }
  112. ///<summary>
  113. /// Setup the InputProzessor.
  114. /// Starts InputProzessor and NetworkEventReader with ipAddress and port: 13000,13001
  115. ///
  116. ///</summary>
  117. void ProzessorSetup()
  118. {
  119. //Create InputProzessor and start streaming/reading.
  120. if (UseStream)
  121. {
  122. InputProzessor = new Processor.Processor(ipAddress, 13000);
  123. NWEventReader = new NWEventReader(ipAddress, 13001);
  124. InputProzessor.StartStreaming();
  125. this.EventFilename = NWEventReader.StartNWRead();
  126. }
  127. else
  128. {
  129. if (!EntityFilename.Equals(string.Empty))
  130. InputProzessor = new Processor.Processor(EntityFilename);
  131. InputProzessor.StartStreaming();
  132. }
  133. Stopwatch watch = new Stopwatch();
  134. double starttime = double.NaN;
  135. //Try to start stream
  136. watch.Start();
  137. while (double.IsNaN(starttime))
  138. {
  139. starttime = InputProzessor.GetOldestTimeStamp();
  140. Thread.Sleep(10);
  141. if (watch.ElapsedMilliseconds > 5000)
  142. {
  143. CityLogger.LogError("Starting stream on " + ipAddress + ":" + 13000 + " has timed out.");
  144. InputProzessor.StopStreaming();
  145. CriticalError();
  146. }
  147. }
  148. watch.Stop();
  149. EarliestTimestamp = starttime;
  150. if (InputProzessor.JumpToTimestamp(starttime, out _))
  151. {
  152. CityLogger.Log("Stream started", LogLevel.INFO);
  153. StartCoroutine(ReadData());
  154. }
  155. else
  156. {
  157. CityLogger.LogWarning("Unable to do initial jump on timestamp: " + starttime);
  158. InputProzessor.StopStreaming();
  159. CriticalError();
  160. }
  161. }
  162. ///<summary>
  163. /// Coroutine to read from InputProzessor every (1/updateRate)*Velocity seconds.
  164. ///</summary>
  165. IEnumerator ReadData()
  166. {
  167. float gv;
  168. //Get Event CSV Reader for reading Events
  169. EventCSV = new EventCSVReader(EventFilename);
  170. CityLogger.Log("EventFileName " + EventFilename, 0);
  171. MapSensor.SetSensorList(SensorHandler.SensorList);
  172. CityLogger.Log("Start ReadingData", LogLevel.INFO);
  173. endChunk = InputProzessor.GetChunkEndtimestamp();
  174. startChunk = InputProzessor.GetChunkStarttimestamp();
  175. //Start EventHandler
  176. EventHandler.SetUp(EventCSV, MapSensor);
  177. //Start Coroutine which runs every 1/UpdateRate seconds
  178. StartCoroutine(UpdateWithProzessorUpdateRate());
  179. Stopwatch watch = new Stopwatch();
  180. //Start Reading InputObjects
  181. while (this.IsRunning)
  182. {
  183. //Only read data if simulation is running
  184. if (this.GameVelocity > 0)
  185. {
  186. gv = this.GameVelocity;
  187. watch.Restart();
  188. HandleNextInput();
  189. watch.Stop();
  190. float updateTime = this.UpdateRateInSeconds / gv;
  191. float waittime = updateTime - (watch.ElapsedMilliseconds / 1000.0f);
  192. if (waittime < 0)
  193. {
  194. CityLogger.LogWarning("Unable to stick to update timing. Program is behind by: " + waittime * (-1));
  195. waittime = 0;
  196. }
  197. yield return new WaitForSecondsRealtime(waittime);
  198. }
  199. else
  200. {
  201. yield return null;
  202. }
  203. }
  204. }
  205. ///<summary>
  206. /// Reads values from the next timestamp
  207. ///</summary>
  208. void HandleNextInput()
  209. {
  210. List<InputObject> inputBuffer;
  211. inputBuffer = InputProzessor.ReadNextValues();
  212. if (inputBuffer.Count > 0)
  213. {
  214. //GameTimestamp is the newest read Timestamp
  215. this.NewestGameInputObject = inputBuffer[inputBuffer.Count - 1];
  216. this.GameTimestamp = this.NewestGameInputObject.Time;
  217. Handler.SensorList = SensorHandler.SensorList;
  218. if (double.IsNaN(startChunk))
  219. {
  220. startChunk = EarliestTimestamp;
  221. }
  222. if (!double.IsNaN(endChunk) && this.GameTimestamp >= endChunk)
  223. {
  224. //if next timestamp is greater then endchunk or is the last value in the Intervall [startChunk,endChunk]
  225. //stop the Simulation and jump to the end of the Intervall
  226. StopPressed();
  227. this.JumpToTimestamp(endChunk);
  228. }
  229. else if (this.GameTimestamp >= NewestTimestamp)
  230. {
  231. //if the simulation reads faster than it gets updates
  232. //set the GameVelocity to 1 and handle the input
  233. this.GameVelocity = 1;
  234. this.Handler.Handle(inputBuffer);
  235. }
  236. else if (!forward && this.GameTimestamp <= startChunk)
  237. {
  238. //if the simulation runs backwards and the next timestamp is smaller or the first value in the intervall [startChunk,endChunk]
  239. //stop the Simulation and jump to the start of the intervall
  240. StopPressed();
  241. this.JumpToTimestamp(startChunk);
  242. }
  243. else
  244. {
  245. //if next timestamp is in the invall handle the input
  246. Handler.Handle(inputBuffer);
  247. }
  248. }
  249. }
  250. ///<summary>
  251. /// Sets the starttime of the timeintervall the Simulation is running in.
  252. ///<remarks>
  253. /// Also sets the starttime in the Inputprozessor
  254. ///</remarks>
  255. ///</summary>
  256. public override void SetChunkStarttimestamp(double time)
  257. {
  258. InputProzessor.SetChunkStarttimestamp(time);
  259. double newTime = InputProzessor.GetChunkStarttimestamp();
  260. startChunk = newTime;
  261. }
  262. ///<summary>
  263. /// Sets the endtime of the timeintervall the Simulation is running in.
  264. ///<remarks>
  265. /// Also sets the endtime in the Inputprozessor
  266. ///</remarks>
  267. ///</summary>
  268. public override void SetChunkEndtimestamp(double time)
  269. {
  270. InputProzessor.SetChunkEndtimestamp(time);
  271. double newTime = InputProzessor.GetChunkEndtimestamp();
  272. endChunk = newTime;
  273. }
  274. ///<summary>
  275. /// coroutine which runs every 1/UpdateRate seconds
  276. ///</summary>
  277. IEnumerator UpdateWithProzessorUpdateRate()
  278. {
  279. while (this.IsRunning)
  280. {
  281. this.NewestTimestamp = this.InputProzessor.GetNewestTimeStamp();
  282. yield return new WaitForSecondsRealtime(this.UpdateRateInSeconds);
  283. }
  284. }
  285. ///<summary>
  286. /// Jump to timestamp.Start JumpToTimestampRoutine
  287. ///</summary>
  288. public override void JumpToTimestamp(double timestamp)
  289. {
  290. if (!double.IsNaN(timestamp))
  291. {
  292. if (this.InputProzessor != null)
  293. {
  294. StartCoroutine(JumpToTimestampRoutine(timestamp));
  295. }
  296. }
  297. }
  298. ///<summary>
  299. /// Start to timestamp by calling InputProzessor.JumpToTimestamp
  300. ///</summary>
  301. private IEnumerator JumpToTimestampRoutine(double timestamp)
  302. {
  303. if (this.InputProzessor.JumpToTimestamp(timestamp, out double x))
  304. {
  305. //Clear the scene
  306. //Destroying an objects needs 1 frame
  307. this.Handler.ClearAll();
  308. yield return null;
  309. //InputProzessor needs some time to jump to the timestamp
  310. yield return new WaitForSecondsRealtime(0.25f);
  311. if (x != -1)
  312. this.GameTimestamp = x;
  313. //Handle the next Input.
  314. HandleNextInput();
  315. CityLogger.Log(string.Format("Timestamp returned from Prozessor {0}, timestamp Parameter {1}, InputBufferTimestamp{2}", x, timestamp, this.NewestGameInputObject.Time), LogLevel.DEBUG);
  316. }
  317. else CityLogger.Log("Couldn't Jump " + timestamp, LogLevel.INFO);
  318. yield return null;
  319. }
  320. ///<summary>
  321. /// Reverse Simulation
  322. ///</summary>
  323. public void ReverseTime()
  324. {
  325. this.forward = !this.forward;
  326. this.InputProzessor.ReverseTime();
  327. }
  328. private void OnDestroy()
  329. {
  330. //if the GameObject gets destroyed
  331. //stop streaming
  332. if (InputProzessor != null)
  333. {
  334. InputProzessor.StopStreaming();
  335. }
  336. if (NWEventReader != null)
  337. {
  338. NWEventReader.StopReading();
  339. }
  340. IsRunning = false;
  341. }
  342. private void CriticalError()
  343. {
  344. CityLogger.LogError("Encountered critical error. Shutting down application...");
  345. #if UNITY_EDITOR
  346. UnityEditor.EditorApplication.isPlaying = false;
  347. UnityEditor.EditorApplication.Exit(0);
  348. #else
  349. Application.Quit();
  350. #endif
  351. Environment.Exit(0);
  352. }
  353. ///<summary>
  354. /// Set Velocity to the last Velocity known before stop was pressed
  355. ///</summary>
  356. public override void PlayPressed()
  357. {
  358. if (this.GameVelocity == 0)
  359. {
  360. //if the GameVelocity is 0
  361. //change the GameVelocity to the savedGameVelocity
  362. //if the GameVeloctiy was changed to 0 by using the plus and minus button
  363. //the saved GameVelocity will be the velocity from the last StopPressed()
  364. this.GameVelocity = this.StopedGameVeloctiy;
  365. CityLogger.Log("PlayPressed" + this.GameVelocity.ToString(), LogLevel.DEBUG);
  366. }
  367. }
  368. ///<summary>
  369. /// Save Veloctiy and set velocity to 0.
  370. ///</summary>
  371. public override void StopPressed()
  372. {
  373. if (this.GameVelocity > 0)
  374. {
  375. // if the GameVelocity is greater 0
  376. // save the current GameVelocity and change the GameVelocity to 0
  377. this.StopedGameVeloctiy = this.GameVelocity;
  378. this.GameVelocity = 0;
  379. CityLogger.Log("StopPressed" + this.StopedGameVeloctiy.ToString(), LogLevel.DEBUG);
  380. }
  381. }
  382. ///<summary>
  383. /// Reverse Simulation
  384. ///</summary>
  385. public override void ReversePressed()
  386. {
  387. this.ReverseTime();
  388. CityLogger.Log("ReversePressed", LogLevel.DEBUG);
  389. }
  390. ///<summary>
  391. /// Increase velocity by StepSizeGameVelocity
  392. ///</summary>
  393. public override void PlusPressed()
  394. {
  395. //Increase GameVelocity
  396. //no limit
  397. this.GameVelocity = this.RoundWithDigits(this.GameVelocity + this.StepSizeGameVelocity, this.NumberDigitsGameVelocity);
  398. CityLogger.Log("PlusPressed" + this.GameVelocity.ToString(), LogLevel.DEBUG);
  399. }
  400. ///<summary>
  401. /// Decrease velocity by StepSizeGameVelocity.
  402. ///</summary>
  403. public override void MinusPressed()
  404. {
  405. //Decrease GameVelocity
  406. // always greater 0
  407. this.GameVelocity = this.RoundWithDigits(this.GameVelocity - this.StepSizeGameVelocity, this.NumberDigitsGameVelocity);
  408. if (this.GameVelocity < 0)
  409. {
  410. this.GameVelocity = 0;
  411. }
  412. CityLogger.Log("MinusPressed" + this.GameVelocity.ToString(), LogLevel.DEBUG);
  413. }
  414. ///<summary>
  415. /// Rounds number
  416. ///</summary>
  417. private float RoundWithDigits(float value, int NumberDigits)
  418. {
  419. //try to prevent round errors
  420. //for example 0.1 - 0.1 returned a extrem small number and
  421. //yield return new WaitForSecondsRealtime(1 / (this.UpdateRate * this.GameVelocity));
  422. // would be a very long time.
  423. return Mathf.Round(value * Mathf.Pow(10, NumberDigits)) / (Mathf.Pow(10, NumberDigits));
  424. }
  425. ///<summary>
  426. /// Rounds number
  427. ///</summary>
  428. private double RoundWithDigits(double value, int NumberDigits)
  429. {
  430. return (double)Mathf.Round((float)value * Mathf.Pow(10, NumberDigits)) / (Mathf.Pow(10, NumberDigits));
  431. }
  432. }
  433. }