weird _unity_self null error...only present when i try to make a section of my code its own method

hi guys im currently messing around making a card game and im using a insertion sort on a array that holds a struct containing a transform, vector3’s and a int. if i keep my insertion sort in the main body of GameStart() i receive no errors but i wanted to extract it to its own method so i can re use it(currently im using random range to set the player order but in the event of the tie i would like to extract the tied players and then re generate a range so i can re insert them back into the original array in the correct tie broken order while maintaining the order of the first players).after i extract it to its own method then i get this error from unity

ArgumentNullException: Value cannot be null.
Parameter name: _unity_self
UnityEditor.SerializedObject.FindProperty (System.String propertyPath) (at <fd50159aad624335967647b443372e50>:0)
UnityEditor.UIElements.Bindings.SerializedObjectBindingContext.BindPropertyRelative (UnityEngine.UIElements.IBindable field, UnityEditor.SerializedProperty parentProperty) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEditor.UIElements.Bindings.SerializedObjectBindingContext.BindTree (UnityEngine.UIElements.VisualElement element, UnityEditor.SerializedProperty parentProperty) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEditor.UIElements.Bindings.SerializedObjectBindingContext.ContinueBinding (UnityEngine.UIElements.VisualElement element, UnityEditor.SerializedProperty parentProperty) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEditor.UIElements.Bindings.DefaultSerializedObjectBindingImplementation+BindingRequest.Bind (UnityEngine.UIElements.VisualElement element) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEngine.UIElements.VisualTreeBindingsUpdater.Update () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.VisualTreeUpdater.UpdateVisualTreePhase (UnityEngine.UIElements.VisualTreeUpdatePhase phase) (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.Panel.UpdateBindings () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.UpdateSchedulers () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.UIEventRegistration.UpdateSchedulers () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEditor.RetainedMode.UpdateSchedulers () (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)

i cant see the unity messages in side of visual studio while the debugger is attached and while debugger is attached it seems to run through my entire code correctly so im not sure where the error is coming from
my array is being sorted correctly weather my function is extracted or in the main body so im not sure where the _unity_self null reference is coming from as it doesnt actually let me double click it or give me the line number that its happening at either
i have attached my entire code GameStart() is initally called on line 45 at the end of start and the actual GameStart() funtion is on line 183 the shuffling function and its companion function take up alot of lines of code(i didnt want sudo random and was playing with arrays) also attached a zipfile of the entire project if that may be better to look at… code below

using System;
using System.Collections;
using System.Linq;
using UnityEngine;


public class DeckHandler : MonoBehaviour
{
    public GameObject discardPile;
    public Dealer dealerScript;
    public Sprite[] sprites;
    private Sprite[] cards;
    private int cardIndex = 0;
    private CardSprites cardSprites;
    private bool swap = false;
    public int shuffleCount;
    private int _shuffleCount;
    // Start is called before the first frame update
    void Start()
    {
        _shuffleCount = shuffleCount;
        cards = new Sprite[sprites.Length - 1];
        if (PlayerPrefs.HasKey("Has_deck"))
        {
            if (PlayerPrefs.GetInt("Has_deck") == 1)
            {
                Debug.Log("deck exists");
                string cardsArray = PlayerPrefs.GetString("shuffled_deck");//get the deck from playerprefs
                cardSprites = JsonUtility.FromJson<CardSprites>(cardsArray);
                for (int i = 0; i < cards.Length; i++)
                {
                    cards[i] = cardSprites.deckEntrys[i].cardSprite;
                    //Debug.Log("cards[" + i + "] = " + cards[i]);
                }
                cardSprites = null;
            }
        }
        else // create a new deck and shuffle it.
        {
            Array.Copy(sprites, 1, cards, 0, cards.Length);
            shuffle(cards);
            PlayerPrefs.SetInt("Has_deck", 1);
            cardSprites = null;
        }
        gameStart();
    }

    // Update is called once per frame
    void Update()
    {

    }

    void shuffle(Sprite[] cards)
    {
        if (_shuffleCount <= 0)
        {   //fully shuffled reset shoffle count to default and return
            //_shuffleCount = shuffleCount;
            SaveDeck();
            return;
        }
        int half = cards.Length / 2;
        Sprite[] tempSprites = new Sprite[cards.Length];
        Sprite[] spriteArrA = new Sprite[half];
        Sprite[] spriteArrB = new Sprite[half];
        Array.Copy(cards, spriteArrA, half);
        Array.Copy(cards, half, spriteArrB, 0, half);

        for (int a = 0, b = 0, i = 0; i < tempSprites.Length; i++)
        {
            shuffler(spriteArrA, spriteArrB, tempSprites, ref i, ref a, ref b, ref swap);//ref is c# version of a pointer
        }
        Array.Copy(tempSprites, cards, cards.Length);
        // take the new Array that has been shuffled once and split it into 6
        int sixth = cards.Length / 6;
        spriteArrA = new Sprite[sixth];
        spriteArrB = new Sprite[sixth];
        Sprite[] spriteArrC = new Sprite[sixth];
        Sprite[] spriteArrD = new Sprite[sixth];
        Sprite[] spriteArrE = new Sprite[sixth];
        Sprite[] spriteArrF = new Sprite[sixth];
        Array.Copy(cards, spriteArrA, sixth);
        Array.Copy(cards, sixth, spriteArrB, 0, sixth);
        Array.Copy(cards, sixth * 2, spriteArrC, 0, sixth);
        Array.Copy(cards, sixth * 3, spriteArrD, 0, sixth);
        Array.Copy(cards, sixth * 4, spriteArrE, 0, sixth);
        Array.Copy(cards, sixth * 5, spriteArrF, 0, sixth);
        //shuffle thoes 6 into 3
        int third = cards.Length / 3;
        Sprite[] spriteArrG = new Sprite[third];//a>d
        Sprite[] spriteArrH = new Sprite[third];//c>f
        Sprite[] spriteArrI = new Sprite[third];//b>e
        for (int count = 0, a = 0, b = 0, i = 0; i < third; i++)
        {
            if (count == 0)
            {
                shuffler(spriteArrA, spriteArrD, spriteArrG, ref i, ref a, ref b, ref swap);
                if (i == third - 1)
                {
                    a = 0;
                    b = 0;
                    i = -1;//-1 because loop will incriment it to 1 if set at 0
                    count++;
                }
            }
            else if (count == 1)
            {
                shuffler(spriteArrC, spriteArrF, spriteArrH, ref i, ref a, ref b, ref swap);
                if (i == third - 1)
                {
                    a = 0;
                    b = 0;
                    i = -1;
                    count++;
                }
            }
            else
            {
                shuffler(spriteArrB, spriteArrE, spriteArrI, ref i, ref a, ref b, ref swap);
            }
        }
        //shuffel two thirds into each other
        int twoThirds = third * 2;
        Sprite[] spriteArrJ = new Sprite[twoThirds];
        for (int i = 0, a = 0, b = 0; i < twoThirds; i++)
        {
            shuffler(spriteArrG, spriteArrH, spriteArrJ, ref i, ref a, ref b, ref swap);
        }
        //copy back into origonal Arrays
        Array.Copy(spriteArrJ, spriteArrG, third);
        Array.Copy(spriteArrJ, third, spriteArrH, 0, third);
        //reshuffel shuffeled Array into non-shuffled(semi shuffeled?) Array
        for (int i = 0, a = 0, b = 0; i < twoThirds; i++)
        {
            shuffler(spriteArrH, spriteArrI, spriteArrJ, ref i, ref a, ref b, ref swap);
        }
        Array.Copy(spriteArrJ, spriteArrH, third);
        Array.Copy(spriteArrJ, third, spriteArrI, 0, third);
        tempSprites = spriteArrG.Concat(spriteArrH).Concat(spriteArrI).ToArray();//join shuffled Arrays back together
        //cut the deck b over a
        spriteArrA = new Sprite[half];
        spriteArrB = new Sprite[half];
        Array.Copy(tempSprites, spriteArrA, half);
        Array.Copy(tempSprites, half, spriteArrB, 0, half);
        tempSprites = spriteArrB.Concat(spriteArrA).ToArray();
        Array.Copy(tempSprites, cards, cards.Length);
        // use recursion to reshuffle shuffled Array
        _shuffleCount--;
        shuffle(cards);
    }
    void shuffler(Sprite[] sourceA, Sprite[] sourceB, Sprite[] destination, ref int i, ref int a, ref int b, ref bool swap)
    {
        if (!swap)
        {
            //add spritesArrA to Sprites[0]
            destination[i] = sourceA[a];
            a++;
            swap = true;
        }
        else
        {
            //add spritesArrB to Sprites[1]
            destination[i] = sourceB[b];
            b++;
            swap = false;
        }

    }

    [System.Serializable]
    private struct Players
    {
        public Transform playerTransform;
        public Vector3[] hand;
        public int order;
    };
    [SerializeField] private Players[] players;
    private GameObject playersContainer;
    private int maxPlayers = 6;
    private int playerCount;
    private int handCount;
    private float offset;
    void gameStart()
    {
        //get the player container
        playersContainer = GameObject.FindWithTag("Players");
        //count the active children
        for (int i = 0; i < maxPlayers; i++)
        {
            if (playersContainer.transform.GetChild(i).gameObject.activeSelf)
            {
                playerCount++;
            }
        }
        //initiate player array
        players = new Players[playerCount];
        //calculate starting card count and first card offset
        if (playerCount < 3)
        {
            handCount = 9;
            offset = -4.0f * .8f;
        }
        else if (playerCount >= 3 && playerCount <= 5)
        {
            handCount = 7;
            offset = -3.0f * .8f;
        }
        else
        {
            handCount = 5;
            offset = -2.0f * .8f;
        }
        for (int i = 0; i < playerCount; i++)
        {
            players[i].hand = new Vector3[handCount];
        }
        //populate player array
        for (int i = 0; i < playerCount; i++)
        {
            players[i].order = UnityEngine.Random.Range(0, 21);
            string currentPlayer = "Player" + (i + 1).ToString();
            players[i].playerTransform = playersContainer.transform.Find(currentPlayer);
            //Debug.Log(currentPlayer + "position = " + players[i].playerTransform.position);
            float _offset = offset;
            for (int j = 0; j < handCount; j++)
            {
                Vector3 playerVector = GetVector(i, _offset);
                players[i].hand[j] = new Vector3(playerVector.x, playerVector.y, playerVector.z);
                _offset += .8f;
            }
        }
        //sort array
        SortArray(players);
        /*
        for (int i = 1; i < playerCount; i++)
        {
            Players currentPlayer = players[i];//get current player
            int previousElement = i - 1;//calculate previous elements position in array
            int currentValue = players[i].order;//get current elements value
            int previousValue = players[previousElement].order;//get previous elements value
            while (previousElement >= 0 && previousValue > currentValue)//while we are not less the first element and the
                                                                        //previous value is greater then the current value
            {
                players[previousElement + 1] = players[previousElement];//set the next element to the previous element
                previousElement--;//note new position of previous element
                if (previousElement >= 0)
                {
                    previousValue = players[previousElement].order;
                }
            }
            players[previousElement + 1] = currentPlayer;//set the next element to the current element
        }
        */
        //deal starting hand to each player
        for (int i = 0; i < playerCount; i++)
        {
            for (int j = 0; j < handCount; j++)
            {
                dealerScript.dealCard(players[i].hand[j], cards[cardIndex], players[i].playerTransform);
                cardIndex++;
            }
        }
        //deal first card
        Vector3 discardPosition = discardPile.transform.position;
        dealerScript.dealCard(discardPosition, cards[cardIndex], discardPile.transform);
        cardIndex++;
    }
    Vector3 GetVector(int i, float _offset)
    {
        Vector3 calculatedVector;
        if (players[i].playerTransform.position.y < 0)
        {
            calculatedVector = players[i].playerTransform.position + (Vector3.right * _offset);
        }
        else
        {
            calculatedVector = players[i].playerTransform.position + (Vector3.left * _offset);
        }
        return calculatedVector;
    }
    void SortArray(Players[] array)
    {
        //sort player array using a insertion sort algorithm https://www.geeksforgeeks.org/insertion-sort/
        for (int i = 1; i < array.Length; i++)
        {
            Players currentPlayer = array[i];//get current player
            int previousElement = i - 1;//calculate previous elements position in array
            int currentValue = array[i].order;//get current elements value
            int previousValue = array[previousElement].order;//get previous elements value
            while (previousElement >= 0 && previousValue > currentValue)//while we are not less the first element and the
                                                                        //previous value is greater then the current value
            {
                array[previousElement + 1] = array[previousElement];//set the next element to the previous element
                previousElement--;//note new position of previous element
                if (previousElement >= 0)
                {
                    previousValue = array[previousElement].order;
                }
            }
            array[previousElement + 1] = currentPlayer;//set the next element to the current element
        }
        return;
        /*
        void sort(int[] arr)
        {
            int n = arr.Length;
            for (int i = 1; i < n; ++i)
            {
                int key = arr[i];
                int j = i - 1;

                // Move elements of arr[0..i-1],
                // that are greater than key,
                // to one position ahead of
                // their current position
                while (j >= 0 && arr[j] > key)
                {
                    arr[j + 1] = arr[j];
                    j = j - 1;
                }
                arr[j + 1] = key;
            }
        }
        */
    }
    void SaveDeck()
    {
        cardSprites = new CardSprites(cards);//populate class to save to json
        string jsonString = JsonUtility.ToJson(cardSprites);
        cardSprites = null;//release memory
        Debug.Log("json string = " + jsonString);
        PlayerPrefs.SetString("shuffled_deck", jsonString);
        PlayerPrefs.Save();
    }
    [System.Serializable]
    public class DeckEntry
    {
        public Sprite cardSprite;
        public string cardName;
    }
    [System.Serializable]
    public class CardSprites
    {
        public DeckEntry[] deckEntrys;
        public CardSprites(Sprite[] cards)
        {
            deckEntrys = new DeckEntry[cards.Length];

            for (int i = 0; i < cards.Length; i++)
            {
                deckEntrys[i] = new DeckEntry
                {
                    cardSprite = cards[i],
                    cardName = cards[i].name
                };
                Debug.Log("added");
            }
        }

    }

}

8983630–1236337–Scramble(card game).7z (726 KB)

From the callstack it looks like errors in the UIElements stuff.

I’m not sure that’s even out of experimental yet, as there’s a warning not to use it for production stuff.

I would stick with UGUI.

Except there’s nothing in the script that uses UI Elements, so it’s most likely an issue on Unity’s side.

What Unity version are you on OP?

Also UI Elements is well out of experimental. Pretty much all of the Editor UI in 2021+ is using it now.

[quote=Kurt-Dekker, post: 8983672, member: 225647]
I’m not sure that’s even out of experimental yet, as there’s a warning not to use it for production stuff.
[/quote]
Runtime UI Toolkit has been out for some time. It’s not on par with uGUI yet.
There’s a bit of a mixed message out there whether it is production ready. Though it was released for runtime.
I can’t remember whether it was 2021.2 or 2021.3 or later.

Though since this has to do with bindings, it seems editor related.
UI Toolkit for runtime doesn’t have any binding system yet.

I’ve taken a quick look into the project
There’s a lot to say about the DeckHandler script.

Try updating Unity to 2022.2.17 (since you’re using 2022.2.16 that shouldn’t be any trouble)
You could try deleting the library folder and have Unity rebuild it.

Edit: After re-opening the project, it does give errors.
But those are related to the sprites… that may be related to the “there’s a lot to say about the DeckHandler script.
Sprites (or UnityEngine.Object) cannot be serialized to json.
Which may or may not be related to your issue.

you could try clearing your playerprefs data using PlayerPrefs.DeleteAll()

It’s a lot to debug and it’s late for me.

is there a way to change which ui version im using?

22.2.16 i was having a issue in 21.3.4f1 where my array element 0 in the inspector was squished and unreadable and couldnt figure out how to fix it but saw the issue was fixed in the 22 versions

ill try deleting the library file although it wasn’t in the zip. when im saving the into json my struct deck entry seems to serialize the instance id of the sprite and does rebuild the array correctly.

if i uncomment the for loop below the call to the sort function and then comment the SortArray() funtion out then unity will give no errors its only when i separate it out. i tried to pass a ref Players[ ] players to it thinking maby its a copy issue but that didn’t work either

This was also fixed in the recent 2021 releases. So you should’ve just updated 2021 versions, rather than leaving the LTS version.

actually just checked it wont create any errors when the sort function and loop are commented/uncommented in/out and no objects are selected in the editor. the errors will only pop up when i click on the deckhandler object(which holds the players struct and the SerializedFeild of the actual array. if i remove the [SerializedFeild] from the array then the errors all dissapear…i agree theres alot in my deckhandler script i think im gonna work on rebuilding it either by using namespaces and the event system or just using the script components as its doing to many things currently… i may have found a serialization bug perhaps?

unity hub doesn’t show me a new version then 2021.3.4f1 ill double check again to make sure

Latest Unity 2021 version is 2021.3.24: https://unity.com/releases/editor/whats-new/2021.3.24

weird it wasnt showing in my hub but i got it from the link you provided installing now thanks

1 Like

it looked like it was gonna fully reinstall unity so i did a full uninstall restart and reinstall no issues in 21.3.24 and it was actually shown in hub so maby my system was corrupt but no issues with _unity_self after reinstall