Search Unity

Resolved Setting the value of a Particle System Module property using reflection

Discussion in 'Scripting' started by MysticalMonkeys, Feb 16, 2023.

  1. MysticalMonkeys

    MysticalMonkeys

    Joined:
    Dec 5, 2022
    Posts:
    6
    I'm working on an existing node based visual scripting tool in Unity 2018.4, in particular a Float Out node that sets the value of a float property (set in the inspector).

    This is the original code:
    Code (CSharp):
    1. //
    2. // Klak - Utilities for creative coding with Unity
    3. //
    4. // Copyright (C) 2016 Keijiro Takahashi
    5. //
    6. // Permission is hereby granted, free of charge, to any person obtaining a copy
    7. // of this software and associated documentation files (the "Software"), to deal
    8. // in the Software without restriction, including without limitation the rights
    9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    10. // copies of the Software, and to permit persons to whom the Software is
    11. // furnished to do so, subject to the following conditions:
    12. //
    13. // The above copyright notice and this permission notice shall be included in
    14. // all copies or substantial portions of the Software.
    15. //
    16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    22. // THE SOFTWARE.
    23. //
    24. using UnityEngine;
    25. using System.Reflection;
    26.  
    27. namespace Klak.Wiring
    28. {
    29.     [AddComponentMenu("Klak/Wiring/Output/Generic/Float Out")]
    30.     public class FloatOut : NodeBase
    31.     {
    32.         #region Editable properties
    33.  
    34.         [SerializeField]
    35.         Component _target;
    36.  
    37.         [SerializeField]
    38.         string _propertyName;
    39.  
    40.         #endregion
    41.  
    42.         #region Node I/O
    43.  
    44.         [Inlet]
    45.         public float input {
    46.             set {
    47.                 if (!enabled || _target == null || _propertyInfo == null) return;
    48.                 _propertyInfo.SetValue(_target, value, null);
    49.             }
    50.         }
    51.  
    52.         #endregion
    53.  
    54.         #region Private members
    55.  
    56.         PropertyInfo _propertyInfo;
    57.  
    58.         void OnEnable()
    59.         {
    60.             if (_target == null || string.IsNullOrEmpty(_propertyName)) return;
    61.             _propertyInfo = _target.GetType().GetProperty(_propertyName);
    62.         }
    63.  
    64.         #endregion
    65.     }
    66. }
    67.  
    I'm trying to add the ability to set float properties of particle system modules. So far I've been able to update the editor so that when the target is a particle system I can select the desired module and one of its float properties in the inspector:


    As for setting the value of the module's property in the Input property's set method I'm drawing a blank.
    I tried the following:
    Code (CSharp):
    1. //
    2. //
    3. // Klak - Utilities for creative coding with Unity
    4. //
    5. // Copyright (C) 2016 Keijiro Takahashi
    6. //
    7. // Permission is hereby granted, free of charge, to any person obtaining a copy
    8. // of this software and associated documentation files (the "Software"), to deal
    9. // in the Software without restriction, including without limitation the rights
    10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11. // copies of the Software, and to permit persons to whom the Software is
    12. // furnished to do so, subject to the following conditions:
    13. //
    14. // The above copyright notice and this permission notice shall be included in
    15. // all copies or substantial portions of the Software.
    16. //
    17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23. // THE SOFTWARE.
    24. //
    25. using UnityEngine;
    26. using System.Reflection;
    27.  
    28. namespace Klak.Wiring
    29. {
    30.     [AddComponentMenu("Klak/Wiring/Output/Generic/Float Out")]
    31.     public class FloatOut : NodeBase
    32.     {
    33.         #region Editable properties
    34.  
    35.         [SerializeField]
    36.         Component _target;
    37.  
    38.         [SerializeField]
    39.         string _propertyName;
    40.  
    41.         [SerializeField]
    42.         string _particleSystemModuleName;
    43.  
    44.         #endregion
    45.  
    46.         #region Node I/O
    47.  
    48.         [Inlet]
    49.         public float input {
    50.             set {
    51.                 if (!enabled || _target == null || _propertyInfo == null) return;
    52.  
    53.                 if (_target.GetType() == typeof(ParticleSystem))
    54.                 {
    55.                     _propertyInfo.SetValue(_target.GetType().GetProperty(_moduleInfo.Name), value, null);
    56.                 }
    57.                  
    58.                 else _propertyInfo.SetValue(_target, value, null);
    59.             }
    60.         }
    61.  
    62.         #endregion
    63.  
    64.         #region Private members
    65.  
    66.         PropertyInfo _propertyInfo;
    67.         PropertyInfo _moduleInfo;
    68.  
    69.         void OnEnable()
    70.         {
    71.             if (_target == null || string.IsNullOrEmpty(_propertyNdame)) return;
    72.  
    73.             else
    74.             {
    75.                 if (_target.GetType() == typeof(ParticleSystem))
    76.                 {
    77.                     _moduleInfo = _target.GetType().GetProperty(_particleSystemModuleName);
    78.                     _propertyInfo = _moduleInfo.PropertyType.GetProperty(_propertyName);
    79.                 }
    80.  
    81.                 else
    82.                 {
    83.                     _propertyInfo = _target.GetType().GetProperty(_propertyName);
    84.                 }
    85.             }
    86.         }
    87.  
    88.         #endregion
    89.     }
    90. }
    91.  
    Line 55 obviously doesn't work as I'm trying to set the value of the PropertyInfo of the module, instead of the target's actual module, but I don't know how to access the actual module object.
    (and if I manage to access the module I'll have to cache it in a local variable first before I can set the value, right?)

    Any help is appreciated.
     
  2. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,065
    The modules in the particle system are structs, so you'll just modify a copy and won't update the particle system if you try to access it directly. Instead, you need to do it in three steps:
    • Get the module object from the particle system (
      moduleObj = _moduleInfo.GetValue(_target)
      )
    • Set the float value on the module object (
      _propertyInfo.SetValue(moduleObj, value)
      )
    • Set the changed module object back on the particle system (
      _moduleInfo.SetValue(_target, moduleObj)
      )
    In your code on line 55, you try to set the float value on the
    PropertyInfo
    type object instead of on the actual module object itself. You first need to get the module object using reflection using the property info object.
     
  3. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    Technically, yes. This is true.

    ParticleSystem-Modules in Unity are weird though.
    That 'struct' isn't really a normal struct. It acts as an interface for an underlying Native object.
    Thus, setting a new struct probably won't work, since it doesn't modify the underlying c++-object.

    OP will probably need to use the Properties on the Module directly, instead of trying to use reflection to set the underlying values.
    These properties all call
    set_PROP_Injected
    -methods to modify the C++-object.
     
  4. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    To illustrate; here's the code for the MainModule-struct:
    Code (CSharp):
    1. public struct MainModule
    2. {
    3.     internal ParticleSystem m_ParticleSystem;
    4.     //
    5.     // Summary:
    6.     //     Cause some particles to spin in the opposite direction.
    7.     [Obsolete("Please use flipRotation instead. (UnityUpgradable) -> UnityEngine.ParticleSystem/MainModule.flipRotation", false)]
    8.     public float randomizeRotationDirection
    9.     {
    10.         get
    11.         {
    12.             return flipRotation;
    13.         }
    14.         set
    15.         {
    16.             flipRotation = value;
    17.         }
    18.     }
    19.     //
    20.     // Summary:
    21.     //     The current Particle System velocity.
    22.     public Vector3 emitterVelocity
    23.     {
    24.         get
    25.         {
    26.             get_emitterVelocity_Injected(ref this, out var ret);
    27.             return ret;
    28.         }
    29.         [NativeThrows]
    30.         set
    31.         {
    32.             set_emitterVelocity_Injected(ref this, ref value);
    33.         }
    34.     }
    35.     //
    36.     // Summary:
    37.     //     The duration of the Particle System in seconds.
    38.     public float duration
    39.     {
    40.         get
    41.         {
    42.             return get_duration_Injected(ref this);
    43.         }
    44.         [NativeThrows]
    45.         set
    46.         {
    47.             set_duration_Injected(ref this, value);
    48.         }
    49.     }
    50.     //
    51.     // Summary:
    52.     //     Specifies whether the Particle System is looping.
    53.     public bool loop
    54.     {
    55.         get
    56.         {
    57.             return get_loop_Injected(ref this);
    58.         }
    59.         [NativeThrows]
    60.         set
    61.         {
    62.             set_loop_Injected(ref this, value);
    63.         }
    64.     }
    65.     //
    66.     // Summary:
    67.     //     If ParticleSystem.MainModule._loop is true, when you enable this property, the
    68.     //     Particle System looks like it has already simulated for one loop when first becoming
    69.     //     visible.
    70.     public bool prewarm
    71.     {
    72.         get
    73.         {
    74.             return get_prewarm_Injected(ref this);
    75.         }
    76.         [NativeThrows]
    77.         set
    78.         {
    79.             set_prewarm_Injected(ref this, value);
    80.         }
    81.     }
    82.     //
    83.     // Summary:
    84.     //     Start delay in seconds.
    85.     public MinMaxCurve startDelay
    86.     {
    87.         get
    88.         {
    89.             get_startDelay_Injected(ref this, out var ret);
    90.             return ret;
    91.         }
    92.         [NativeThrows]
    93.         set
    94.         {
    95.             set_startDelay_Injected(ref this, ref value);
    96.         }
    97.     }
    98.     //
    99.     // Summary:
    100.     //     A multiplier for ParticleSystem.MainModule._startDelay in seconds.
    101.     public float startDelayMultiplier
    102.     {
    103.         get
    104.         {
    105.             return get_startDelayMultiplier_Injected(ref this);
    106.         }
    107.         [NativeThrows]
    108.         set
    109.         {
    110.             set_startDelayMultiplier_Injected(ref this, value);
    111.         }
    112.     }
    113.     //
    114.     // Summary:
    115.     //     The total lifetime in seconds that each new particle has.
    116.     public MinMaxCurve startLifetime
    117.     {
    118.         get
    119.         {
    120.             get_startLifetime_Injected(ref this, out var ret);
    121.             return ret;
    122.         }
    123.         [NativeThrows]
    124.         set
    125.         {
    126.             set_startLifetime_Injected(ref this, ref value);
    127.         }
    128.     }
    129.     //
    130.     // Summary:
    131.     //     A multiplier for ParticleSystem.MainModule._startLifetime.
    132.     public float startLifetimeMultiplier
    133.     {
    134.         get
    135.         {
    136.             return get_startLifetimeMultiplier_Injected(ref this);
    137.         }
    138.         [NativeThrows]
    139.         set
    140.         {
    141.             set_startLifetimeMultiplier_Injected(ref this, value);
    142.         }
    143.     }
    144.     //
    145.     // Summary:
    146.     //     The initial speed of particles when the Particle System first spawns them.
    147.     public MinMaxCurve startSpeed
    148.     {
    149.         get
    150.         {
    151.             get_startSpeed_Injected(ref this, out var ret);
    152.             return ret;
    153.         }
    154.         [NativeThrows]
    155.         set
    156.         {
    157.             set_startSpeed_Injected(ref this, ref value);
    158.         }
    159.     }
    160.     //
    161.     // Summary:
    162.     //     A multiplier for ParticleSystem.MainModule._startSpeed.
    163.     public float startSpeedMultiplier
    164.     {
    165.         get
    166.         {
    167.             return get_startSpeedMultiplier_Injected(ref this);
    168.         }
    169.         [NativeThrows]
    170.         set
    171.         {
    172.             set_startSpeedMultiplier_Injected(ref this, value);
    173.         }
    174.     }
    175.     //
    176.     // Summary:
    177.     //     A flag to enable specifying particle size individually for each axis.
    178.     public bool startSize3D
    179.     {
    180.         get
    181.         {
    182.             return get_startSize3D_Injected(ref this);
    183.         }
    184.         [NativeThrows]
    185.         set
    186.         {
    187.             set_startSize3D_Injected(ref this, value);
    188.         }
    189.     }
    190.     //
    191.     // Summary:
    192.     //     The initial size of particles when the Particle System first spawns them.
    193.     [NativeName("StartSizeX")]
    194.     public MinMaxCurve startSize
    195.     {
    196.         get
    197.         {
    198.             get_startSize_Injected(ref this, out var ret);
    199.             return ret;
    200.         }
    201.         [NativeThrows]
    202.         set
    203.         {
    204.             set_startSize_Injected(ref this, ref value);
    205.         }
    206.     }
    207.     //
    208.     // Summary:
    209.     //     A multiplier for the initial size of particles when the Particle System first
    210.     //     spawns them.
    211.     [NativeName("StartSizeXMultiplier")]
    212.     public float startSizeMultiplier
    213.     {
    214.         get
    215.         {
    216.             return get_startSizeMultiplier_Injected(ref this);
    217.         }
    218.         [NativeThrows]
    219.         set
    220.         {
    221.             set_startSizeMultiplier_Injected(ref this, value);
    222.         }
    223.     }
    224.     //
    225.     // Summary:
    226.     //     The initial size of particles along the x-axis when the Particle System first
    227.     //     spawns them.
    228.     public MinMaxCurve startSizeX
    229.     {
    230.         get
    231.         {
    232.             get_startSizeX_Injected(ref this, out var ret);
    233.             return ret;
    234.         }
    235.         [NativeThrows]
    236.         set
    237.         {
    238.             set_startSizeX_Injected(ref this, ref value);
    239.         }
    240.     }
    241.     //
    242.     // Summary:
    243.     //     A multiplier for ParticleSystem.MainModule._startSizeX.
    244.     public float startSizeXMultiplier
    245.     {
    246.         get
    247.         {
    248.             return get_startSizeXMultiplier_Injected(ref this);
    249.         }
    250.         [NativeThrows]
    251.         set
    252.         {
    253.             set_startSizeXMultiplier_Injected(ref this, value);
    254.         }
    255.     }
    256.     //
    257.     // Summary:
    258.     //     The initial size of particles along the y-axis when the Particle System first
    259.     //     spawns them.
    260.     public MinMaxCurve startSizeY
    261.     {
    262.         get
    263.         {
    264.             get_startSizeY_Injected(ref this, out var ret);
    265.             return ret;
    266.         }
    267.         [NativeThrows]
    268.         set
    269.         {
    270.             set_startSizeY_Injected(ref this, ref value);
    271.         }
    272.     }
    273.     //
    274.     // Summary:
    275.     //     A multiplier for ParticleSystem.MainModule._startSizeY.
    276.     public float startSizeYMultiplier
    277.     {
    278.         get
    279.         {
    280.             return get_startSizeYMultiplier_Injected(ref this);
    281.         }
    282.         [NativeThrows]
    283.         set
    284.         {
    285.             set_startSizeYMultiplier_Injected(ref this, value);
    286.         }
    287.     }
    288.     //
    289.     // Summary:
    290.     //     The initial size of particles along the z-axis when the Particle System first
    291.     //     spawns them.
    292.     public MinMaxCurve startSizeZ
    293.     {
    294.         get
    295.         {
    296.             get_startSizeZ_Injected(ref this, out var ret);
    297.             return ret;
    298.         }
    299.         [NativeThrows]
    300.         set
    301.         {
    302.             set_startSizeZ_Injected(ref this, ref value);
    303.         }
    304.     }
    305.     //
    306.     // Summary:
    307.     //     A multiplier for ParticleSystem.MainModule._startSizeZ.
    308.     public float startSizeZMultiplier
    309.     {
    310.         get
    311.         {
    312.             return get_startSizeZMultiplier_Injected(ref this);
    313.         }
    314.         [NativeThrows]
    315.         set
    316.         {
    317.             set_startSizeZMultiplier_Injected(ref this, value);
    318.         }
    319.     }
    320.     //
    321.     // Summary:
    322.     //     A flag to enable 3D particle rotation.
    323.     public bool startRotation3D
    324.     {
    325.         get
    326.         {
    327.             return get_startRotation3D_Injected(ref this);
    328.         }
    329.         [NativeThrows]
    330.         set
    331.         {
    332.             set_startRotation3D_Injected(ref this, value);
    333.         }
    334.     }
    335.     //
    336.     // Summary:
    337.     //     The initial rotation of particles when the Particle System first spawns them.
    338.     [NativeName("StartRotationZ")]
    339.     public MinMaxCurve startRotation
    340.     {
    341.         get
    342.         {
    343.             get_startRotation_Injected(ref this, out var ret);
    344.             return ret;
    345.         }
    346.         [NativeThrows]
    347.         set
    348.         {
    349.             set_startRotation_Injected(ref this, ref value);
    350.         }
    351.     }
    352.     //
    353.     // Summary:
    354.     //     A multiplier for ParticleSystem.MainModule._startRotation.
    355.     [NativeName("StartRotationZMultiplier")]
    356.     public float startRotationMultiplier
    357.     {
    358.         get
    359.         {
    360.             return get_startRotationMultiplier_Injected(ref this);
    361.         }
    362.         [NativeThrows]
    363.         set
    364.         {
    365.             set_startRotationMultiplier_Injected(ref this, value);
    366.         }
    367.     }
    368.     //
    369.     // Summary:
    370.     //     The initial rotation of particles around the x-axis when emitted.
    371.     public MinMaxCurve startRotationX
    372.     {
    373.         get
    374.         {
    375.             get_startRotationX_Injected(ref this, out var ret);
    376.             return ret;
    377.         }
    378.         [NativeThrows]
    379.         set
    380.         {
    381.             set_startRotationX_Injected(ref this, ref value);
    382.         }
    383.     }
    384.     //
    385.     // Summary:
    386.     //     The initial rotation multiplier of particles around the x-axis when the Particle
    387.     //     System first spawns them.
    388.     public float startRotationXMultiplier
    389.     {
    390.         get
    391.         {
    392.             return get_startRotationXMultiplier_Injected(ref this);
    393.         }
    394.         [NativeThrows]
    395.         set
    396.         {
    397.             set_startRotationXMultiplier_Injected(ref this, value);
    398.         }
    399.     }
    400.     //
    401.     // Summary:
    402.     //     The initial rotation of particles around the y-axis when the Particle System
    403.     //     first spawns them.
    404.     public MinMaxCurve startRotationY
    405.     {
    406.         get
    407.         {
    408.             get_startRotationY_Injected(ref this, out var ret);
    409.             return ret;
    410.         }
    411.         [NativeThrows]
    412.         set
    413.         {
    414.             set_startRotationY_Injected(ref this, ref value);
    415.         }
    416.     }
    417.     //
    418.     // Summary:
    419.     //     The initial rotation multiplier of particles around the y-axis when the Particle
    420.     //     System first spawns them..
    421.     public float startRotationYMultiplier
    422.     {
    423.         get
    424.         {
    425.             return get_startRotationYMultiplier_Injected(ref this);
    426.         }
    427.         [NativeThrows]
    428.         set
    429.         {
    430.             set_startRotationYMultiplier_Injected(ref this, value);
    431.         }
    432.     }
    433.     //
    434.     // Summary:
    435.     //     The initial rotation of particles around the z-axis when the Particle System
    436.     //     first spawns them
    437.     public MinMaxCurve startRotationZ
    438.     {
    439.         get
    440.         {
    441.             get_startRotationZ_Injected(ref this, out var ret);
    442.             return ret;
    443.         }
    444.         [NativeThrows]
    445.         set
    446.         {
    447.             set_startRotationZ_Injected(ref this, ref value);
    448.         }
    449.     }
    450.     //
    451.     // Summary:
    452.     //     The initial rotation multiplier of particles around the z-axis when the Particle
    453.     //     System first spawns them.
    454.     public float startRotationZMultiplier
    455.     {
    456.         get
    457.         {
    458.             return get_startRotationZMultiplier_Injected(ref this);
    459.         }
    460.         [NativeThrows]
    461.         set
    462.         {
    463.             set_startRotationZMultiplier_Injected(ref this, value);
    464.         }
    465.     }
    466.     //
    467.     // Summary:
    468.     //     Makes some particles spin in the opposite direction.
    469.     public float flipRotation
    470.     {
    471.         get
    472.         {
    473.             return get_flipRotation_Injected(ref this);
    474.         }
    475.         [NativeThrows]
    476.         set
    477.         {
    478.             set_flipRotation_Injected(ref this, value);
    479.         }
    480.     }
    481.     //
    482.     // Summary:
    483.     //     The initial color of particles when the Particle System first spawns them.
    484.     public MinMaxGradient startColor
    485.     {
    486.         get
    487.         {
    488.             get_startColor_Injected(ref this, out var ret);
    489.             return ret;
    490.         }
    491.         [NativeThrows]
    492.         set
    493.         {
    494.             set_startColor_Injected(ref this, ref value);
    495.         }
    496.     }
    497.     //
    498.     // Summary:
    499.     //     A scale that this Particle System applies to gravity, defined by Physics.gravity.
    500.     public MinMaxCurve gravityModifier
    501.     {
    502.         get
    503.         {
    504.             get_gravityModifier_Injected(ref this, out var ret);
    505.             return ret;
    506.         }
    507.         [NativeThrows]
    508.         set
    509.         {
    510.             set_gravityModifier_Injected(ref this, ref value);
    511.         }
    512.     }
    513.     //
    514.     // Summary:
    515.     //     Change the gravity multiplier.
    516.     public float gravityModifierMultiplier
    517.     {
    518.         get
    519.         {
    520.             return get_gravityModifierMultiplier_Injected(ref this);
    521.         }
    522.         [NativeThrows]
    523.         set
    524.         {
    525.             set_gravityModifierMultiplier_Injected(ref this, value);
    526.         }
    527.     }
    528.     //
    529.     // Summary:
    530.     //     This selects the space in which to simulate particles. It can be either world
    531.     //     or local space.
    532.     public ParticleSystemSimulationSpace simulationSpace
    533.     {
    534.         get
    535.         {
    536.             return get_simulationSpace_Injected(ref this);
    537.         }
    538.         [NativeThrows]
    539.         set
    540.         {
    541.             set_simulationSpace_Injected(ref this, value);
    542.         }
    543.     }
    544.     //
    545.     // Summary:
    546.     //     Simulate particles relative to a custom transform component.
    547.     public Transform customSimulationSpace
    548.     {
    549.         get
    550.         {
    551.             return get_customSimulationSpace_Injected(ref this);
    552.         }
    553.         [NativeThrows]
    554.         set
    555.         {
    556.             set_customSimulationSpace_Injected(ref this, value);
    557.         }
    558.     }
    559.     //
    560.     // Summary:
    561.     //     Override the default playback speed of the Particle System.
    562.     public float simulationSpeed
    563.     {
    564.         get
    565.         {
    566.             return get_simulationSpeed_Injected(ref this);
    567.         }
    568.         [NativeThrows]
    569.         set
    570.         {
    571.             set_simulationSpeed_Injected(ref this, value);
    572.         }
    573.     }
    574.     //
    575.     // Summary:
    576.     //     When true, use the unscaled delta time to simulate the Particle System. Otherwise,
    577.     //     use the scaled delta time.
    578.     public bool useUnscaledTime
    579.     {
    580.         get
    581.         {
    582.             return get_useUnscaledTime_Injected(ref this);
    583.         }
    584.         [NativeThrows]
    585.         set
    586.         {
    587.             set_useUnscaledTime_Injected(ref this, value);
    588.         }
    589.     }
    590.     //
    591.     // Summary:
    592.     //     Control how the Particle System applies its Transform component to the particles
    593.     //     it emits.
    594.     public ParticleSystemScalingMode scalingMode
    595.     {
    596.         get
    597.         {
    598.             return get_scalingMode_Injected(ref this);
    599.         }
    600.         [NativeThrows]
    601.         set
    602.         {
    603.             set_scalingMode_Injected(ref this, value);
    604.         }
    605.     }
    606.     //
    607.     // Summary:
    608.     //     If set to true, the Particle System automatically begins to play on startup.
    609.     public bool playOnAwake
    610.     {
    611.         get
    612.         {
    613.             return get_playOnAwake_Injected(ref this);
    614.         }
    615.         [NativeThrows]
    616.         set
    617.         {
    618.             set_playOnAwake_Injected(ref this, value);
    619.         }
    620.     }
    621.     //
    622.     // Summary:
    623.     //     The maximum number of particles to emit.
    624.     public int maxParticles
    625.     {
    626.         get
    627.         {
    628.             return get_maxParticles_Injected(ref this);
    629.         }
    630.         [NativeThrows]
    631.         set
    632.         {
    633.             set_maxParticles_Injected(ref this, value);
    634.         }
    635.     }
    636.     //
    637.     // Summary:
    638.     //     Control how the Particle System calculates its velocity, when moving in the world.
    639.     public ParticleSystemEmitterVelocityMode emitterVelocityMode
    640.     {
    641.         get
    642.         {
    643.             return get_emitterVelocityMode_Injected(ref this);
    644.         }
    645.         [NativeThrows]
    646.         set
    647.         {
    648.             set_emitterVelocityMode_Injected(ref this, value);
    649.         }
    650.     }
    651.     //
    652.     // Summary:
    653.     //     Select whether to Disable or Destroy the GameObject, or to call the MonoBehaviour.OnParticleSystemStopped
    654.     //     script Callback, when the Particle System stops and all particles have died.
    655.     public ParticleSystemStopAction stopAction
    656.     {
    657.         get
    658.         {
    659.             return get_stopAction_Injected(ref this);
    660.         }
    661.         [NativeThrows]
    662.         set
    663.         {
    664.             set_stopAction_Injected(ref this, value);
    665.         }
    666.     }
    667.     //
    668.     // Summary:
    669.     //     Configure the Particle System to not kill its particles when their lifetimes
    670.     //     are exceeded.
    671.     public ParticleSystemRingBufferMode ringBufferMode
    672.     {
    673.         get
    674.         {
    675.             return get_ringBufferMode_Injected(ref this);
    676.         }
    677.         [NativeThrows]
    678.         set
    679.         {
    680.             set_ringBufferMode_Injected(ref this, value);
    681.         }
    682.     }
    683.     //
    684.     // Summary:
    685.     //     When ParticleSystem.MainModule.ringBufferMode is set to loop, this value defines
    686.     //     the proportion of the particle life that loops.
    687.     public Vector2 ringBufferLoopRange
    688.     {
    689.         get
    690.         {
    691.             get_ringBufferLoopRange_Injected(ref this, out var ret);
    692.             return ret;
    693.         }
    694.         [NativeThrows]
    695.         set
    696.         {
    697.             set_ringBufferLoopRange_Injected(ref this, ref value);
    698.         }
    699.     }
    700.     //
    701.     // Summary:
    702.     //     Configure whether the Particle System will still be simulated each frame, when
    703.     //     it is offscreen.
    704.     public ParticleSystemCullingMode cullingMode
    705.     {
    706.         get
    707.         {
    708.             return get_cullingMode_Injected(ref this);
    709.         }
    710.         [NativeThrows]
    711.         set
    712.         {
    713.             set_cullingMode_Injected(ref this, value);
    714.         }
    715.     }
    716.     internal MainModule(ParticleSystem particleSystem)
    717.     {
    718.         m_ParticleSystem = particleSystem;
    719.     }
    720.     [MethodImpl(MethodImplOptions.InternalCall)]
    721.     [SpecialName]
    722.     private static extern void get_emitterVelocity_Injected(ref MainModule _unity_self, out Vector3 ret);
    723.     [MethodImpl(MethodImplOptions.InternalCall)]
    724.     [SpecialName]
    725.     private static extern void set_emitterVelocity_Injected(ref MainModule _unity_self, ref Vector3 value);
    726.     [MethodImpl(MethodImplOptions.InternalCall)]
    727.     [SpecialName]
    728.     private static extern float get_duration_Injected(ref MainModule _unity_self);
    729.     [MethodImpl(MethodImplOptions.InternalCall)]
    730.     [SpecialName]
    731.     private static extern void set_duration_Injected(ref MainModule _unity_self, float value);
    732.     [MethodImpl(MethodImplOptions.InternalCall)]
    733.     [SpecialName]
    734.     private static extern bool get_loop_Injected(ref MainModule _unity_self);
    735.     [MethodImpl(MethodImplOptions.InternalCall)]
    736.     [SpecialName]
    737.     private static extern void set_loop_Injected(ref MainModule _unity_self, bool value);
    738.     [MethodImpl(MethodImplOptions.InternalCall)]
    739.     [SpecialName]
    740.     private static extern bool get_prewarm_Injected(ref MainModule _unity_self);
    741.     [MethodImpl(MethodImplOptions.InternalCall)]
    742.     [SpecialName]
    743.     private static extern void set_prewarm_Injected(ref MainModule _unity_self, bool value);
    744.     [MethodImpl(MethodImplOptions.InternalCall)]
    745.     [SpecialName]
    746.     private static extern void get_startDelay_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    747.     [MethodImpl(MethodImplOptions.InternalCall)]
    748.     [SpecialName]
    749.     private static extern void set_startDelay_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    750.     [MethodImpl(MethodImplOptions.InternalCall)]
    751.     [SpecialName]
    752.     private static extern float get_startDelayMultiplier_Injected(ref MainModule _unity_self);
    753.     [MethodImpl(MethodImplOptions.InternalCall)]
    754.     [SpecialName]
    755.     private static extern void set_startDelayMultiplier_Injected(ref MainModule _unity_self, float value);
    756.     [MethodImpl(MethodImplOptions.InternalCall)]
    757.     [SpecialName]
    758.     private static extern void get_startLifetime_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    759.     [MethodImpl(MethodImplOptions.InternalCall)]
    760.     [SpecialName]
    761.     private static extern void set_startLifetime_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    762.     [MethodImpl(MethodImplOptions.InternalCall)]
    763.     [SpecialName]
    764.     private static extern float get_startLifetimeMultiplier_Injected(ref MainModule _unity_self);
    765.     [MethodImpl(MethodImplOptions.InternalCall)]
    766.     [SpecialName]
    767.     private static extern void set_startLifetimeMultiplier_Injected(ref MainModule _unity_self, float value);
    768.     [MethodImpl(MethodImplOptions.InternalCall)]
    769.     [SpecialName]
    770.     private static extern void get_startSpeed_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    771.     [MethodImpl(MethodImplOptions.InternalCall)]
    772.     [SpecialName]
    773.     private static extern void set_startSpeed_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    774.     [MethodImpl(MethodImplOptions.InternalCall)]
    775.     [SpecialName]
    776.     private static extern float get_startSpeedMultiplier_Injected(ref MainModule _unity_self);
    777.     [MethodImpl(MethodImplOptions.InternalCall)]
    778.     [SpecialName]
    779.     private static extern void set_startSpeedMultiplier_Injected(ref MainModule _unity_self, float value);
    780.     [MethodImpl(MethodImplOptions.InternalCall)]
    781.     [SpecialName]
    782.     private static extern bool get_startSize3D_Injected(ref MainModule _unity_self);
    783.     [MethodImpl(MethodImplOptions.InternalCall)]
    784.     [SpecialName]
    785.     private static extern void set_startSize3D_Injected(ref MainModule _unity_self, bool value);
    786.     [MethodImpl(MethodImplOptions.InternalCall)]
    787.     [SpecialName]
    788.     private static extern void get_startSize_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    789.     [MethodImpl(MethodImplOptions.InternalCall)]
    790.     [SpecialName]
    791.     private static extern void set_startSize_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    792.     [MethodImpl(MethodImplOptions.InternalCall)]
    793.     [SpecialName]
    794.     private static extern float get_startSizeMultiplier_Injected(ref MainModule _unity_self);
    795.     [MethodImpl(MethodImplOptions.InternalCall)]
    796.     [SpecialName]
    797.     private static extern void set_startSizeMultiplier_Injected(ref MainModule _unity_self, float value);
    798.     [MethodImpl(MethodImplOptions.InternalCall)]
    799.     [SpecialName]
    800.     private static extern void get_startSizeX_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    801.     [MethodImpl(MethodImplOptions.InternalCall)]
    802.     [SpecialName]
    803.     private static extern void set_startSizeX_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    804.     [MethodImpl(MethodImplOptions.InternalCall)]
    805.     [SpecialName]
    806.     private static extern float get_startSizeXMultiplier_Injected(ref MainModule _unity_self);
    807.     [MethodImpl(MethodImplOptions.InternalCall)]
    808.     [SpecialName]
    809.     private static extern void set_startSizeXMultiplier_Injected(ref MainModule _unity_self, float value);
    810.     [MethodImpl(MethodImplOptions.InternalCall)]
    811.     [SpecialName]
    812.     private static extern void get_startSizeY_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    813.     [MethodImpl(MethodImplOptions.InternalCall)]
    814.     [SpecialName]
    815.     private static extern void set_startSizeY_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    816.     [MethodImpl(MethodImplOptions.InternalCall)]
    817.     [SpecialName]
    818.     private static extern float get_startSizeYMultiplier_Injected(ref MainModule _unity_self);
    819.     [MethodImpl(MethodImplOptions.InternalCall)]
    820.     [SpecialName]
    821.     private static extern void set_startSizeYMultiplier_Injected(ref MainModule _unity_self, float value);
    822.     [MethodImpl(MethodImplOptions.InternalCall)]
    823.     [SpecialName]
    824.     private static extern void get_startSizeZ_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    825.     [MethodImpl(MethodImplOptions.InternalCall)]
    826.     [SpecialName]
    827.     private static extern void set_startSizeZ_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    828.     [MethodImpl(MethodImplOptions.InternalCall)]
    829.     [SpecialName]
    830.     private static extern float get_startSizeZMultiplier_Injected(ref MainModule _unity_self);
    831.     [MethodImpl(MethodImplOptions.InternalCall)]
    832.     [SpecialName]
    833.     private static extern void set_startSizeZMultiplier_Injected(ref MainModule _unity_self, float value);
    834.     [MethodImpl(MethodImplOptions.InternalCall)]
    835.     [SpecialName]
    836.     private static extern bool get_startRotation3D_Injected(ref MainModule _unity_self);
    837.     [MethodImpl(MethodImplOptions.InternalCall)]
    838.     [SpecialName]
    839.     private static extern void set_startRotation3D_Injected(ref MainModule _unity_self, bool value);
    840.     [MethodImpl(MethodImplOptions.InternalCall)]
    841.     [SpecialName]
    842.     private static extern void get_startRotation_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    843.     [MethodImpl(MethodImplOptions.InternalCall)]
    844.     [SpecialName]
    845.     private static extern void set_startRotation_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    846.     [MethodImpl(MethodImplOptions.InternalCall)]
    847.     [SpecialName]
    848.     private static extern float get_startRotationMultiplier_Injected(ref MainModule _unity_self);
    849.     [MethodImpl(MethodImplOptions.InternalCall)]
    850.     [SpecialName]
    851.     private static extern void set_startRotationMultiplier_Injected(ref MainModule _unity_self, float value);
    852.     [MethodImpl(MethodImplOptions.InternalCall)]
    853.     [SpecialName]
    854.     private static extern void get_startRotationX_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    855.     [MethodImpl(MethodImplOptions.InternalCall)]
    856.     [SpecialName]
    857.     private static extern void set_startRotationX_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    858.     [MethodImpl(MethodImplOptions.InternalCall)]
    859.     [SpecialName]
    860.     private static extern float get_startRotationXMultiplier_Injected(ref MainModule _unity_self);
    861.     [MethodImpl(MethodImplOptions.InternalCall)]
    862.     [SpecialName]
    863.     private static extern void set_startRotationXMultiplier_Injected(ref MainModule _unity_self, float value);
    864.     [MethodImpl(MethodImplOptions.InternalCall)]
    865.     [SpecialName]
    866.     private static extern void get_startRotationY_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    867.     [MethodImpl(MethodImplOptions.InternalCall)]
    868.     [SpecialName]
    869.     private static extern void set_startRotationY_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    870.     [MethodImpl(MethodImplOptions.InternalCall)]
    871.     [SpecialName]
    872.     private static extern float get_startRotationYMultiplier_Injected(ref MainModule _unity_self);
    873.     [MethodImpl(MethodImplOptions.InternalCall)]
    874.     [SpecialName]
    875.     private static extern void set_startRotationYMultiplier_Injected(ref MainModule _unity_self, float value);
    876.     [MethodImpl(MethodImplOptions.InternalCall)]
    877.     [SpecialName]
    878.     private static extern void get_startRotationZ_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    879.     [MethodImpl(MethodImplOptions.InternalCall)]
    880.     [SpecialName]
    881.     private static extern void set_startRotationZ_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    882.     [MethodImpl(MethodImplOptions.InternalCall)]
    883.     [SpecialName]
    884.     private static extern float get_startRotationZMultiplier_Injected(ref MainModule _unity_self);
    885.     [MethodImpl(MethodImplOptions.InternalCall)]
    886.     [SpecialName]
    887.     private static extern void set_startRotationZMultiplier_Injected(ref MainModule _unity_self, float value);
    888.     [MethodImpl(MethodImplOptions.InternalCall)]
    889.     [SpecialName]
    890.     private static extern float get_flipRotation_Injected(ref MainModule _unity_self);
    891.     [MethodImpl(MethodImplOptions.InternalCall)]
    892.     [SpecialName]
    893.     private static extern void set_flipRotation_Injected(ref MainModule _unity_self, float value);
    894.     [MethodImpl(MethodImplOptions.InternalCall)]
    895.     [SpecialName]
    896.     private static extern void get_startColor_Injected(ref MainModule _unity_self, out MinMaxGradient ret);
    897.     [MethodImpl(MethodImplOptions.InternalCall)]
    898.     [SpecialName]
    899.     private static extern void set_startColor_Injected(ref MainModule _unity_self, ref MinMaxGradient value);
    900.     [MethodImpl(MethodImplOptions.InternalCall)]
    901.     [SpecialName]
    902.     private static extern void get_gravityModifier_Injected(ref MainModule _unity_self, out MinMaxCurve ret);
    903.     [MethodImpl(MethodImplOptions.InternalCall)]
    904.     [SpecialName]
    905.     private static extern void set_gravityModifier_Injected(ref MainModule _unity_self, ref MinMaxCurve value);
    906.     [MethodImpl(MethodImplOptions.InternalCall)]
    907.     [SpecialName]
    908.     private static extern float get_gravityModifierMultiplier_Injected(ref MainModule _unity_self);
    909.     [MethodImpl(MethodImplOptions.InternalCall)]
    910.     [SpecialName]
    911.     private static extern void set_gravityModifierMultiplier_Injected(ref MainModule _unity_self, float value);
    912.     [MethodImpl(MethodImplOptions.InternalCall)]
    913.     [SpecialName]
    914.     private static extern ParticleSystemSimulationSpace get_simulationSpace_Injected(ref MainModule _unity_self);
    915.     [MethodImpl(MethodImplOptions.InternalCall)]
    916.     [SpecialName]
    917.     private static extern void set_simulationSpace_Injected(ref MainModule _unity_self, ParticleSystemSimulationSpace value);
    918.     [MethodImpl(MethodImplOptions.InternalCall)]
    919.     [SpecialName]
    920.     private static extern Transform get_customSimulationSpace_Injected(ref MainModule _unity_self);
    921.     [MethodImpl(MethodImplOptions.InternalCall)]
    922.     [SpecialName]
    923.     private static extern void set_customSimulationSpace_Injected(ref MainModule _unity_self, Transform value);
    924.     [MethodImpl(MethodImplOptions.InternalCall)]
    925.     [SpecialName]
    926.     private static extern float get_simulationSpeed_Injected(ref MainModule _unity_self);
    927.     [MethodImpl(MethodImplOptions.InternalCall)]
    928.     [SpecialName]
    929.     private static extern void set_simulationSpeed_Injected(ref MainModule _unity_self, float value);
    930.     [MethodImpl(MethodImplOptions.InternalCall)]
    931.     [SpecialName]
    932.     private static extern bool get_useUnscaledTime_Injected(ref MainModule _unity_self);
    933.     [MethodImpl(MethodImplOptions.InternalCall)]
    934.     [SpecialName]
    935.     private static extern void set_useUnscaledTime_Injected(ref MainModule _unity_self, bool value);
    936.     [MethodImpl(MethodImplOptions.InternalCall)]
    937.     [SpecialName]
    938.     private static extern ParticleSystemScalingMode get_scalingMode_Injected(ref MainModule _unity_self);
    939.     [MethodImpl(MethodImplOptions.InternalCall)]
    940.     [SpecialName]
    941.     private static extern void set_scalingMode_Injected(ref MainModule _unity_self, ParticleSystemScalingMode value);
    942.     [MethodImpl(MethodImplOptions.InternalCall)]
    943.     [SpecialName]
    944.     private static extern bool get_playOnAwake_Injected(ref MainModule _unity_self);
    945.     [MethodImpl(MethodImplOptions.InternalCall)]
    946.     [SpecialName]
    947.     private static extern void set_playOnAwake_Injected(ref MainModule _unity_self, bool value);
    948.     [MethodImpl(MethodImplOptions.InternalCall)]
    949.     [SpecialName]
    950.     private static extern int get_maxParticles_Injected(ref MainModule _unity_self);
    951.     [MethodImpl(MethodImplOptions.InternalCall)]
    952.     [SpecialName]
    953.     private static extern void set_maxParticles_Injected(ref MainModule _unity_self, int value);
    954.     [MethodImpl(MethodImplOptions.InternalCall)]
    955.     [SpecialName]
    956.     private static extern ParticleSystemEmitterVelocityMode get_emitterVelocityMode_Injected(ref MainModule _unity_self);
    957.     [MethodImpl(MethodImplOptions.InternalCall)]
    958.     [SpecialName]
    959.     private static extern void set_emitterVelocityMode_Injected(ref MainModule _unity_self, ParticleSystemEmitterVelocityMode value);
    960.     [MethodImpl(MethodImplOptions.InternalCall)]
    961.     [SpecialName]
    962.     private static extern ParticleSystemStopAction get_stopAction_Injected(ref MainModule _unity_self);
    963.     [MethodImpl(MethodImplOptions.InternalCall)]
    964.     [SpecialName]
    965.     private static extern void set_stopAction_Injected(ref MainModule _unity_self, ParticleSystemStopAction value);
    966.     [MethodImpl(MethodImplOptions.InternalCall)]
    967.     [SpecialName]
    968.     private static extern ParticleSystemRingBufferMode get_ringBufferMode_Injected(ref MainModule _unity_self);
    969.     [MethodImpl(MethodImplOptions.InternalCall)]
    970.     [SpecialName]
    971.     private static extern void set_ringBufferMode_Injected(ref MainModule _unity_self, ParticleSystemRingBufferMode value);
    972.     [MethodImpl(MethodImplOptions.InternalCall)]
    973.     [SpecialName]
    974.     private static extern void get_ringBufferLoopRange_Injected(ref MainModule _unity_self, out Vector2 ret);
    975.     [MethodImpl(MethodImplOptions.InternalCall)]
    976.     [SpecialName]
    977.     private static extern void set_ringBufferLoopRange_Injected(ref MainModule _unity_self, ref Vector2 value);
    978.     [MethodImpl(MethodImplOptions.InternalCall)]
    979.     [SpecialName]
    980.     private static extern ParticleSystemCullingMode get_cullingMode_Injected(ref MainModule _unity_self);
    981.     [MethodImpl(MethodImplOptions.InternalCall)]
    982.     [SpecialName]
    983.     private static extern void set_cullingMode_Injected(ref MainModule _unity_self, ParticleSystemCullingMode value);
    984. }
    985.  
    As you can see, there isn't any variable in there. They're all using get & set-methods.
     
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    Like it was already mentioned, the modules are represented as structs. Usually you have to use a temporary copy of the struct and assign the struct back when done. Though since those structs just contains external methods / properties and the only actual "field" in that struct is the particle system reference it belongs to, just setting the property on the struct instance is enough.

    However this code:

    Code (CSharp):
    1. if (_target.GetType() == typeof(ParticleSystem))
    2. {
    3.     _propertyInfo.SetValue(_target.GetType().GetProperty(_moduleInfo.Name), value, null);
    4. }
    Simply makes no sense. SetValue expects an instance of the type the propertyInfo belongs to as well as the new value. So the first argument has to be the actual instance of the struct since the _propertyInfo belongs to the struct. The struct instance has to be retrieved through the "_moduleInfo" property of the ParticleSystem itself. You currently oass a PropertyInfo as instance to SetValue which of course makes no sense. You have to do

    Code (CSharp):
    1.     _propertyInfo.SetValue(_moduleInfo.GetValue(_target), value, null);
    As I said, usually you would need to cache the boxed object that _moduleInfo.GetValue returns as this is the actual "value" that is stored or returned by the property. Since those structs are just wrappers for native external methods, this line should be enough. Of course you could actually cache the object that GetValue returns for a particular particle system, since that struct would never change. As I said, the only field the struct actually has is the ParticleSystem reference. Actually, to make the process garbage free, you could store that struct ahead of time and use reflection to replace the internal ParticleSystem reference to the target particle system. That way you don't need to store several boxed struct values for each particle system.

    Though since you seem to aim for a more "general approach", you probably have to sacrifice some efficiency for usability / genericness.
     
  6. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    Neat idea, but I'm not sure this would work.
    All of the extern-calls are done using 'ref this'. So there's some funny stuff going on there, and it's probably using the actual memory-address or something to that effect (otherwise the C++ could simply use a copy and read the ParticleSystem from that to get to the proper object).
     
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    That's not an issue at all. As I said, you would need to update the internal m_ParticleSystem reference before you do work on your single instance. Of course the internal (external) methods would get a pointer to the single struct instance (boxed in our cached variable). But Unity only uses this struct instance to grab the actual ParticleSystem reference. So this does work. However since this is about creating an access node for one particular particle system, it's much easier to grab the boxed struct instance in the setup phase, so you don't have to grab a new one each time.

    So in OnEnable you can do

    Code (CSharp):
    1. _boxedStruct = _moduleInfo.GetValue(_target);
    where "_boxedStruct" would be an object variable to store the boxed struct for later use. So inside the actual input property you can simply do

    Code (CSharp):
    1. _propertyInfo.SetValue(_boxedStruct, value, null);
    and it would work equally well, without extra garbage each time the input property is set. Since the ParticleSystem we're interested in does not change during the lifetime of this node, the module struct also does not change, since all it has is the reference to the particle system.

    Just to be clear what I was talking about. This line
    _moduleInfo.GetValue(_target);
    does allocate memory since we get a struct here as an
    object
    so it needs to be boxed. Though since we can simply reuse the struct in this case, we don't have to allocate a new struct each time.

    Reflection works best with objects and references. Values types are always a pain in the back since reflection can only work with them in boxed form. In rare cases, when you have a method that returns a value type, you could actually create a delegate that does return the actual struct. Though that only works in cases where the struct is an accessible type (no internal / private type) and all you want to access can be accessed from the struct itself. So when building a an actual delegate for such a hidden method, we actually left the reflection world and are back in the normal C# world.
     
  8. MysticalMonkeys

    MysticalMonkeys

    Joined:
    Dec 5, 2022
    Posts:
    6
    Interesting discussion, thanks everyone.

    Code (CSharp):
    1.     _propertyInfo.SetValue(_moduleInfo.GetValue(_target), value, null);
    This indeed did the trick!
     
  9. MysticalMonkeys

    MysticalMonkeys

    Joined:
    Dec 5, 2022
    Posts:
    6
    Ah yes good idea! Thanks again.
     
  10. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    Weird. Why would it then need a 'ref this', instead of just 'this'?
     
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    Well, the native methods are external methods, so they are static by default. Without "ref" the argument would be a normal argument and would be copied by default.

    Yes "normal" instance methods of a struct would already have a reference / pointer to the instance by default. Though this implicit "this" reference / pointer is always hidden from us. That's why we use a high level language :) Always keep in mind that in the end every piece of C# code is actually static code that lives in one single place in memory. Every single method. Instance methods just receive their instance as implicit argument. With reflection, depending on the exact case, you can often even map instance methods to delegates that take the implicit this as first the argument. That's how extension methods work as well. Extension methods are the same as instance methods, just without the implicit this, but with an explicit this.

    Note that in the past extension methods on struct types would essentially work on a copy of the struct, like any other method would. However since I think C#7 or so they introduced "ref" extension methods for structs. So now we can do

    Code (CSharp):
    1. public static void SomeExtMethod(this ref MyStructType aInstance)
    2. {
    3.     // [ ... ]
    4. }
    5.  
    6. MyStructType inst = new MyStructType();
    7. inst.SomeExtMethod();
    8.  
    Here we get an actual ref / pointer to the struct instance, so we can actually modify it, like a normal member method can.
     
  12. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    I understand all of this.

    But a copy would also have its
    internal ParticleSystem m_ParticleSystem;
    filled with a pointer to the same ParticleSystem-instance. So why the 'ref', if it's just going to be grabbing the m_ParticleSystem from it? Just to avoid creating a copy in RAM?

    It would make more sense if the 'ref' is so that the C++-side gets the actual instance, and can then grab the memory-address from it (std::addressof) for some other things.
     
    Last edited: Feb 16, 2023
  13. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    Well, in this particular case it wouldn't make much difference since the struct only contains a reference to the particle system. So it doesn't really make any difference here. Though in other cases the struct may contain other information that doesn't need to be copied. So they generally stick to indirect referencing. Why they have done this in this particular case, we don't know. Could have internal reasons or just a different style of a different department. Since that's all internal implementation details, we should not think about it too much :)