void RecurseInteractions(int cubeId)
    {
        if (visited.Contains(cubeId))
        {
            Assert.IsTrue(cubes[cubeId].GetComponent <NetworkInfo>().GetAuthorityIndex() == authorityIndex);
            return;
        }

        visited.Add(cubeId);

        Interactions.Entry entry = interactions.GetInteractions(cubeId);

        for (int i = 0; i < Constants.NumCubes; ++i)
        {
            if (entry.interactions[i] == 0)
            {
                continue;
            }

            var networkInfo = cubes[i].GetComponent <NetworkInfo>();
            if (networkInfo.GetAuthorityIndex() != 0)
            {
                continue;
            }

            TakeAuthorityOverObject(networkInfo);

            RecurseInteractions(i);
        }
    }
    public void RecurseSupportObjects(GameObject gameObject, ref HashSet <GameObject> support)
    {
        if (support.Contains(gameObject))
        {
            return;
        }

        support.Add(gameObject);

        NetworkInfo networkInfo = gameObject.GetComponent <NetworkInfo>();

        int cubeId = networkInfo.GetCubeId();

        Interactions.Entry entry = interactions.GetInteractions(cubeId);

        for (int i = 0; i < Constants.NumCubes; ++i)
        {
            if (entry.interactions[i] == 0)
            {
                continue;
            }

            if (cubes[i].layer != layer)
            {
                continue;
            }

            if (cubes[i].transform.position.y < gameObject.transform.position.y + Constants.SupportHeightThreshold)
            {
                continue;
            }

            RecurseSupportObjects(cubes[i], ref support);
        }
    }