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);
};
}
}
}
}