public void BrowseLayer(bool next)
    {
        Undo.RecordObjects(new Object[] { this, m_blockMap }, "Changed Cell Layer");
        Vector3 vCell = this.CurrentCell;

        vCell.z = vCell.z + (next ? CellSize : -CellSize);
        vCell.z = CellOffset.z + Mathf.Round((vCell.z - CellOffset.z) / CellSize) * CellSize;

        UpdateCurrentCell(vCell.z);

        // try to load previous set cell offset for current  z layer of current cell
        GNBlockMapLayer targetLayer = GetCurrentTargetLayer(true);

        if (targetLayer.HasStoredCellOffset(CellSize))
        {
            // Debug.Log("Loaded CellOffset");
            CellOffset = targetLayer.GetStoredCellOffset(CellSize);
        }
        else
        {
            targetLayer.SetStoredCellOffest(CellSize, CellOffset);
        }

        // UpdateCurrentCell(vCell.z);
    }
    private GameObject GetGameObjectAt(Vector3 cell)
    {
        GNBlockMapLayer currentLayer = cell.z == CurrentCell.z ? GetCurrentTargetLayer() : GetTargetLayer(cell.z);

        if (currentLayer == null)
        {
            return(null);
        }
        Transform transform    = currentLayer.transform;
        int       iNumChildren = transform.childCount;

        for (int i = 0; i < iNumChildren; i++)
        {
            Transform childTransform = transform.GetChild(i);
            Vector3   pos            = childTransform.position;
            if (IsMultipleCellBlock(childTransform.gameObject))
            {
                pos -= GetOffsetFor(childTransform.gameObject);
            }
            if (Vector3.Distance(pos, cell) < MIN_GRID_RESOLTION)
            {
                return(childTransform.gameObject);
            }
        }
        return(null);
    }
    public void UndoRedoPerformed()
    {
        if (OnPrefabChanged != null)
        {
            OnPrefabChanged();
        }
        if (OnCellZChanged != null)
        {
            OnCellZChanged();
        }
        if (OnCellXYChanged != null)
        {
            OnCellXYChanged();
        }
        if (OnGridChanged != null)
        {
            OnGridChanged();
        }
        if (OnToolChanged != null)
        {
            OnToolChanged();
        }

        m_currentTargetLayer = null;
        if (m_blockMap != null)
        {
            UpdateVisibleLayers();
            UpdateCurrentCell();
        }
    }
    private GNBlockMapLayer GetCurrentTargetLayer(bool create = true)
    {
        if (m_currentTargetLayer)
        {
            return(m_currentTargetLayer);
        }
        float zLayer = CurrentCell.z;

        m_currentTargetLayer = GetTargetLayer(zLayer, create);
        return(m_currentTargetLayer);
    }
    private bool MoveToCorrectTargetLayer(GameObject gameObject)
    {
        GNBlockMapLayer targetLayer = GetTargetLayer(GetTargetZPosition(gameObject), true);

        if (targetLayer.transform != gameObject.transform.parent)
        {
            Debug.LogWarning("Moving GameObject" + gameObject + " from layer + " + gameObject.transform.parent.name + " to layer " + targetLayer.name + " (Tile Info : " + GetTileInfo(gameObject) + " )");

            Undo.RecordObject(gameObject, "Moved to correct target layer");
            EditorUtility.SetDirty(gameObject);
            gameObject.transform.parent = targetLayer.transform;
            return(true);
        }
        return(false);
    }
    private void UpdateVisibleLayers(bool _enableAll = false)
    {
        GNBlockMapLayer targetLayer       = GetCurrentTargetLayer(false);
        float           currentZPosition  = CurrentCell.z + CellOffset.z; //float.Parse(targetLayer.name);
        Transform       blockMapTransform = m_blockMap.transform;
        int             iNumChildren      = blockMapTransform.childCount;

        for (int i = 0; i < iNumChildren; i++)
        {
            Transform childTransform = blockMapTransform.GetChild(i);

            if (childTransform.gameObject.name == "_brush")
            {
                continue;
            }

            float zPosition;
            try
            {
                zPosition = float.Parse(childTransform.gameObject.name);
            }
            catch (System.Exception)
            {
                Debug.LogWarning("Could not parse zPosition for layer: " + childTransform.gameObject.name);
                continue;
            }

            if ((targetLayer != null && childTransform.gameObject == targetLayer.gameObject) ||
                _enableAll ||
                CurrentShowLayerMode == ShowLayerMode.ALL ||
                (CurrentShowLayerMode == ShowLayerMode.BELOW && zPosition > currentZPosition)
                )
            {
                childTransform.gameObject.SetActive(true);
            }
            else
            {
                childTransform.gameObject.SetActive(false);
            }
        }
    }
    private void RemoveEmptyLayers()
    {
        Transform blockMapTransform = m_blockMap.transform;

        // Debug.Log("zLayer " + CurrentCell.z + " " + CellOffset.z);

        for (int i = 0; i < blockMapTransform.childCount;)
        {
            Transform       childTransform = blockMapTransform.GetChild(i);
            GNBlockMapLayer blockMapLayer  = childTransform.GetComponent <GNBlockMapLayer>();
            if (blockMapLayer && childTransform.childCount == 0)
            {
                DestroyImmediate(childTransform.gameObject);
                EditorUtility.SetDirty(m_blockMap);
            }
            else
            {
                i++;
            }
        }
    }
    public bool ChangeCellSize(float _fNewValue)
    {
        if (m_blockMap.m_fCellSize != _fNewValue)
        {
            m_blockMap.m_fCellSize = _fNewValue;

            Vector3 cellOffset = new Vector3(
                m_blockMap.m_fCellSize / 2f - 1.0f,
                m_blockMap.m_fCellSize / 2f - 1.0f,
                m_blockMap.m_fCellSize / 2f - 1.0f
                );
            m_blockMap.m_vCellOffset = cellOffset;

            // first, try to get a new Z layer using the default offset
            float newZ = CellOffset.z + Mathf.Round((m_blockMap.m_currentCell.z - CellOffset.z) / CellSize) * CellSize;
            UpdateCurrentCell(newZ);
            newZ = CurrentCell.z;

            // now try to load and apply previous set cell offset for current Z-Layer and CellSize
            GNBlockMapLayer targetLayer = GetTargetLayer(newZ, true);
            if (targetLayer.HasStoredCellOffset(_fNewValue))
            {
                m_blockMap.m_vCellOffset = targetLayer.GetStoredCellOffset(_fNewValue);
                // Debug.Log("Loaded CellOffset");
            }
            else
            {
                m_blockMap.m_vCellOffset = cellOffset;
                targetLayer.SetStoredCellOffest(_fNewValue, cellOffset);
            }

            OnGridChanged();
            UpdateCurrentCell(newZ);

            return(true);
        }
        return(false);
    }
    private GNBlockMapLayer GetTargetLayer(float zLayer, bool create = true)
    {
        Transform blockMapTransform = m_blockMap.transform;
        int       iNumChildren      = blockMapTransform.childCount;
        string    strLayerName      = zLayer.ToString("00.000");

        // Debug.Log("zLayer " + CurrentCell.z + " " + CellOffset.z);

        for (int i = 0; i < iNumChildren; i++)
        {
            Transform childTransform = blockMapTransform.GetChild(i);
            if (childTransform.gameObject.name == strLayerName)
            {
                GNBlockMapLayer blockMapLayer = childTransform.GetComponent <GNBlockMapLayer>();
                if (!blockMapLayer)
                {
                    blockMapLayer = childTransform.gameObject.AddComponent <GNBlockMapLayer>();
                    EditorUtility.SetDirty(blockMapLayer);
                }

                return(blockMapLayer);
            }
        }

        if (create)
        {
            GameObject createdGameObject = new GameObject();
            createdGameObject.transform.position = new Vector3(0, 0, zLayer);
            createdGameObject.transform.parent   = m_blockMap.transform;
            createdGameObject.name = strLayerName;
            GNBlockMapLayer blockMapLayer = createdGameObject.AddComponent <GNBlockMapLayer>();
            EditorUtility.SetDirty(createdGameObject);
            // Undo.RegisterCreatedObjectUndo(createdGameObject, "Created a new TargetLayer");
            return(blockMapLayer);
        }

        return(null);
    }
    private bool FixObject(GameObject gameObject)
    {
        GNBlockMapTile tile = gameObject.GetComponent <GNBlockMapTile>();

        if (tile != null)
        {
            float           z           = GetTargetZPosition(gameObject);
            GNBlockMapLayer targetLayer = GetTargetLayer(z, false);
            if (targetLayer == null || targetLayer.transform != gameObject.transform.parent)
            {
                Undo.RecordObject(gameObject.transform, "fix position");
                tile.transform.position += tile.Offset;
                Debug.LogWarning(" Moving old collision tile to correct position " + tile.transform.position);
            }

            UnityEngine.Assertions.Assert.AreEqual(tile.transform.parent.GetComponent <GNBlockMapLayer>(), GetTargetLayer(GetTargetZPosition(gameObject), false));
            return(false);
        }

        if (gameObject.isStatic && gameObject.GetComponent <NPVoxCubeSimplifierInstance>() != null)
        {
            // if(gameObject)
            // TODO: check for negative scale and revert them?!?

            Vector3 scle = gameObject.transform.localScale;
            if (scle.x < 0)
            {
                Undo.RecordObject(gameObject.transform, "fix scale");
                scle.Scale(new Vector3(-1, 1, 1));
                Debug.LogWarning(" Removing negative scale from object at position " + gameObject.transform.position);
                gameObject.transform.localScale = scle;
            }
            if (scle.y < 0)
            {
                Undo.RecordObject(gameObject.transform, "fix scale");
                scle.Scale(new Vector3(1, -1, 1));
                Debug.LogWarning(" Removing negative scale from object at position " + gameObject.transform.position);
                gameObject.transform.localScale = scle;
            }
            if (scle.z < 0)
            {
                Undo.RecordObject(gameObject.transform, "fix scale");
                scle.Scale(new Vector3(1, 1, -1));
                Debug.LogWarning(" Removing negative scale from object at position " + gameObject.transform.position);
                gameObject.transform.localScale = scle;
            }
        }

        // Vector3 pos = Align(gameObject.transform.position);
        //  new Vector3(
        //      Mathf.Round(gameObject.transform.localPosition.x / MIN_GRID_RESOLTION) * MIN_GRID_RESOLTION,
        //      Mathf.Round(gameObject.transform.localPosition.y / MIN_GRID_RESOLTION) * MIN_GRID_RESOLTION,
        //      Mathf.Round(gameObject.transform.localPosition.z / MIN_GRID_RESOLTION) * MIN_GRID_RESOLTION
        // );

        // if(gameObject.transform.position.x != pos.x || gameObject.transform.position.y != pos.y || gameObject.transform.position.z != pos.z)
        // {
        //     Debug.LogWarning(" Aligning object to position " + pos);
        //     gameObject.transform.position = pos;
        // }

        return(MoveToCorrectTargetLayer(gameObject));
        // return false;
    }