Search Unity

Question Actions + static class not working. Sending null error

Discussion in 'Scripting' started by Corva-Nocta, Nov 27, 2022.

  1. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Hey all,
    I'm a little confused about this problem. I'm trying to make some Actions to work with, but for some reason I can't get it to work. I added the Actions to a static class, which should mean I can use it without having to add it to an object in my scene right? Here is what I am working with:

    Code (csharp):
    1. using UnityEngine;
    2. using System;
    3. public static class Actions
    4. {
    5.     public static Action<Vector3> OnClickGround;
    6.     public static Action<ulong> OnClickObject;
    7. }
    which seems to be fine, no errors. But then why I try to call any of the actions I use this code:

    Code (csharp):
    1. using UnityEngine;
    2. using Unity.Netcode;
    3. using UnityEngine.EventSystems;
    4. public class ClickToMove : MonoBehaviour
    5. {
    6.     private void Update()
    7.     {
    8.         if (Input.GetMouseButtonDown(0))
    9.         {
    10.             if (EventSystem.current.IsPointerOverGameObject())
    11.             {
    12.                 return;
    13.             }
    14.             RaycastHit _hit;
    15.             if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out _hit, 1000))
    16.             {
    17.                 if (_hit.transform.gameObject.layer == 6)
    18.                 {
    19.                     Actions.OnClickGround(_hit.point);
    20.                 }
    21.             }
    22.         }
    23.     }
    24. }
    This is where the problem is. I've debugged it a bunch of different ways and everything is working fine except the "Actions.OnClickGround(_hit.point);" which just gives me a null error. For some reason it can't grab the Actions script and I'm not sure why. I've looked through a few tutorials and I have no idea what I am missing, any ideas? Why isn't this working?
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    It's grabbing the Actions code just fine. But did you actually set OnClickGround to do anything? Does it have a value? From what you have in your code, I'm not seeing anything set a value to it.
     
    Bunny83 likes this.
  3. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    I have set the action to do things on another script.

    Code (csharp):
    1. public class Player : NetworkBehaviour
    2. {
    3. private void OnEnable()
    4.     {
    5.         if (IsLocalPlayer)
    6.         {
    7.             Actions.OnClickGround += SetWalkDestServerRpc;
    8.             Actions.OnClickObject += SetTargDestServerRpc;
    9.         }
    10.     }
    11.     private void OnDisable()
    12.     {
    13.         if (IsLocalPlayer)
    14.         {
    15.             Actions.OnClickGround -= SetWalkDestServerRpc;
    16.             Actions.OnClickObject -= SetTargDestServerRpc;
    17.         }
    18.     }
    19.  
    20. [ServerRpc]
    21.     public void SetWalkDestServerRpc(Vector3 pos)
    22.     {
    23.         targetObj = null;
    24.         interactable = null;
    25.         res = null;
    26.         targ = null;
    27.         walkPos = pos;
    28.         conversation.StopConversation();
    29.         SwitchState(walkState);
    30.     }
    31. }
    the trouble is the error isn't happening on this script at all
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Did that code run before you attempted to use the delegate and found it was null?

    It's always the same three steps, regardless of what you are doing:

    How to fix a NullReferenceException error

    https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

    Three steps to success:
    - Identify what is null <-- any other action taken before this step is WASTED TIME
    - Identify why it is null
    - Fix that
     
  5. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    This action calling has never worked on this script, but I've done actions in this same manner before and it worked just fine. I am following the same process and tutorials, so it should be working the same right?

    I also can't find what is actually null. It seems there shouldn't be anything that is null, I'm calling a static class so there shouldn't be anything that is null.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Assuming it is in the line you posted, it cannot be _hit because that's a struct and structs cannot be null.

    Therefore it has to be the delegate (Action) that is null.

    Dunno where that assertion comes from... this stuff is pretty easy to test. Static things can be null all day long.

    Witness:

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. // drop this on a GameObject, press PLAY.. BOOM
    4.  
    5. public static class foo { public static System.Action act; }
    6.  
    7. public class WatchMeCrash : MonoBehaviour
    8. {
    9.     void Start ()
    10.     {
    11.         foo.act();  // BOOM!
    12.     }
    13. }
    If you expect it to be null, check it for null before trying to invoke it.
     
  7. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Yes, the _hit.point is not null, I can grab that easily enough.

    Sorry I meant the Action shouldn't be null, since I am always grabbing the Vector3 it should be able to be used so I don't get why it would be giving me a null error.

    I even tried just giving it a static Vector3, I just made the line:

    Code (csharp):
    1. Actions.OnClickGround(Vector3(0, 0, 0));
    This will still give me the null error. Not sure why.

    "NullReferenceException: Object reference not set to an instance of an object"
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    You're staring right at the thing that is null.

    Actions.OnClickGround
    is null.

    If you doubt me, compare it to null and print out "I AM NULL!"

    We also know that is NOT the code you ran because that is not valid C# code.

    Did you perhaps mean that you tried:

    Code (csharp):
    1. Actions.OnClickGround(new Vector3(0, 0, 0));
     
  9. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Haha I definitely don't doubt you. But I am not clear as to why it is null. I mean, when I have used Actions in the past I am doing the same process (I am pretty sure) so I am not sure why it wouldn't be working, or why it is null.

    As I understand it, calling the Actions.OnClickGround(Vector3) should be activating that action so any other script that is listening for that action should be able to be called.

    [Edit] I did mean to use "new Vector3(0,0,0)" in that hard coded example
     
    Last edited: Nov 27, 2022
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Dunno what to tell you. Actions CAN be null.

    If you declare one, static or instance, it will be null until you add at least one listener to it.

    I am pretty sure it will re-become null once you remove all listeners.

    Like I said, check it before you call it if you think it can be null.

    Otherwise, always initialize it with a single bogus dummy method, although I actually DO NOT recommend this.
     
  11. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Maybe that's the problem, that I don't have any listeners? Which would be weird, but that might be the problem. If there are no listeners, then calling the action would return null right?

    I will look there and see what is wrong.
     
  12. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,925
    If I'm using a static class for events I treat it like a broke and provide explicit methods to call the events:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public static class Actions
    5. {
    6.     public static event Action<Vector3> OnClickGround;
    7.     public static event Action<ulong> OnClickObject;
    8.    
    9.     public static void CallOnClickGround(Vector3 position) => OnClickGround?.Invoke(position);
    10.    
    11.     public static void CallOnClickObject(ulong value) => OnClickObject?.Invoke(value);
    12. }
    Notice I'm using the ?. operator which will only call
    Invoke()
    if the event isn't null (you could also guard the call and throw warnings if it is null).

    As Kurt noted above, delegates with no subscribers are null. You can clear all subscribers by assigning a delegate as null. So it's pretty clear, your delegates have no subscribers.
     
  13. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Yeah that was in fact the issue (Kurt knows all haha) so I think I need to add some of what you showed here to make beter Actions.
     
  14. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Looks like it was in fact the fact that I didn't have any listeners. Definitely did not know that would cause a null reference. But now that I know I can fix it! Thanks for working through it with me!
     
    Kurt-Dekker likes this.
  15. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Yep, what I was trying to tell you. Glad you got it worked out.