Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How To Changing Value Inside Class

Discussion in 'Entity Component System' started by tahsinXYZ, Sep 19, 2021.

  1. tahsinXYZ

    tahsinXYZ

    Joined:
    Aug 14, 2019
    Posts:
    70
    Hello people I have Farmable Resource Node class and it has a nested struct called data and FarmGrowJob that inherits from IJob.Like this :
    Code (CSharp):
    1. public struct Data
    2.     {
    3.         internal float currentGrowthRate;
    4.         public float oldRate;
    5.         public float growthRateAfterHarverst;
    6.         public float growthSpeed;
    7.     }
    8.  
    9.     public Data data;
    Code (CSharp):
    1. public struct FarmGrowJob : IJob
    2.     {
    3.         public static float deltaTime;
    4.         public FarmableResourceNode.Data data;
    5.  
    6.         public void Execute()
    7.         {
    8.             data.currentGrowthRate += data.growthSpeed * deltaTime;
    9.         }
    10.     }
    And I have a Plant grow system like this :
    Code (CSharp):
    1. public class PlantGrowingSystem : MonoBehaviour
    2. {
    3.     public static PlantGrowingSystem system;
    4.     public List<FarmableResourceNode> farmableResourceNodes = new List<FarmableResourceNode>();
    5.  
    6.     private void Awake()
    7.     {
    8.         system = this;
    9.     }
    10.     private void Update()
    11.     {
    12.         FarmableResourceNode.FarmGrowJob.deltaTime = Time.deltaTime;
    13.         NativeList<JobHandle> jobHandles = new NativeList<JobHandle>(Allocator.Temp);
    14.         for(int i = 0; i < farmableResourceNodes.Count; i++)
    15.         {
    16.             FarmableResourceNode.FarmGrowJob farmGrowJob = new FarmableResourceNode.FarmGrowJob();
    17.             farmGrowJob.data = farmableResourceNodes[i].data;
    18.             jobHandles.Add(farmGrowJob.Schedule());
    19.         }
    20.         JobHandle.CompleteAll(jobHandles);
    21.         jobHandles.Dispose();
    22.     }
    23. }
    But problem is inside data there no change. How can I solve this ? Thanks in advance!
     
  2. apkdev

    apkdev

    Joined:
    Dec 12, 2015
    Posts:
    277
    Code (CSharp):
    1. public struct FarmGrowJob : IJob
    2. {
    3.     public static float deltaTime;
    4.     public FarmableResourceNode.Data data;
    5.  
    6.     public void Execute()
    7.     {
    8.         data.currentGrowthRate += data.growthSpeed * deltaTime;
    9.     }
    10. }
    I see you're passing in a struct (
    FarmableResourceNode.Data data;
    ) to your job. Structs are value types, which means they're copied when they're passed around (as opposed to classes/reference types, which always refer to the same object unless you explicitly create a clone). This includes jobs - the entire job struct is copied to the job system when you schedule it. However, it isn't copied back when the job has finished executing.

    The only way to pass results from a job back to your code is using native containers. This means that even if your job returns a single
    float
    value, you still need to wrap it in a native container, so that the data is actually stored separately in memory. Annoying, I know, but these are the rules.

    A few versions ago you'd need to create an array with a single element, but that was even more annoying, so Unity added
    NativeReference<T>
    which can be used to allocate memory for a single struct. You can find it in the com.unity.collections package.

    It works like this:

    Code (CSharp):
    1. public struct FarmGrowJob : IJob
    2. {
    3.     public static float deltaTime;
    4.     public NativeReference<FarmableResourceNode.Data> data;
    5.  
    6.     public void Execute()
    7.     {
    8.         data.Value.currentGrowthRate += data.Value.growthSpeed * deltaTime;
    9.     }
    10. }

    By the way, I recommend you check out IJobFor/IJobParallelFor - it will allow you to schedule a single job to process all of your data. This is much more efficient because scheduling small jobs is pretty expensive.
     
    tahsinXYZ likes this.
  3. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Data is a struct, so you're copying it from farmableResourceNodes.data to FarmGrowJob.data but you're not copying it back after the jobs are complete. The result is just getting discarded once the job ends.

    Also it seems like you're creating a job for every instance of Data as opposed to iterating a list of Data in a job.
    I think what you might want to do is copy all the farmableResourceNodes.Data into a NativeArray and pass that NativeArray into the job for computation. Then after the job is finished, you copy the results back to the farmableResourceNodes.

    However for the minimal computation being done, the cost of the job and copying the data back and forth may well take longer than just computing it directly within your current for loop.

    Edit: Ah apk beat me. :)
    I'd just add that using a NativeReference, you'd still need to store all of those somewhere in order to write them back to farmableResourceNodes. If you're going to copy the data, a single array would be more efficient and then also look at IJobParallelFor as apk said if you're processing significant numbers of Data's.
     
    Last edited: Sep 19, 2021
    tahsinXYZ and apkdev like this.
  4. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    447
    You should not start a job for a single struct. You should have a native array of this structures an start one IJobParralelFor instead. Scheduling a job has an overhead so it will take longer to schedule it then do your actual work.
     
    tahsinXYZ likes this.
  5. tahsinXYZ

    tahsinXYZ

    Joined:
    Aug 14, 2019
    Posts:
    70
    I tried IJobParralelFor but it does not letm change value of element of NativeArray.
     
  6. tahsinXYZ

    tahsinXYZ

    Joined:
    Aug 14, 2019
    Posts:
    70
    Can not change value of data.Value because C# does not let me. It gives "cs1612" error.
     
    Last edited: Sep 19, 2021
  7. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    447
    Do not use classes for your data. Jobs do not work with reference types.
     
    tahsinXYZ likes this.
  8. tahsinXYZ

    tahsinXYZ

    Joined:
    Aug 14, 2019
    Posts:
    70
    I am not using. I am using nested struct.
     
  9. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    447
    You wrote
    So I have assumed it is a class, you did not show full source code of Farmable Resource Node.
     
    tahsinXYZ likes this.
  10. tahsinXYZ

    tahsinXYZ

    Joined:
    Aug 14, 2019
    Posts:
    70
    BTW i have solved my problem thanks anyway.