Hello,
I’m currently trying to make a virtual greenhouse using hybrid ECS.
I have a PlantColumn IComponentData which contains an int, NativeString512 and a DynamicBuffer.
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
[System.Serializable]
public struct PlantColumn : IComponentData
{
public int id;
public NativeString512 plantName;
public DynamicBuffer<Property> properties;
}
Property is another IComponentData which contains a NativeString512, int, float and a bool.
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;
public struct Property : IComponentData
{
public NativeString512 header;
public int intValue;
public float floatValue;
public bool boolValue;
public NativeString512 stringValue;
public void AssignValue(string _header, System.Object value)
{
if (value.GetType() == typeof(int))
{
intValue = int.Parse(value.ToString());
header = new NativeString512(value.ToString());
}
else if (value.GetType() == typeof(float))
{
floatValue = float.Parse(value.ToString());
header = new NativeString512(value.ToString());
}
else if (value.GetType() == typeof(string))
{
stringValue = new NativeString512(value.ToString());
header = new NativeString512(value.ToString());
}
else if (value.GetType() == typeof(bool))
{
bool.Parse(value.ToString());
header = new NativeString512(value.ToString());
}
else
Debug.LogError("Value type not valid or couldn't be parsed to a valid type. Valid value types are: int, float, string, bool");
}
}
This is the temporary test script I use to create the entities and create a placeholder dataset with only a ‘height’ property.
using UnityEngine;
using Unity.Entities;
using Unity.Collections;
using UnityEngine.UIElements;
using Unity.Transforms;
using Unity.Rendering;
using Unity.Mathematics;
using System.Collections.Generic;
public class GreenhouseBootstrap : MonoBehaviour
{
[SerializeField] private Mesh mesh;
[SerializeField] private Material mat;
[SerializeField] private GameObject prefab;
List<Plant> testPlantDataset;
void Start()
{
testPlantDataset = new List<Plant>();
for (int i = 0; i < 20; i++)
{
Plant plant = new Plant();
plant.properties = new Dictionary<string, object>();
plant.plantName = "Plant00" + i;
plant.properties.Add("height", i * UnityEngine.Random.Range(20f, 40f));
testPlantDataset.Add(plant);
}
InstantiateFilteredDataset(20);
}
public void InstantiateFilteredDataset(int amount)
{
//Get the EntityManager
EntityManager manager = World.Active.EntityManager;
//Instantiate the PlantColumns prefab and convert them to entities
for (int i = 0; i < amount; i++)
{
GameObject obj = Instantiate(prefab, new Vector3(i + (i * 0.5f), 0, 0), Quaternion.identity);
obj.AddComponent<ConvertToEntity>().ConversionMode = ConvertToEntity.Mode.ConvertAndDestroy;
}
//Construct an EntityQueryDescription that includes all entities that DON'T have a LocalToParent component on them
EntityQueryDesc query = new EntityQueryDesc
{
None = new ComponentType[] {typeof(LocalToParent)}
};
//Create the EntityQuery using the EntityManager
EntityQuery entityQuery = manager.CreateEntityQuery(query);
//Convert the EntityQuery to a NativeArray<Entity> so we can loop through all the found entities
NativeArray<Entity> entityArray = entityQuery.ToEntityArray(Allocator.TempJob);
//Loop through all the found entities and add a PlantColum component on them
for (int i = 0; i < entityArray.Length; i++)
{
manager.AddComponentData(entityArray[i], new PlantColumn { id = entityArray[i].Index });
DynamicBuffer<Property> tempPropertyBuffer = manager.GetComponentData<PlantColumn>(entityArray[i]).properties;
foreach (KeyValuePair<string, System.Object> kvp in testPlantDataset[i].properties)
{
Property prop = new Property();
string propertyName = kvp.Key;
System.Object propertyValue = kvp.Value;
prop.AssignValue(propertyName, propertyValue);
tempPropertyBuffer.Add(prop);
}
}
//Dispose the NativeArray<Entity> to prevent memory leaks
entityArray.Dispose();
}
The error occurs at line 76
The reason I’m using an object is because a property can be more than just one data type.
The problem is that whenever I create my plant entities and add a PlantColumn ComponentData on them and then try to add a Property using entity.properties.Add(new Property()) I get a NullReferenceException.
The error points to the DynamicBuffer class. Something with AtomicSafetyHandle.CheckWriteAndThrow().
I was wondering if a structure like this is even possible.
Thanks in advance!