Пример #1
0
        /// <summary>
        /// Creates a new chunk object based on the given chunk position.
        /// </summary>
        /// <param name="chunkPos">The position of the chunk.</param>
        /// <returns>The newly created chunk game object.</returns>
        internal BlockChunk LoadChunk(ChunkPosition chunkPos)
        {
            var go    = new GameObject($"Chunk: ({chunkPos.X}, {chunkPos.Y}, {chunkPos.Z})");
            var chunk = go.AddComponent <BlockChunk>();

            chunk.Position = chunkPos;

            go.hideFlags = HideFlags.HideAndDontSave;
            go.transform.SetParent(m_Transform);
            go.transform.localPosition = new Vector3(chunkPos.X, chunkPos.Y, chunkPos.Z) * m_ChunkSize.Value;

            var meshFilter   = go.AddComponent <MeshFilter>();
            var meshCollider = go.AddComponent <MeshCollider>();

            go.AddComponent <MeshRenderer>();

            meshFilter.sharedMesh = new Mesh
            {
                name = $"Chunk Visual: ({chunkPos.X}, {chunkPos.Y}, {chunkPos.Z})"
            };

            meshCollider.sharedMesh = new Mesh
            {
                name = $"Chunk Collision: ({chunkPos.X}, {chunkPos.Y}, {chunkPos.Z})"
            };

            return(chunk);
        }
Пример #2
0
        /// <summary>
        /// Gets the chunk at the target chunk position.
        /// </summary>
        /// <param name="chunkPos">The chunk position.</param>
        /// <param name="create">Whether or not to create the chunk if it doesn't currently exist.</param>
        /// <returns>The chunk, or null if it doesn't exist.</returns>
        private Chunk GetChunk(ChunkPosition chunkPos, bool create)
        {
            var chunk = World.GetChunk(chunkPos);

            if (chunk != null || !create)
            {
                return(chunk);
            }

            chunk = World.CreateChunk(chunkPos);
            bool remesh = ChunkLoader.LoadSync(chunk);

            if (remesh)
            {
                m_DirtyChunks.Add(chunkPos);
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(0));
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(1));
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(2));
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(3));
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(4));
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(5));
                RemeshDirtyChunks();
            }

            return(chunk);
        }
Пример #3
0
        /// <summary>
        /// Determines which chunks should be remeshed based on the given block position.
        /// </summary>
        /// <param name="blockPos">The local block position.</param>
        /// <param name="chunkPos">The chunk position.</param>
        private void RemeshEffectedChunks(BlockPosition blockPos, ChunkPosition chunkPos)
        {
            m_DirtyChunks.Add(chunkPos);

            if (blockPos.X == 0)
            {
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(1));
            }

            if (blockPos.X == World.ChunkSize.Mask)
            {
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(0));
            }

            if (blockPos.Y == 0)
            {
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(3));
            }

            if (blockPos.Y == World.ChunkSize.Mask)
            {
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(2));
            }

            if (blockPos.Z == 0)
            {
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(5));
            }

            if (blockPos.Z == World.ChunkSize.Mask)
            {
                m_DirtyChunks.Add(chunkPos.ShiftAlongDirection(4));
            }
        }
Пример #4
0
        /// <summary>
        /// Destroys the chunk at the given chunk coordinates if it exists.
        /// </summary>
        /// <param name="pos">The chunk position.</param>
        internal void DestroyChunk(ChunkPosition pos)
        {
            var chunk = GetChunk(pos);

            if (chunk != null)
            {
                m_Chunks.Remove(chunk);
            }
        }
Пример #5
0
        /// <summary>
        /// Analyses the given chunk and starts a set of remesh tasks for handling that chunk.
        /// This method blocks until all remesh tasks have been completed.
        /// </summary>
        /// <param name="worldContainer">The world to operate on.</param>
        /// <param name="chunkPos">The chunk target position.</param>
        internal RemeshTaskStack RemeshChunk(WorldContainer worldContainer, ChunkPosition chunkPos)
        {
            var taskStack  = new RemeshTaskStack(chunkPos);
            var chunkGroup = new ChunkGroup(worldContainer, chunkPos);

            foreach (var dis in m_Distributors)
            {
                dis.CreateTasks(chunkGroup, taskStack);
            }

            return(taskStack);
        }
Пример #6
0
        /// <summary>
        /// Gets the chunk at the given chunk position.
        /// </summary>
        /// <param name="chunkPos">The chunk position.</param>
        /// <returns>The Block Chunk.</returns>
        private BlockChunk GetChunk(ChunkPosition chunkPos)
        {
            foreach (var chunk in m_Chunks)
            {
                if (chunk.Position.Equals(chunkPos))
                {
                    return(chunk);
                }
            }

            return(null);
        }
Пример #7
0
        /// <summary>
        /// Gets the chunk at the given chunk position.
        /// </summary>
        /// <param name="pos">The position of the chunk.</param>
        /// <returns>The block container, or null if it doesn't exist.</returns>
        internal Chunk GetChunk(ChunkPosition pos)
        {
            for (int i = 0; i < m_Chunks.Count; i++)
            {
                if (m_Chunks[i].Position.Equals(pos))
                {
                    return(m_Chunks[i]);
                }
            }

            return(null);
        }
Пример #8
0
        /// <summary>
        /// Marks a given chunk to be remeshed.
        /// </summary>
        /// <param name="chunkPos">The position of the chunk to remesh.</param>
        private void MarkForRemesh(ChunkPosition chunkPos)
        {
            if (!World.DoesChunkExist(chunkPos))
            {
                return;
            }

            if (m_DirtyChunks.Contains(chunkPos))
            {
                return;
            }

            m_DirtyChunks.Add(chunkPos);
        }
Пример #9
0
        /// <summary>
        /// Requests the chunk at the given position to start loading in the background.
        /// </summary>
        /// <param name="chunkPos">The chunk position.</param>
        /// <returns>True if the operation was started. False if the chunk is already loaded.</returns>
        public bool LoadChunkAsync(ChunkPosition chunkPos)
        {
            var chunk = World.GetChunk(chunkPos);

            if (chunk != null)
            {
                return(false);
            }

            chunk = World.CreateChunk(chunkPos);
            ChunkLoader.LoadAsync(chunk);

            return(true);
        }
Пример #10
0
        /// <summary>
        /// Creates a new chunk at the given chunk position if it doesn't currently exist.
        /// </summary>
        /// <param name="pos">The chunk position.</param>
        /// <returns>
        /// The newly created chunk, or the current chunk if if already exists.
        /// </returns>
        internal Chunk CreateChunk(ChunkPosition pos)
        {
            var oldChunk = GetChunk(pos);

            if (oldChunk != null)
            {
                return(oldChunk);
            }

            var newChunk = new Chunk(ChunkSize, pos);

            m_Chunks.Add(newChunk);

            return(newChunk);
        }
Пример #11
0
        /// <summary>
        /// Checks for changes in the camera's chunk position and updates the field
        /// and resets the iterator as needed.
        /// </summary>
        private void UpdateCameraPosition()
        {
            var pos      = m_Camera.transform.position;
            var chunkPos = new ChunkPosition
            {
                X = Mathf.FloorToInt(pos.x) >> m_BlockWorld.ChunkSize.IntBits,
                Y = Mathf.FloorToInt(pos.y) >> m_BlockWorld.ChunkSize.IntBits,
                Z = Mathf.FloorToInt(pos.z) >> m_BlockWorld.ChunkSize.IntBits,
            };

            if (!chunkPos.Equals(m_LastCameraPosition))
            {
                m_LastCameraPosition = chunkPos;
                m_ChunkLoadPatternIterator.Reset();
            }
        }
Пример #12
0
        /// <summary>
        /// Triggers the given at the given position to be remeshed, if not already in the list.
        /// Preforms no action if the chunk does not exist.
        /// </summary>
        /// <param name="chunkPos">The chunk position.</param>
        /// <param name="later">Whether to remesh the chunk now or later.</param>
        private void RemeshChunkAt(ChunkPosition chunkPos, bool later)
        {
            if (!World.DoesChunkExist(chunkPos))
            {
                return;
            }

            if (later)
            {
                RemeshHandler.RemeshChunkLater(chunkPos);
            }
            else
            {
                RemeshHandler.RemeshChunk(chunkPos);
            }
        }
Пример #13
0
        /// <summary>
        /// Gets or creates the chunk at the given position.
        /// </summary>
        /// <param name="chunkPos">The chunk position.</param>
        /// <returns>The block chunk.</returns>
        private BlockChunk GetChunk(ChunkPosition chunkPos)
        {
            foreach (var chunk in m_Chunks)
            {
                if (chunk.Position.Equals(chunkPos))
                {
                    return(chunk);
                }
            }

            var c = m_ChunkCreator.LoadChunk(chunkPos);

            m_Chunks.Add(c);

            return(c);
        }
Пример #14
0
        /// <inheritdoc cref="ChunkLoadingPattern"/>
        protected override void GeneratePositions(ChunkPosition[] positions, Vector3Int extents)
        {
            int i = 0;

            for (int x = -extents.x; x <= extents.x; x++)
            {
                for (int y = -extents.y; y <= extents.y; y++)
                {
                    for (int z = -extents.z; z <= extents.z; z++)
                    {
                        positions[i++] = new ChunkPosition(x, y, z);
                    }
                }
            }

            System.Array.Sort(positions, (a, b) =>
                              (a.X * a.X + a.Y * a.Y + a.Z * a.Z) - (b.X * b.X + b.Y * b.Y + b.Z * b.Z));
        }
Пример #15
0
        /// <summary>
        /// Schedules the chunk to be remeshed at a later point in time, after all primary
        /// remesh tasks are finished.
        /// </summary>
        /// <param name="chunkPos">The target chunk position.</param>
        /// <see cref="RemeshChunk(ChunkProperties)"/>
        internal void RemeshChunkLater(ChunkPosition chunkPos)
        {
            foreach (var task in m_ActiveTasks)
            {
                if (task.ChunkPosition.Equals(chunkPos))
                {
                    return;
                }
            }

            foreach (var task in m_PendingRemesh)
            {
                if (task.Equals(chunkPos))
                {
                    return;
                }
            }

            m_PendingRemesh.Add(chunkPos);
        }
Пример #16
0
        /// <summary>
        /// Force loads all chunks within a given region, if not already loaded.
        /// </summary>
        /// <param name="center">The center of the bounding region.</param>
        /// <param name="extents">The radius of each axis.</param>
        /// <returns>True if any additional chunks were loaded.</returns>
        internal bool LoadChunkRegion(ChunkPosition center, Vector3Int extents)
        {
            // TODO Remove "was loaded" check, to stop tasks from being run synchronously.

            var min = new Vector3Int
            {
                x = center.X - extents.x,
                y = center.Y - extents.y,
                z = center.Z - extents.z,
            };

            var max = new Vector3Int
            {
                x = center.X + extents.x,
                y = center.Y + extents.y,
                z = center.Z + extents.z,
            };

            bool loaded = false;

            for (int x = min.x; x <= max.x; x++)
            {
                for (int y = min.y; y <= max.y; y++)
                {
                    for (int z = min.z; z <= max.z; z++)
                    {
                        var chunkPos = new ChunkPosition(x, y, z);
                        var task     = new LoadChunkTask(chunkPos);
                        m_ServerThread.RunTaskSync(task);

                        loaded |= task.WasJustLoaded;
                    }
                }
            }

            return(loaded);
        }
Пример #17
0
        /// <summary>
        /// Analyses the given chunk and starts a set of remesh tasks for handling that chunk.
        /// If the chunk was scheduled to be remeshed later, it will be immediately be remeshed.
        /// If the chunk is already being remeshed, this method does nothing.
        /// </summary>
        /// <param name="chunkPos">The chunk target position.</param>
        /// <param name="pendingTask">
        /// If true, this task is allowed to task any number of frames to finish. Otherwise, the task
        /// is required to finish the next frame.
        /// </param>
        internal void RemeshChunk(ChunkPosition chunkPos, bool pendingTask = false)
        {
            for (int i = 0; i < m_ActiveTasks.Count; i++)
            {
                if (m_ActiveTasks[i].ChunkPosition.Equals(chunkPos))
                {
                    m_ActiveTasks[i].IsPendingTask = false;
                    return;
                }
            }

            for (int i = 0; i < m_PendingRemesh.Count; i++)
            {
                if (m_PendingRemesh[i].Equals(chunkPos))
                {
                    m_PendingRemesh.RemoveAt(i);
                    break;
                }
            }

            var properties = m_ChunkPropertiesPool.Pull();
            var blockList  = m_BlockWorld.BlockList;
            var world      = m_BlockWorld.WorldContainer.World;

            ChunkAnalyzer.LoadProperties(properties, blockList, world, chunkPos);

            var taskStack = new RemeshTaskStack(properties);

            taskStack.IsPendingTask = pendingTask;
            m_ActiveTasks.Add(taskStack);

            foreach (var dis in m_Distributors)
            {
                dis.CreateTasks(properties, taskStack);
            }
        }
Пример #18
0
 /// <summary>
 /// Requests the chunk at the given position to start loading in the background.
 /// </summary>
 /// <param name="chunkPos">The chunk position.</param>
 internal void LoadChunkAsync(ChunkPosition chunkPos) => m_ServerThread.RunTask(new LoadChunkTask(chunkPos));
Пример #19
0
 /// <summary>
 /// Checks if the given chunk exists or not.
 /// </summary>
 /// <returns>True if the chunk exists, false otherwise.</returns>
 public bool DoesChunkExist(ChunkPosition chunkPos) => World.DoesChunkExist(chunkPos);
Пример #20
0
 /// <summary>
 /// Causes the target chunk to be loaded, if not already loaded.
 /// </summary>
 public void LoadChunk(ChunkPosition chunkPos) => GetChunk(chunkPos, true);
Пример #21
0
 /// <summary>
 /// Gets whether or not the target chunk exists.
 /// </summary>
 /// <param name="pos">The position of the chunk.</param>
 /// <returns>True if the chunk exists, false otherwise.</returns>
 internal bool DoesChunkExist(ChunkPosition pos) => GetChunk(pos) != null;
Пример #22
0
 /// <summary>
 /// Creates a new chunk object.
 /// </summary>
 /// <param name="chunkSize">The chunk size.</param>
 /// <param name="position">The size of this chunk in the world.</param>
 internal Chunk(GridSize chunkSize, ChunkPosition position)
 {
     Size     = chunkSize;
     Position = position;
     Blocks   = new ushort[Size.Volume];
 }
Пример #23
0
 /// <summary>
 /// Requests the chunk at the given position to start loading in the background.
 /// </summary>
 /// <param name="chunkPos">The chunk position.</param>
 /// <returns>True if the operation was started. False if the chunk is already loaded.</returns>
 public bool LoadChunkAsync(ChunkPosition chunkPos) => m_WorldContainer.LoadChunkAsync(chunkPos);
Пример #24
0
 /// <summary>
 /// Creates a new remesh task stack.
 /// </summary>
 /// <param name="chunkPos">The chunk position.</param>
 internal RemeshTaskStack(ChunkPosition chunkPos)
 {
     ChunkPosition = chunkPos;
 }