Get Particles Value cannot be null.

stockingem 2 years ago updated 2 years ago 7

Hi everyone. I looked for solution in existing topics, but this bug reproduces even in fresh empty project with all settings correct (net4 etc)

Every time I connect Particle System variable to Get Particles node — I get this error spam

ArgumentNullException: Value cannot be null.
Parameter name: particles
UnityEngine.ParticleSystem.GetParticles (UnityEngine.ParticleSystem+Particle[] particles, System.Int32 size) (at C:/buildslave/unity/build/Modules/ParticleSystem/ScriptBindings/ParticleSystem.bindings.cs:96)
UnityEngine.ParticleSystem.GetParticles (UnityEngine.ParticleSystem+Particle[] particles) (at C:/buildslave/unity/build/Modules/ParticleSystem/ScriptBindings/ParticleSystem.bindings.cs:97)
Ludiq.InstanceFunctionInvoker`3[TTarget,TParam0,TResult].InvokeUnsafe (System.Object target, System.Object arg0) (at C:/Users/lazlo/Projects/Bolt1/Package/Ludiq.Core/Runtime/Reflection/Optimization/InstanceFunctionInvoker_1.cs:51)
Ludiq.InstanceFunctionInvoker`3[TTarget,TParam0,TResult].Invoke (System.Object target, System.Object arg0) (at C:/Users/lazlo/Projects/Bolt1/Package/Ludiq.Core/Runtime/Reflection/Optimization/InstanceFunctionInvoker_1.cs:32)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
Ludiq.InstanceFunctionInvoker`3[TTarget,TParam0,TResult].Invoke (System.Object target, System.Object arg0) (at C:/Users/lazlo/Projects/Bolt1/Package/Ludiq.Core/Runtime/Reflection/Optimization/InstanceFunctionInvoker_1.cs:40)
Ludiq.InstanceFunctionInvoker`3[TTarget,TParam0,TResult].Invoke (System.Object target, System.Object[] args) (at C:/Users/lazlo/Projects/Bolt1/Package/Ludiq.Core/Runtime/Reflection/Optimization/InstanceFunctionInvoker_1.cs:20)
Ludiq.Member.Invoke (System.Object target, System.Object[] arguments) (at C:/Users/lazlo/Projects/Bolt1/Package/Ludiq.Core/Runtime/Reflection/Member.cs:1045)
Bolt.InvokeMember.Invoke (System.Object target, Bolt.Flow flow) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Framework/Codebase/InvokeMember.cs:220)
Bolt.InvokeMember.Enter (Bolt.Flow flow) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Framework/Codebase/InvokeMember.cs:262)
Bolt.Flow.InvokeDelegate (Bolt.ControlInput input) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Flow.cs:447)
Bolt.Flow.Invoke (Bolt.ControlOutput output) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Flow.cs:341)
Bolt.Flow.Run (Bolt.ControlOutput port) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Flow.cs:244)
Bolt.EventUnit`1[TArgs].Run (Bolt.Flow flow) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Framework/Events/EventUnit.cs:179)
Bolt.EventUnit`1[TArgs].Trigger (Ludiq.GraphReference reference, TArgs args) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Framework/Events/EventUnit.cs:150)
Bolt.EventUnit`1+<>c__DisplayClass14_0[TArgs].b__0 (TArgs args) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Flow/Runtime/Framework/Events/EventUnit.cs:69)
Bolt.EventBus.Trigger[TArgs] (Bolt.EventHook hook, TArgs args) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Core/Runtime/Events/EventBus.cs:72)
Bolt.EventMachine`2[TGraph,TMacro].TriggerRegisteredEvent[TArgs] (Bolt.EventHook hook, TArgs args) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Core/Runtime/Events/EventMachine.cs:36)
Bolt.EventMachine`2[TGraph,TMacro].TriggerEvent (System.String name) (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Core/Runtime/Events/EventMachine.cs:14)
Bolt.EventMachine`2[TGraph,TMacro].Update () (at C:/Users/lazlo/Projects/Bolt1/Package/Bolt.Core/Runtime/Events/EventMachine.cs:75)

Bolt Version:
Unity Version:
Scripting Backend:
.NET Version (API Compatibility Level):
.NET 4.x

Hello Stockingem,

I'm sorry you're experiencing this issue and I apologize for the late reply on this. You should hear back on this from the lead developer soon.


Hasan from Ludiq

Need More Information

Hi Stockinghem,

Could you please send a screenshot of your graph?

Sorry for the delay


Hi Sotckingem,

Thanks for the screenshot. This does look like a bug indeed, I'll investigate.

Fixed (Unreleased)

Hi Stockingem,

Thanks for the report. I investigated and learned something new!

Unity declares ParticleSystem.GetParticles like this:

public int GetParticles([Out] ParticleSystem.Particle[] particles) { return GetParticles(particles, -1); }

Notice the [Out] attribute, which is necessary for the native P/Invoke interop.

However, this [Out] attribute also makes it so that ParameterInfo.IsOut returns true. Which is what Bolt uses to check whether a parameter has the C# "out" modifier, that guarantees assignment from within the method itself. 

This is a tricky edge case of reflection and the CLR not uniformly implementing the out modifier:


In other words, this attribute made Bolt think that the particles parameter was a pure output parameter, whereas in fact, Unity requires an existing array to be passed.

I fixed it by changing my detection code for the "out" modifier to also check for IsByRef:

        // <a href="https://stackoverflow.com/questions/30102174/" class="redactor-autoparser-object">https://stackoverflow.com/questions/30102174/</a>
        public static bool HasOutModifier(this ParameterInfo parameterInfo)

            // Checking for IsOut is not enough, because parameters marked with the [Out] attribute
            // also return true, while not necessarily having the "out" modifier. This is common for P/Invoke,
            // for example in Unity's ParticleSystem.GetParticles.
            return parameterInfo.IsOut && parameterInfo.ParameterType.IsByRef;

Funnily enough, Unity's own documentation doesn't differentiate those properly either! In the documentation page, you'll see the particles parameter being falsely tagged as having an out modifier:


Now, getting this particular method to work in Bolt 1 is a bit tricky, because you need to pre-allocate a properly typed array. Here's a guide (that will only work once Bolt has been updated with the fix):

1. Open Tools > Bolt > Unit Options Wizard

2. Add System.Array to your types

3. Add "Particle of Particle System" to your types:

4. Hit Generate and wait

5. In your graph, add Array: Create Instance with a single element type

6. On the Element Type port, pick Particle of Particle System:

7. In the Length port, pick how many max particles you want to retrieve from the particle system.

8. Pass the created array to ParticleSystem.GetParticles

9. Use a For Loop + Get List Item to retrieve each returned particle

In the following example, I log the position of the first 100 particles in the system:

Thank you, Lazlo!