public void SetBlock_GetBlock()
        {
            // Arrange
            var blockType1 = new Mock <IMeshBlockDetails>();
            var blockType2 = new Mock <IMeshBlockDetails>();
            var blockType3 = new Mock <IMeshBlockDetails>();
            var blockPos1  = new BlockPosition(1, 1, 4);
            var blockPos2  = new BlockPosition(2, 2, 3);
            var blockPos3  = new BlockPosition(3, 3, 2);
            var blockPos4  = new BlockPosition(4, 4, 1);

            var chunkSize = new GridSize(3);
            var chunkPos  = new ChunkPosition(1, 3, 6);
            var props     = new ChunkProperties();

            // Act
            props.Reset(chunkPos, chunkSize);
            props.SetBlock(blockPos1, blockType1.Object);
            props.SetBlock(blockPos2, blockType2.Object);
            props.SetBlock(blockPos3, blockType3.Object);

            // Assert
            Assert.AreEqual(blockType1.Object, props.GetBlock(blockPos1));
            Assert.AreEqual(blockType2.Object, props.GetBlock(blockPos2));
            Assert.AreEqual(blockType3.Object, props.GetBlock(blockPos3));
            Assert.AreEqual(null, props.GetBlock(blockPos4));
        }
        /// <summary>
        /// Generates the visual remeshing tasks, as needed.
        /// </summary>
        /// <param name="properties">The chunk properties.</param>
        /// <param name="tasks">The task list to add to.</param>
        private void GenerateVisuals(ChunkProperties properties, RemeshTaskStack taskStack)
        {
            List <int> materials = new List <int>();

            foreach (var pos in BlockIterator(properties.ChunkSize.Value))
            {
                var type = properties.GetBlock(pos);

                if (!type.IsVisible)
                {
                    continue;
                }

                for (int j = 0; j < 6; j++)
                {
                    var material = type.GetMaterialID(j);
                    if (materials.Contains(material))
                    {
                        continue;
                    }

                    materials.Add(material);
                    taskStack.AddTask(new VisualRemeshTask(properties, material));
                }
            }
        }
        /// <inheritdoc cref="VoxelChunkMesher"/>
        public override bool CanPlaceQuad(ChunkProperties chunkProperties, BlockPosition pos, int side)
        {
            var block = chunkProperties.GetBlock(pos);

            if (!block.IsSolid)
            {
                return(false);
            }

            var nextPos = pos;

            nextPos = nextPos.ShiftAlongDirection(side);
            if (!nextPos.IsWithinGrid(chunkProperties.ChunkSize))
            {
                return(true);
            }

            var next = chunkProperties.GetBlock(nextPos);

            return(!next.IsSolid);
        }
        /// <summary>
        /// Generates the collision remesh task, as needed.
        /// </summary>
        /// <param name="properties">The chunk properties.</param>
        /// <param name="tasks">The task list to add to.</param>
        private void GenerateCollision(ChunkProperties properties, RemeshTaskStack taskStack)
        {
            foreach (var pos in BlockIterator(properties.ChunkSize.Value))
            {
                var type = properties.GetBlock(pos);

                if (type.IsSolid)
                {
                    taskStack.AddTask(new CollisionRemeshTask(properties));
                    return;
                }
            }
        }
        public void SetBlock_ResetChunk_GetBlock_ReturnsNull()
        {
            // Arrange
            var blockType = new Mock <IMeshBlockDetails>();
            var blockPos  = new BlockPosition(1, 1, 4);

            var chunkSize = new GridSize(3);
            var chunkPos1 = new ChunkPosition(1, 3, 6);
            var chunkPos2 = new ChunkPosition(17, -123, 12999);
            var props     = new ChunkProperties();

            // Act
            props.Reset(chunkPos1, chunkSize);
            props.SetBlock(blockPos, blockType.Object);
            props.Reset(chunkPos2, chunkSize);

            // Assert
            Assert.AreEqual(null, props.GetBlock(blockPos));
        }
        /// <summary>
        /// Iterates over all the blocks in a chunk and generates quads as needed, finally
        /// remeshing them into the output mesh when complete.
        /// </summary>
        void Remesh()
        {
            int chunkSize = m_ChunkProperties.ChunkSize.Value;

            for (int j = 0; j < 6; j++)
            {
                for (int t = 0; t < chunkSize; t++)
                {
                    bool planeActive = false;
                    for (int a = 0; a < chunkSize; a++)
                    {
                        for (int b = 0; b < chunkSize; b++)
                        {
                            var pos = GetAsBlockCoords(j, t, a, b);

                            if (!CanPlaceQuad(m_ChunkProperties, pos, j))
                            {
                                continue;
                            }

                            var type     = m_ChunkProperties.GetBlock(pos);
                            var texture  = type.GetTextureID(j);
                            var rotation = SolveRotation(pos, type.GetRotation(j));
                            var quad     = new GreedyMesher.Quad(rotation, texture);

                            m_GreedyMesher.SetQuad(a, b, quad);
                            planeActive = true;
                        }
                    }

                    if (planeActive)
                    {
                        m_GreedyMesher.Mesh(t, j, m_Mesh);
                    }
                }
            }

            if (m_WieldVertices)
            {
                m_Mesh.WieldVertices();
            }
        }