Beispiel #1
0
 public void QueueChunkUpdate(Vector3i chunkPos, bool lowPrioriity)
 {
     if (LoadedChunks.TryGetValue(chunkPos, out var chunk))
     {
         QueueChunkUpdate(chunk, lowPrioriity);
     }
 }
Beispiel #2
0
        private void SetChunkNeighborhood(TerrainChunk chunk)
        {
            TerrainChunk xUp;
            TerrainChunk xDown;
            TerrainChunk zUp;
            TerrainChunk zDown;

            LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X + 1, chunk.Position.Z), out xUp);
            LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X - 1, chunk.Position.Z), out xDown);
            LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X, chunk.Position.Z + 1), out zUp);
            LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X, chunk.Position.Z - 1), out zDown);

            if (xUp != null)
            {
                chunk.SetNeighbors(xUp, TerrainNeighbor.XUp);
                xUp.SetNeighbors(chunk, TerrainNeighbor.XDown);
            }
            if (xDown != null)
            {
                chunk.SetNeighbors(xDown, TerrainNeighbor.XDown);
                xDown.SetNeighbors(chunk, TerrainNeighbor.XUp);
            }
            if (zUp != null)
            {
                chunk.SetNeighbors(zUp, TerrainNeighbor.ZUp);
                zUp.SetNeighbors(chunk, TerrainNeighbor.ZDown);
            }
            if (zDown != null)
            {
                chunk.SetNeighbors(zDown, TerrainNeighbor.ZDown);
                zDown.SetNeighbors(chunk, TerrainNeighbor.ZUp);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Get the relative Chunk from a world position.
        /// </summary>
        /// <param name="chunkPosition"></param>
        /// <param name="worldPosition"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public Chunk GetRelativeChunk(Direction chunkPosition, Vector3Int worldPosition)
        {
            switch (chunkPosition)
            {
            case Direction.Left:
                return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(-8, 0, 0), out var leftChunk) ? leftChunk : null);

            case Direction.Right:
                return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(8, 0, 0), out var rightChunk) ? rightChunk : null);

            case Direction.Bottom:
                return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, -4, 0), out var bottomChunk) ? bottomChunk : null);

            case Direction.Top:
                return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, 4, 0), out var topChunk) ? topChunk : null);

            case Direction.Back:
                return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, 0, -8), out var backChunk) ? backChunk : null);

            case Direction.Front:
                return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, 0, 8), out var frontChunk) ? frontChunk : null);

            default:
                throw new ArgumentOutOfRangeException(nameof(chunkPosition), chunkPosition, null);
            }
        }
Beispiel #4
0
        public override BlockData GetBlockData(int x, int y, int z)
        {
            var chunkInWorld = ChunkInWorld(x, y, z);
            var blockInChunk = BlockInChunk(x, y, z);

            return(LoadedChunks.TryGetValue(chunkInWorld, out Chunk chunk) ? chunk.GetBlockData(blockInChunk) : null);
        }
Beispiel #5
0
        public Chunk GetChunk(Vector2Int chunkPosition)
        {
            Chunk result;

            LoadedChunks.TryGetValue(chunkPosition, out result);
            return(result);
        }
Beispiel #6
0
        public override LightLevel GetBlockLightLevel(int x, int y, int z)
        {
            var chunkInWorld = ChunkInWorld(x, y, z);
            var blockInChunk = BlockInChunk(x, y, z);

            return(LoadedChunks.TryGetValue(chunkInWorld, out Chunk chunk)
                ? chunk.GetLightLevel(blockInChunk)
                : LightLevel.Zero);
        }
Beispiel #7
0
        public override Block GetBlock(int x, int y, int z)
        {
            var chunkInWorld = ChunkInWorld(x, y, z);
            var blockInChunk = BlockInChunk(x, y, z);

            return(LoadedChunks.TryGetValue(chunkInWorld, out Chunk chunk)
                ? GameRegistry.GetBlock(chunk.GetBlock(blockInChunk))
                : BlockRegistry.BlockAir);
        }
Beispiel #8
0
 public Tile this[Vector2Int worldPosition]
 {
     get
     {
         Vector2Int chunkPosition = Chunk.CalculateResidingChunk(worldPosition);
         Chunk      chunk;
         if (LoadedChunks.TryGetValue(chunkPosition, out chunk))
         {
             return(chunk.GetTile(Tile.TilePositionInRelationToChunk(worldPosition)));
         }
         return(null);
     }
 }
Beispiel #9
0
        public List <Chunk> GetChunks(List <Vector2Int> chunkPositions)
        {
            List <Chunk> result = new List <Chunk>();

            for (int i = chunkPositions.Count - 1; i >= 0; --i)
            {
                Chunk value;
                if (LoadedChunks.TryGetValue(chunkPositions[i], out value))
                {
                    result.Add(value);
                    chunkPositions.RemoveAt(i);
                }
            }

            return(result);
        }
    /// <summary>
    /// Checks the <see cref="LoadedChunks"/> dictionary for the relevent chunk position
    /// Returns null if not present
    /// </summary>
    /// <param name="chunk">The coordinate of the chunk we wish to find</param>
    /// <returns></returns>
    public LoadedChunk2 GetLoadedChunk(Vec2i chunk)
    {
        LoadedChunk2 lChunk;

        if (InSubworld)
        {
            if (SubworldChunks.TryGetValue(chunk, out lChunk))
            {
                return(lChunk);
            }
        }
        if (LoadedChunks.TryGetValue(chunk, out lChunk))
        {
            return(lChunk);
        }
        return(null);
    }
Beispiel #11
0
        public override void SetBlockData(int x, int y, int z, BlockData data)
        {
            var chunkInWorld = ChunkInWorld(x, y, z);
            var blockInChunk = BlockInChunk(x, y, z);

            if (LoadedChunks.TryGetValue(chunkInWorld, out var chunk))
            {
                chunk.SetBlockData(blockInChunk, data);
            }

            var pos = new Vector3i(x, y, z);

            lock (_queuedLightUpdates)
            {
                if (!_queuedLightUpdates.Contains(pos))
                {
                    _queuedLightUpdates.Enqueue(pos);
                }
            }

            if (blockInChunk.X == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(-1, 0, 0), false);
            }
            else if (blockInChunk.X == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(+1, 0, 0), false);
            }
            if (blockInChunk.Y == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, -1, 0), false);
            }
            else if (blockInChunk.Y == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, +1, 0), false);
            }
            if (blockInChunk.Z == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, -1), false);
            }
            else if (blockInChunk.Z == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, +1), false);
            }
            QueueChunkUpdate(chunk, false);
        }
Beispiel #12
0
        public override void SetBlockLightLevel(int x, int y, int z, LightLevel lightLevel)
        {
            var chunkInWorld = ChunkInWorld(x, y, z);
            var blockInChunk = BlockInChunk(x, y, z);

            if (!LoadedChunks.TryGetValue(chunkInWorld, out var chunk))
            {
                return;
            }
            chunk.SetLightLevel(blockInChunk, lightLevel);

            if (blockInChunk.X == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(-1, 0, 0), false);
            }
            else if (blockInChunk.X == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(+1, 0, 0), false);
            }
            if (blockInChunk.Y == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, -1, 0), false);
            }
            else if (blockInChunk.Y == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, +1, 0), false);
            }
            if (blockInChunk.Z == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, -1), false);
            }
            else if (blockInChunk.Z == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, +1), false);
            }
            QueueChunkUpdate(chunk, false);
        }
Beispiel #13
0
        public override void SetBlock(int x, int y, int z, Block block, bool update, bool lowPriority)
        {
            var chunkInWorld = ChunkInWorld(x, y, z);
            var blockInChunk = BlockInChunk(x, y, z);

            if (LoadedChunks.TryGetValue(chunkInWorld, out var chunk))
            {
                if (chunk.GetBlock(blockInChunk) == block.Id)
                {
                    return;
                }
                chunk.SetBlock(blockInChunk, block.Id);
            }
            else
            {
                chunk = new Chunk(this, chunkInWorld);
                chunk.SetBlock(blockInChunk, block.Id);
                lock (LoadedChunks)
                {
                    LoadedChunks.Add(chunkInWorld, chunk);
                }
            }

            if (!update)
            {
                return;
            }

            var pos = new Vector3i(x, y, z);

            lock (_queuedLightUpdates)
            {
                if (!_queuedLightUpdates.Contains(pos))
                {
                    _queuedLightUpdates.Enqueue(pos);
                }
            }

            if (blockInChunk.X == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(-1, 0, 0), lowPriority);
            }
            else if (blockInChunk.X == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(+1, 0, 0), lowPriority);
            }
            if (blockInChunk.Y == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, -1, 0), lowPriority);
            }
            else if (blockInChunk.Y == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, +1, 0), lowPriority);
            }
            if (blockInChunk.Z == 0)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, -1), lowPriority);
            }
            else if (blockInChunk.Z == Chunk.Size - 1)
            {
                QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, +1), lowPriority);
            }
            QueueChunkUpdate(chunk, lowPriority);
        }
Beispiel #14
0
        private void LoadThread()
        {
            var chunksWaitingForNeighbours = new HashSet <Vector3i>();

            while (!_unloaded)
            {
                //Remove chunks waiting that have been unloaded
                var chunksToRemove =
                    chunksWaitingForNeighbours.Where(
                        chunkPos =>
                        !_populatedChunks.Contains(chunkPos) && !_chunksReadyToAdd.ContainsKey(chunkPos) ||
                        _populatedChunks.Contains(chunkPos) && !LoadedChunks.ContainsKey(chunkPos)).ToList();
                chunksToRemove.ForEach(chunkPos => chunksWaitingForNeighbours.Remove(chunkPos));

                //Update chunks waiting for neighbours
                var chunksToUpdate =
                    chunksWaitingForNeighbours.Where(
                        chunkPos =>
                        BlockFaceHelper.Faces.All(
                            face => _populatedChunks.Contains(chunkPos + face.GetNormali())))
                    .ToList();
                foreach (var chunkPos in chunksToUpdate)
                {
                    QueueChunkUpdate(chunkPos, true);
                    chunksWaitingForNeighbours.Remove(chunkPos);
                }

                var playerChunksLists = new List <List <Vector3i> >();
                foreach (var playerEntity in PlayerEntities)
                {
                    var playerChunksToLoad = new List <Vector3i>();
                    var playerChunk        = ChunkInWorld(playerEntity.Position.ToVector3i());

                    //Load 7x7x7 around player
                    for (var x = -3; x <= 3; x++)
                    {
                        for (var y = -3; y <= 3; y++)
                        {
                            for (var z = -3; z <= 3; z++)
                            {
                                var chunkPos = playerChunk + new Vector3i(x, y, z);
                                if (playerChunksToLoad.Contains(chunkPos))
                                {
                                    continue;
                                }
                                if (_populatedChunks.Contains(chunkPos) || _chunksReadyToAdd.ContainsKey(chunkPos))
                                {
                                    //Reset chunk time so it will not be unloaded
                                    if (LoadedChunks.TryGetValue(chunkPos, out var chunk))
                                    {
                                        chunk.Time = DateTime.Now;
                                    }
                                    continue;
                                }

                                playerChunksToLoad.Add(chunkPos);
                            }
                        }
                    }


                    //Load 61x3x61 terrain if overworld
                    //heightmap(x*Chunk.Size + Chunk.Size/2, z*Chunk.Size + Chunk.Size/2)

                    var height          = 0 + Chunk.Size / 2;
                    var heightMapChunkY = ChunkInWorld(0, height, 0).Y;
                    for (var x = -30; x <= 30; x++)
                    {
                        for (var y = -1; y <= 1; y++)
                        {
                            for (var z = -30; z <= 30; z++)
                            {
                                if (x <= 3 && x >= -3 && y <= 3 && y >= -3 && z <= 3 && z >= -3)
                                {
                                    continue;
                                }

                                var chunkPos = new Vector3i(playerChunk.X + x, heightMapChunkY + y, playerChunk.Z + z);

                                if (_populatedChunks.Contains(chunkPos) || _chunksReadyToAdd.ContainsKey(chunkPos))
                                {
                                    //Reset chunk time so it will not be unloaded
                                    if (LoadedChunks.TryGetValue(chunkPos, out var chunk))
                                    {
                                        chunk.Time = DateTime.Now;
                                    }
                                    continue;
                                }

                                playerChunksToLoad.Add(chunkPos);
                            }
                        }
                    }



                    playerChunksToLoad.Sort(
                        (v0, v1) =>
                        (int)(v0.ToVector3() - playerChunk.ToVector3()).LengthSquared -
                        (int)(v1.ToVector3() - playerChunk.ToVector3()).LengthSquared);

                    //Cap player chunk load tasks to 16
                    if (playerChunksToLoad.Count > 16)
                    {
                        playerChunksToLoad.RemoveRange(16, playerChunksToLoad.Count - 16);
                    }

                    playerChunksLists.Add(playerChunksToLoad);
                }

                var merged = ExtensionHelper.ZipMerge(playerChunksLists.ToArray());
                foreach (var chunkPos in merged)
                {
                    var cachedChunk = LoadChunk(chunkPos);

                    if (cachedChunk.IsEmpty)
                    {
                        //Empty chunks dont need to be added to LoadedChunks
                        lock (_populatedChunks)
                        {
                            _populatedChunks.Add(chunkPos);
                        }
                    }
                    else
                    {
                        lock (_chunksReadyToAdd)
                        {
                            _chunksReadyToAdd.Add(chunkPos, cachedChunk);
                        }
                        chunksWaitingForNeighbours.Add(chunkPos);
                    }
                }

                Thread.Sleep(10);
            }
        }
Beispiel #15
0
        public override void Update()
        {
            if (_unloaded)
            {
                return;
            }

            //Update entities
            foreach (var playerEntity in PlayerEntities)
            {
                playerEntity.Update();
            }
            foreach (var entity in Entities)
            {
                entity.Update();
            }

            lock (_chunksReadyToRemove)
            {
                while (_chunksReadyToRemove.Count > 0)
                {
                    var chunkPos = _chunksReadyToRemove.First();

                    if (LoadedChunks.TryGetValue(chunkPos, out var chunk))
                    {
                        lock (LoadedChunks)
                        {
                            LoadedChunks.Remove(chunkPos);
                        }
                        _populatedChunks.Remove(chunkPos);
                        chunk.Dispose();
                    }

                    _chunksReadyToRemove.Remove(chunkPos);
                }
            }

            lock (_chunksReadyToAdd)
            {
                while (_chunksReadyToAdd.Count > 0)
                {
                    var entry = _chunksReadyToAdd.First();
                    lock (LoadedChunks)
                    {
                        if (!LoadedChunks.ContainsKey(entry.Key))
                        {
                            LoadedChunks.Add(entry.Key, new Chunk(entry.Value));
                        }
                        else
                        {
                            Logger.Error("Chunk has already been loaded! " + entry.Key);
                        }
                    }
                    _populatedChunks.Add(entry.Key);
                    _chunksReadyToAdd.Remove(entry.Key);
                }
            }

            while (_chunksReadyToUploadHp.Count > 0)
            {
                lock (_chunksReadyToUploadHp)
                {
                    _chunksReadyToUploadHp.Dequeue().Upload();
                }
            }

            while (_chunksReadyToUploadLp.Count > 0)
            {
                lock (_chunksReadyToUploadLp)
                {
                    _chunksReadyToUploadLp.Dequeue().Upload();
                }
            }
        }