using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading.Tasks; using CSVReader; using Logger; using System.Collections.Concurrent; using System.Linq; namespace ObjectScripts { public class ObjectHandler : AbstractObjectHandler { /// /// Dictionary to keep track of every DataObject. /// (ObjectID,DataObject) /// public Dictionary DataObjectDictionary; /// /// Dictionary for Objects that need to be created. /// private Dictionary ObjectsToCreate; /// /// HashSet filled with Objects that need to be deleted /// private HashSet ObjectsToDelete; /// /// how Long an object can live without an update. /// public float TTL = 10f; /// /// Dictionary to keep track of every Sensor. /// (SensorID,SensorGameobject) /// public Dictionary SensorList { get; set; } void Start() { Forward = true; ObjectDictionary = new Dictionary(); ObjectsToCreate = new Dictionary(); ObjectsToDelete = new HashSet(); DataObjectDictionary = new Dictionary(); this.UpdateRate = this.ManagerObject.UpdateRateInSeconds / this.ManagerObject.GameVelocity; } /// /// Create new GameObject corresponding to given InputObject /// private GameObject Create(InputObject input) { //Create GameObject and DataObject var id = input.ID; //new DataObject DataObject data; //new GameObject GameObject obj; switch (input.Type) { case EntityType.BIKE: obj = Instantiate(prefabBike); break; case EntityType.TRUCK: obj = Instantiate(prefabTruck); break; case EntityType.CAR: obj = Instantiate(prefabCar); break; case EntityType.PERSON: obj = Instantiate(prefabHuman); break; default: obj = Instantiate(prefabHuman); CityLogger.LogError(string.Format("Could not Add Object {0} invalid Entity Type \n", id)); break; } //change name to the id obj.name = id.ToString(); // add GameObject to ObjectDictionary try { ObjectDictionary.Add(id, obj); } catch (System.ArgumentException e) { CityLogger.LogError(string.Format("Could not Add Object {0} to ObjectDictionary\n{1}", id, e)); } // get the DataObject data = obj.GetComponent(); data.SetUp(id, this, input.Type, TTL, ManagerObject.GameVelocity); //Add DataObject to Dicitonary DataObjectDictionary.Add(id, data); //set the position in the simulation to the first given postion data.TargetPos = input.Pos; data.StartPos = input.Pos; //try to get the given sensor GameObject sensor; try { sensor = SensorList[input.SensorID]; } catch (KeyNotFoundException ex) { CityLogger.LogError(ex.Message + "Sensor ID : " + input.SensorID.ToString()); //if sensor was not found set default sensor sensor = SensorList[0]; } //map input data to DataObject data.MapInputObjekt(input, sensor); return obj; } /// /// Add Object to ObjectToDelete list /// public override void DeleteObject(DataObject data) { ObjectsToDelete.Add(data); } /// /// Delete Object with same id as the given DataObject /// Removes GameObject from ObjectDictionary /// Removes DataObject from DataObjectDictionary /// Destroys GameObject /// private void DestroyObject(DataObject data) { var id = data.ID; GameObject removeObj; //check if object to remove is in ObjectDictionary if (ObjectDictionary.TryGetValue(id, out removeObj)) { //try to remove GameObject out of ObjectDicitonary if (!ObjectDictionary.Remove(id)) { //Implement ErrorHandling //didn't occured till now CityLogger.LogError(string.Format("Object could not be removed out of ObjectDictionary ObjectId: {0}", id)); } //try to remove DataObject out of DataObjectDictionary if (!DataObjectDictionary.Remove(id)) { //Implement ErrorHandling //didn't occured till now CityLogger.LogError(string.Format("Object could not be removed out of DataObjectDictionary ObjectId: {0}", id)); } // try to Destroy GameObject try { Destroy(removeObj); } catch (System.Exception) { //Implement ErrorHandling //didn't occured till now throw; } } else { //Implement ErrorHandling //didn't occured till now CityLogger.LogError(string.Format("Object to remove was not found ObjectId: {0} ", id)); } } private void Update() { //Update the update Rate this.GameVelocity = this.ManagerObject.GameVelocity; this.Forward = this.ManagerObject.forward; if (this.GameVelocity > 0) { this.UpdateRate = this.ManagerObject.UpdateRateInSeconds / this.GameVelocity; } else { this.UpdateRate = 0; } //Using ObjectsToDelete and ObjectsToCreate because Unity does not allow to call MonoBehaviour methods in parallel. // so if a parallel foreach is used to handle the input objects, then there is no way to call Create() or DestroyObject(). //Delete/Destroy each Object in ObjectsToDelete foreach (var objectToDelete in ObjectsToDelete) { DestroyObject(objectToDelete); } //After deleteing clear List ObjectsToDelete.Clear(); //Create each Object in ObjectsToCreate foreach (int id in ObjectsToCreate.Keys) { if (ObjectsToCreate.TryGetValue(id, out InputObject input)) { Create(input); } else { CityLogger.LogError(string.Format("Could not create InputObjekt {0}", id)); } } //After creating all Objects clear ObjectsToCreate.Clear(); } /// /// Clear scene by destroying every GameObject /// public override void ClearAll() { this.ObjectsToDelete.UnionWith(this.DataObjectDictionary.Values); this.ObjectsToCreate.Clear(); } /// /// Handle the InputBuffer /// public override void Handle(List InputBuffer) { // if InputBuffer not empty if (InputBuffer != null && InputBuffer.Count > 0) { //take the current DataObjectDictionary Dictionary dataDict; dataDict = DataObjectDictionary; //here a parallel foreach is possible but is way faster with a serial foreach foreach (InputObject input in InputBuffer) { // Debug.Log(b); //If Object with ID exist map the new data to the object if (dataDict.TryGetValue(input.ID, out DataObject data)) { bool valid = SensorList.TryGetValue(input.SensorID, out GameObject sensor); if (!valid) { CityLogger.LogError(string.Format("Unable to find ID {0} in SensorList", input.SensorID)); continue; } data.MapInputObjekt(input, sensor); // MapInputToDataObject(data, input); } else { //if there is no object with the ID. Create an Object. int id = input.ID; if (!ObjectsToCreate.ContainsKey(id)) { ObjectsToCreate.Add(id, input); } else { //updates faster than creating. CityLogger.LogError(string.Format("Update faster then creating id: {0} (two updates for one object)", id)); } // } } // Debug.Log(b); }; } } } }