예제 #1
0
        public void SetBlocks(int fromX, int fromY, int fromZ, int toX, int toY, int toZ, Block block)
        {
            VoxLogger.Log("VoxelWorld : SetBlocks " + block);

            FixValues(ref fromX, ref toX);
            FixValues(ref fromY, ref toY);
            FixValues(ref fromZ, ref toZ);

            int3 chunkFrom = Helpers.ContainingChunkPosition(fromX, fromY, fromZ);
            int3 chunkTo   = Helpers.ContainingChunkPosition(toX, toY, toZ);

            int minY = Helpers.Mod(fromY, Chunk.CHUNK_SIZE);

            for (int cy = chunkFrom.y; cy <= chunkTo.y; cy += Chunk.CHUNK_SIZE, minY = 0)
            {
                int maxY = math.min(toY - cy, Chunk.CHUNK_SIZE - 1);
                int minZ = Helpers.Mod(fromZ, Chunk.CHUNK_SIZE);

                for (int cz = chunkFrom.z; cz <= chunkTo.z; cz += Chunk.CHUNK_SIZE, minZ = 0)
                {
                    int maxZ = math.min(toZ - cz, Chunk.CHUNK_SIZE - 1);
                    int minX = Helpers.Mod(fromX, Chunk.CHUNK_SIZE);

                    for (int cx = chunkFrom.x; cx <= chunkTo.x; cx += Chunk.CHUNK_SIZE, minX = 0)
                    {
                        bool ghostChunk    = false;
                        int3 chunkPosition = new int3(cx, cy, cz);
                        VoxLogger.Log("VoxelWorld : SetBlocks " + block + " | Update chunk at " + chunkPosition + ".");
                        Chunk chunk = GetChunk(chunkPosition);
                        if (chunk == null)
                        {
                            VoxLogger.Log("VoxelWorld : SetBlocks " + block + " | Chunk is ghost chunk.");
                            ghostChunk   = true;
                            chunk        = CreateChunk(chunkPosition);
                            chunk.render = false;
                            chunks.Add(chunkPosition, chunk);
                            chunk.NeedsTerrain = !Serialization.LoadChunk(chunk, true);
                            if (chunk.NeedsTerrain)
                            {
                                AddToQueue(generateQueue, chunkPosition, 0);
                            }
                            ghostChunks.Add(chunk);
                        }

                        int maxX = math.min(toX - cx, Chunk.CHUNK_SIZE - 1);

                        int3 from = new int3(minX, minY, minZ);
                        int3 to   = new int3(maxX, maxY, maxZ);

                        // Only update if it's placing blocks on the edges of the chunk and
                        // if they are the last/first ones in the loop. We don't need the chunks
                        // to update each other.
                        bool updateNorth  = (from.z == Chunk.CHUNK_SIZE - 1 || to.z == Chunk.CHUNK_SIZE - 1) && cz == chunkTo.z;
                        bool updateSouth  = (from.z == 0 || to.z == 0) && cz == chunkFrom.z;
                        bool updateEast   = (from.x == Chunk.CHUNK_SIZE - 1 || to.x == Chunk.CHUNK_SIZE - 1) && cx == chunkTo.x;
                        bool updateWest   = (from.x == 0 || to.x == 0) && cx == chunkFrom.x;
                        bool updateTop    = (from.y == Chunk.CHUNK_SIZE - 1 || to.y == Chunk.CHUNK_SIZE - 1) && cy == chunkTo.y;
                        bool updateBottom = (from.y == 0 || to.y == 0) && cy == chunkFrom.y;

                        chunk.SetRangeRaw(from, to, block);
                        if (!ghostChunk)
                        {
                            // Only update this chunk.
                            chunk.UpdateChunk();

                            UpdateChunkNeighbors(chunkPosition, updateNorth, updateSouth, updateEast, updateWest, updateTop, updateBottom);
                        }
                        else if (!chunk.NeedsTerrain)
                        {
                            VoxLogger.Log("VoxelWorld : SetBlocks " + block + " | Saving ghost chunk " + chunk + ".");
                            Serialization.SaveChunk(chunk, true);
                            DestroyChunk(chunk);
                        }
                    }
                }
            }
        }
예제 #2
0
        private void FinishGeneratingChunks()
        {
            if (!generatingChunks)
            {
                return;
            }

            generateChunksJob.Complete();

            voxelLoaderData.Dispose();
            loadedChunks.Dispose();

            NativeArray <int3>      renChunksKeys   = tempRenderChunks.GetKeyArray(Allocator.Temp);
            NativeArray <ChunkData> renChunksValues = tempRenderChunks.GetValueArray(Allocator.Temp);

            renderChunks.Clear();
            renderChunks.AddRange(renChunksKeys);

            for (int i = 0; i < renChunksKeys.Length; i++)
            {
                int3  chunkPos     = renChunksKeys[i];
                bool  shouldRender = renChunksValues[i].render;
                float priority     = renChunksValues[i].priority;
                if (!chunks.TryGetValue(chunkPos, out Chunk chunk))
                {
                    chunk = CreateChunk(chunkPos);
                    chunks.Add(chunkPos, chunk);
                    chunk.NeedsTerrain = !Serialization.LoadChunk(chunk, true);
                    if (chunk.NeedsTerrain)
                    {
                        AddToQueue(generateQueue, chunkPos, priority);
                    }
                    else if (shouldRender)
                    {
                        TryToQueueChunkRender(chunk, priority);
                    }
                }
                else if (!shouldRender && chunkRenderers.TryGetValue(chunkPos, out MeshRenderer renderer))
                {
                    // This is used for removing edge chunks that shouldn't be rendered.
                    // If we don't do this their meshes will stick around but not be properly updated.
                    PoolChunkRenderer(renderer);
                    chunkRenderers.Remove(chunkPos);
                }
                else if (shouldRender && chunk.HasRender && !chunkRenderers.ContainsKey(chunkPos))
                {
                    // This is in case there are chunks that should render but are missing renderers.
                    // Missing renderers can be caused by the method above.
                    CreateChunkRenderer(chunkPos, chunk.mesh);
                }
                else if (chunk.HasTerrain && !chunk.UpdatingRenderer && !chunk.HasRender && shouldRender)
                {
                    // The chunk is new and needs a mesh.
                    TryToQueueChunkRender(chunk, priority);
                }

                chunk.render = shouldRender;
            }

            renChunksKeys.Dispose();
            renChunksValues.Dispose();

            tempRenderChunks.Dispose();

            chunksToRemove.Clear();

            for (int i = 0; i < tempChunksToRemove.Length; i++)
            {
                DestroyChunk(chunks[tempChunksToRemove[i]]);
            }

            tempChunksToRemove.Dispose();
            generatingChunks = false;
        }