public bool SetBlockType(int worldX, int y, int worldZ, BlockType value, byte state = 0, bool lightBlocks = true, bool tickBlocks = true, bool updateNeighborSections = true)
        {
            if (y >= WorldHeight || y < 0)
            {
                return(false);
            }

            int localX = worldX - PositionX;
            int localZ = worldZ - PositionZ;

            if (!m_Data.SetBlockType(localX, y, localZ, value, out BlockType previousBlockType))
            {
                return(false);
            }

            m_Data.SetBlockState(localX, y, localZ, state);
            UpdateHeightMapAndSkyLight(localX, y, localZ);


            WorldManager world       = WorldManager.Active;
            ChunkManager manager     = world.ChunkManager;
            DataManager  dataManager = world.DataManager;

            Block previousBlock = dataManager.GetBlockByType(previousBlockType);
            Block block         = dataManager.GetBlockByType(value);

            int sectionIndex = Mathf.FloorToInt(y * OverSectionHeight);
            int yInSection   = y - sectionIndex * SectionHeight;

            if (previousBlock.HasAnyFlag(BlockFlags.NeedsRandomTick))
            {
                m_Data.DecreaseTickRefCount(sectionIndex);
            }

            if (block.HasAnyFlag(BlockFlags.NeedsRandomTick))
            {
                m_Data.IncreaseTickRefCount(sectionIndex);
            }

            if (previousBlock.VertexType != BlockVertexType.None)
            {
                if (previousBlock.HasAnyFlag(BlockFlags.Liquid))
                {
                    m_Data.DecreaseRenderableLiquidCount(sectionIndex);
                }
                else
                {
                    m_Data.DecreaseRenderableSolidCount(sectionIndex);
                }
            }

            if (block.VertexType != BlockVertexType.None)
            {
                if (block.HasAnyFlag(BlockFlags.Liquid))
                {
                    m_Data.IncreaseRenderableLiquidCount(sectionIndex);
                }
                else
                {
                    m_Data.IncreaseRenderableSolidCount(sectionIndex);
                }
            }

            SetMeshDirty(sectionIndex, GetDirtyFlags(previousBlock, block));

            if (lightBlocks)
            {
                manager.LightBlock(worldX, y, worldZ);
            }

            if (tickBlocks)
            {
                manager.TickBlock(worldX, y, worldZ);
            }

            if (updateNeighborSections)
            {
                if (localX == 0)
                {
                    Chunk chunk = manager.GetChunk(PositionX - ChunkWidth, PositionZ);
                    chunk?.SetMeshDirty(sectionIndex, MeshDirtyFlags.Both);
                }
                else if (localX == ChunkWidth - 1)
                {
                    Chunk chunk = manager.GetChunk(PositionX + ChunkWidth, PositionZ);
                    chunk?.SetMeshDirty(sectionIndex, MeshDirtyFlags.Both);
                }

                if (yInSection == 0 && sectionIndex > 0)
                {
                    SetMeshDirty(sectionIndex - 1, MeshDirtyFlags.Both);
                }
                else if (yInSection == SectionHeight - 1 && sectionIndex < SectionCountInChunk - 1)
                {
                    SetMeshDirty(sectionIndex + 1, MeshDirtyFlags.Both);
                }

                if (localZ == 0)
                {
                    Chunk chunk = manager.GetChunk(PositionX, PositionZ - ChunkWidth);
                    chunk?.SetMeshDirty(sectionIndex, MeshDirtyFlags.Both);
                }
                else if (localZ == ChunkWidth - 1)
                {
                    Chunk chunk = manager.GetChunk(PositionX, PositionZ + ChunkWidth);
                    chunk?.SetMeshDirty(sectionIndex, MeshDirtyFlags.Both);
                }
            }

            return(m_IsModified = true);
        }