Esempio n. 1
0
    public void OnPlayerDigging(IMinecraftUser user, IMinecraftPacket packet)
    {
        var status   = (DiggingType)packet.ReadVarInt32();
        var position = packet.ReadPosition();
        var face     = (BlockFaceType)packet.ReadByte();

        _logger.LogTrace($"Status={status};Position={position};Face={face}");

        if (user.Player.GameMode is ServerGameModeType.Creative)
        {
            IBlock previousBlock = user.Player.Map.GetBlock(position);

            if (previousBlock.IsAir)
            {
                throw new InvalidOperationException($"Cannot dig air blocks ({position})");
            }

            using var playerDiggingAck = new AcknowledgePlayerDiggingPacket(position, previousBlock, DiggingType.Started);
            user.Player.SendPacketToVisibleEntities(playerDiggingAck);

            using var blockChange = new BlockChangePacket(BlockType.Air, position);
            user.Player.SendPacketToVisibleEntities(blockChange);

            IBlock block = user.Player.Map.SetBlock(BlockType.Air, position);

            using var chunkPacket = new ChunkDataPacket(block.Chunk);
            user.Player.SendPacketToVisibleEntities(chunkPacket, includeEntity: true);
        }
        else
        {
            // TODO: other modes
        }
    }
Esempio n. 2
0
    /// <summary>
    /// Adds chunk data to the world
    /// </summary>
    /// <param name="chunkData"></param>
    public void AddChunkData(ChunkDataPacket chunkData)
    {
        lock (_chunks)
        {
            // if the chunk already exists, add data
            // otherwise, make a new chunk
            var existingChunk = _chunks.Find(c => c.Position.Equals(chunkData.Position));
            if (existingChunk != null)              // chunk already exists
            {
                if (chunkData.GroundUpContinuous)
                {
                    Debug.LogWarning($"Packet data for chunk at {chunkData.Position} tried to load GroundUpContinuous for already loaded chunk!");
                    return;
                }

                existingChunk.AddChunkData(chunkData);
                ChunkRenderer.MarkChunkForRegeneration(existingChunk);
            }
            else
            {
                Chunk chunk = new Chunk(chunkData, this);
                _chunks.Add(chunk);
                ChunkRenderer.AddChunk(chunk);
            }
        }
    }
Esempio n. 3
0
        public async Task SendChunkAsync(Chunk chunk)
        {
            var chunkData = new ChunkDataPacket(chunk.X, chunk.Z);

            for (int i = 0; i < 16; i++)
            {
                chunkData.Data.Add(new ChunkSection().FilledWithLight());
            }

            for (int x = 0; x < 16; x++)
            {
                for (int y = 0; y < 16; y++)
                {
                    for (int z = 0; z < 16; z++)
                    {
                        var block = chunk.Blocks[x, y, z];

                        chunkData.Data[6].BlockStateContainer.Set(x, y, z, block);
                    }
                }
            }

            for (int i = 0; i < 16 * 16; i++)
            {
                chunkData.Biomes.Add(29); //TODO: Add proper biomes
            }

            await PacketHandler.CreateAsync(chunkData, this.MinecraftStream);
        }
Esempio n. 4
0
    private void SendChunkData(IMinecraftUser user)
    {
        IChunk chunk = _worldManager.Overworld.GetRegion(0, 0).GetChunk(0, 0);

        chunk.GenerateHeightMap();

        // Temporary
        _worldManager.Overworld.AddPlayer(user.Player);

        using var packet = new ChunkDataPacket(chunk, serializeFullChunk: true);
        user.Send(packet);
    }
Esempio n. 5
0
        /// <summary>
        /// Unloads the given chunk on the client.
        /// </summary>
        public virtual void UnloadChunk(Coordinates2D position)
        {
            var dataPacket = new ChunkDataPacket();

            dataPacket.AddBitMap          = 0;
            dataPacket.GroundUpContinuous = true;
            dataPacket.PrimaryBitMap      = 0;
            dataPacket.X    = (int)position.X;
            dataPacket.Z    = (int)position.Z;
            dataPacket.Data = ChunkHelper.ChunkRemovalSequence;
            SendPacket(dataPacket);
            LoadedChunks.Remove(position);
        }
Esempio n. 6
0
    public void OnPlayerBlockPlacement(IMinecraftUser user, IMinecraftPacket packet)
    {
        var      handType      = (HandType)packet.ReadVarInt32();
        Position blockPosition = packet.ReadPosition();
        var      blockFace     = (BlockFaceType)packet.ReadVarInt32();
        float    cursorX       = packet.ReadSingle();
        float    cursorY       = packet.ReadSingle();
        float    cursorZ       = packet.ReadSingle();
        bool     isInsideBlock = packet.ReadBoolean();

        // TODO: check if the current player is interacting with an interactable object.
        // Like: Chest, anvil, crafting table.

        IItemSlot currentHeldItem = user.Player.HotBar.SelectedSlot;

        if (currentHeldItem.HasItem)
        {
            BlockData block        = _registry.Blocks.FirstOrDefault(x => x.ItemId == currentHeldItem.ItemId);
            BlockType blockToPlace = block.Type;

            if (blockToPlace is not BlockType.Air)
            {
                Position realBlockPosition = blockFace switch
                {
                    BlockFaceType.Bottom => new Position(blockPosition.X, blockPosition.Y - 1, blockPosition.Z),
                    BlockFaceType.Top => new Position(blockPosition.X, blockPosition.Y + 1, blockPosition.Z),
                    BlockFaceType.North => new Position(blockPosition.X, blockPosition.Y, blockPosition.Z - 1),
                    BlockFaceType.South => new Position(blockPosition.X, blockPosition.Y, blockPosition.Z + 1),
                    BlockFaceType.West => new Position(blockPosition.X - 1, blockPosition.Y, blockPosition.Z),
                    BlockFaceType.East => new Position(blockPosition.X + 1, blockPosition.Y, blockPosition.Z),
                    _ => throw new InvalidOperationException("Invalid block face type.")
                };

                _logger.LogDebug($"Placing block '{blockToPlace}' at position {realBlockPosition}");

                user.Player.Map.SetBlock(blockToPlace, (int)realBlockPosition.X, (int)realBlockPosition.Y, (int)realBlockPosition.Z);

                using var blockChangePacket = new BlockChangePacket(blockToPlace, blockPosition);
                user.Player.SendPacketToVisibleEntities(blockChangePacket);

                using var chunkDataPacket = new ChunkDataPacket(user.Player.Chunk);
                user.Player.SendPacketToVisibleEntities(chunkDataPacket);
            }
        }
    }
}
Esempio n. 7
0
        private static async Task LoginStart(Client client, byte[] data)
        {
            String username = Utils.ReadString(new MemoryStream(data), 16);

            Console.WriteLine("Client attempting to authenticate as " + username);

            Guid guid = new Guid();
            LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(client, guid, username);
            await loginSuccessPacket.SendToClient();

            client.State  = ClientState.Play;
            client.Player = new Player(client, username, guid);

            JoinGamePacket joinGamePacket = new JoinGamePacket(client, client.Player.EntityId, (byte)client.Player.Gamemode, 0, 0x0000000000000000);
            await joinGamePacket.SendToClient();

            Console.WriteLine("Client authenticated as " + username);

            HeldItemChangePacket heldItemChangePacket = new HeldItemChangePacket(client, 0);
            await heldItemChangePacket.SendToClient();

            client.Player.Y = 68;
            PlayerPositionLookPacket playerPositionLookPacket = new PlayerPositionLookPacket(client, client.Player);
            await playerPositionLookPacket.SendToClient();

            PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(client, PlayerInfoAction.AddPlayer);

            playerInfoPacket.AddPlayer(client.Player);
            await playerInfoPacket.SendToClient();

            playerInfoPacket = new PlayerInfoPacket(client, PlayerInfoAction.UpdateLatency);
            playerInfoPacket.AddPlayer(client.Player);
            await playerInfoPacket.SendToClient();

            Region region = new Region(0, 0);

            ChunkColumn column = new ChunkColumn(0, 0);

            column.FillTest();
            ChunkDataPacket chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();


            column = new ChunkColumn(1, 0);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(1, 1);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(0, 1);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(-1, 1);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(-1, -1);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(1, -1);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(0, -1);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            column = new ChunkColumn(-1, -0);
            column.FillTest();
            chunkDataPacket = new ChunkDataPacket(client, column);
            await chunkDataPacket.SendToClient();

            Console.WriteLine("Sent");
        }
Esempio n. 8
0
	/// <summary>
	/// Populates this chunk with data from a <see cref="ChunkDataPacket"/>
	/// </summary>
	/// <param name="packet"></param>
	public void AddChunkData(ChunkDataPacket packet)
	{
		//check if data applies to this chunk
		if (!packet.Position.Equals(Position))
		{
			Debug.LogWarning($"Chunk at {Position} tried to add data for chunk at {packet.Position}??");
			return;
		}

		// lock block array to stop block changes from happening
		var data = new List<byte>(packet.Data);

		Profiler.BeginSample("Loading chunk sections");

		// chunk data
		for (int s = 0; s < 16; s++)
		{
			// check bitmask to see if we're reading data for this section
			if ((packet.PrimaryBitmask & (1) << s) != 0)
			{
				Profiler.BeginSample($"Chunk section: {s}");

				// set max block height to the height of this chunk
				int maxBlockHeight = (s + 1) * 16;
				if (maxBlockHeight > MaxHeight)
					MaxHeight = maxBlockHeight;

				// read bits per block
				byte bitsPerBlock = data.Read(1)[0];
				if (bitsPerBlock < 4)
					bitsPerBlock = 4;

				// choose palette type
				IChunkPalette palette;
				if (bitsPerBlock <= 8)
					palette = new IndirectChunkPalette();
				else
					palette = new DirectChunkPalette();

				palette.Read(data); // read palette data, bringing chunk data into front of buffer

				// bitmask that contains bitsperblock set bits
				uint individualValueMask = (uint)((1 << bitsPerBlock) - 1);

				// read data into array of longs
				int dataArrayLength = VarInt.ReadNext(data);
				ulong[] dataArray = new ulong[dataArrayLength];
				for (int i = 0; i < dataArrayLength; i++)
				{
					dataArray[i] = PacketHelper.GetUInt64(data);
				}

				Profiler.BeginSample("Block data");

				// parse block data
				for (int b = 0; b < 4096; b++)    // for section height
				{
					int startLong = (b * bitsPerBlock) / 64;
					int startOffset = (b * bitsPerBlock) % 64;
					int endLong = ((b + 1) * bitsPerBlock - 1) / 64;

					uint blockData;
					if (startLong == endLong)
					{
						blockData = (uint)(dataArray[startLong] >> startOffset);
					}
					else
					{
						int endOffset = 64 - startOffset;
						blockData = (uint)(dataArray[startLong] >> startOffset | dataArray[endLong] << endOffset);
					}

					blockData &= individualValueMask;

					uint blockState = palette.GetBlockState(blockData);
					BlockState blk = new BlockState((BlockType)blockState);

					// add block to block array
					BlockArray[b + (4096 * s)] = blk;
				}

				Profiler.EndSample();   // block data

				// we don't use sky or block lights
				// read data to move new data to front of buffer
				data.Read(2048);
				if (World.Dimension == World.DimensionType.OVERWORLD)
					data.Read(2048);

				/*
				Profiler.BeginSample("Block lights");

				// parse block light data
				for (int y = 0; y < 16; y++)
				{
					for (int z = 0; z < 16; z++)
					{
						for (int x = 0; x < 16; x += 2)
						{
							// light data takes 4 bits. because of this, we read two light values per byte
							byte value = data.Read(1)[0];

							_blockLights[x, y + (16 * s), z] = value & 0xf;
							_blockLights[x + 1, y + (16 * s), z] = (value >> 4) & 0xf;
						}
					}
				}

				Profiler.EndSample();	// block lights

				// parse sky lights
				if (World.Dimension == World.DimensionType.OVERWORLD)
				{
					Profiler.BeginSample("Sky lights");

					// parse block light data
					for (int y = 0; y < 16; y++)
					{
						for (int z = 0; z < 16; z++)
						{
							for (int x = 0; x < 16; x += 2)
							{
								// light data takes 4 bits. because of this, we read two light values per byte
								byte value = data.Read(1)[0];

								_skylights[x, y + (16 * s), z] = value & 0xf;
								_skylights[x + 1, y + (16 * s), z] = (value >> 4) & 0xf;
							}
						}
					}

					Profiler.EndSample();	// sky lights
				}

*/

				Profiler.EndSample();   // chunk section
			}
			else
			{
				// fill chunk section with air if full chunk
				if (packet.GroundUpContinuous)
				{
					for (int i = 0; i < 4096; i++)
					{
						BlockArray[s + (4096 * s)] = new BlockState(BlockType.AIR);
					}
				}
			}

			// parse biomes
			if (packet.GroundUpContinuous)
			{
				//throw new NotImplementedException();
			}
		}
	}
Esempio n. 9
0
        public static ChunkDataPacket CreatePacket(Chunk chunk)
        {
            var packet = new ChunkDataPacket();

            var X = (int)chunk.AbsolutePosition.X;
            var Z = (int)chunk.AbsolutePosition.Z;

            byte[] blockData;
            byte[] metadata;
            byte[] blockLight;
            byte[] skyLight;

            ushort mask = 1, chunkY = 0;
            bool   nonAir = true;

            // First pass calculates number of sections to send
            int totalSections = 0;

            for (int i = 15; i >= 0; i--)
            {
                Section s = chunk.Sections[chunkY++];

                if (s.IsAir)
                {
                    nonAir = false;
                }
                if (nonAir)
                {
                    totalSections++;
                }
            }

            mask       = 1;
            chunkY     = 0;
            nonAir     = true;
            blockData  = new byte[totalSections * BlockDataLength];
            metadata   = new byte[totalSections * NibbleDataLength];
            blockLight = new byte[totalSections * NibbleDataLength];
            skyLight   = new byte[totalSections * NibbleDataLength];

            ushort PrimaryBitMap = 0, AddBitMap = 0;

            // Second pass produces the arrays
            for (int i = 15; i >= 0; i--)
            {
                Section s = chunk.Sections[chunkY++];

                if (s.IsAir)
                {
                    nonAir = false;
                }
                if (nonAir)
                {
                    Array.Copy(s.Blocks, 0, blockData, (chunkY - 1) * BlockDataLength, BlockDataLength);
                    Array.Copy(s.Metadata.Data, 0, metadata, (chunkY - 1) * NibbleDataLength, NibbleDataLength);
                    Array.Copy(s.BlockLight.Data, 0, blockLight, (chunkY - 1) * NibbleDataLength, NibbleDataLength);
                    Array.Copy(s.SkyLight.Data, 0, skyLight, (chunkY - 1) * NibbleDataLength, NibbleDataLength);

                    PrimaryBitMap |= mask;
                }

                mask <<= 1;
            }

            // Create the final array
            // TODO: Merge this into the other loop, reduce objects
            byte[] data = new byte[blockData.Length + metadata.Length +
                                   blockLight.Length + skyLight.Length + chunk.Biomes.Length];
            int index = 0;

            Array.Copy(blockData, 0, data, index, blockData.Length);
            index += blockData.Length;
            Array.Copy(metadata, 0, data, index, metadata.Length);
            index += metadata.Length;
            Array.Copy(blockLight, 0, data, index, blockLight.Length);
            index += blockLight.Length;
            Array.Copy(skyLight, 0, data, index, skyLight.Length);
            index += skyLight.Length;
            Array.Copy(chunk.Biomes, 0, data, index, chunk.Biomes.Length);

            // Compress the array
            var result             = ZlibStream.CompressBuffer(data);
            var GroundUpContiguous = true;

            return(new ChunkDataPacket(X, Z, GroundUpContiguous, PrimaryBitMap, AddBitMap, result));
        }
Esempio n. 10
0
        public static ChunkDataPacket CreatePacket(Chunk chunk)
        {
            var packet = new ChunkDataPacket();

            var X = (int)chunk.AbsolutePosition.X;
            var Z = (int)chunk.AbsolutePosition.Z;

            byte[] blockData;
            byte[] metadata;
            byte[] blockLight;
            byte[] skyLight;

            ushort mask = 1, chunkY = 0;
            bool nonAir = true;

            // First pass calculates number of sections to send
            int totalSections = 0;
            for (int i = 15; i >= 0; i--)
            {
                Section s = chunk.Sections[chunkY++];

                if (s.IsAir)
                    nonAir = false;
                if (nonAir)
                    totalSections++;
            }

            mask = 1;
            chunkY = 0;
            nonAir = true;
            blockData = new byte[totalSections * BlockDataLength];
            metadata = new byte[totalSections * NibbleDataLength];
            blockLight = new byte[totalSections * NibbleDataLength];
            skyLight = new byte[totalSections * NibbleDataLength];

            ushort PrimaryBitMap = 0, AddBitMap = 0;

            // Second pass produces the arrays
            for (int i = 15; i >= 0; i--)
            {
                Section s = chunk.Sections[chunkY++];

                if (s.IsAir)
                    nonAir = false;
                if (nonAir)
                {
                    Array.Copy(s.Blocks, 0, blockData, (chunkY - 1) * BlockDataLength, BlockDataLength);
                    Array.Copy(s.Metadata.Data, 0, metadata, (chunkY - 1) * NibbleDataLength, NibbleDataLength);
                    Array.Copy(s.BlockLight.Data, 0, blockLight, (chunkY - 1) * NibbleDataLength, NibbleDataLength);
                    Array.Copy(s.SkyLight.Data, 0, skyLight, (chunkY - 1) * NibbleDataLength, NibbleDataLength);

                    PrimaryBitMap |= mask;
                }

                mask <<= 1;
            }

            // Create the final array
            // TODO: Merge this into the other loop, reduce objects
            byte[] data = new byte[blockData.Length + metadata.Length +
                blockLight.Length + skyLight.Length + chunk.Biomes.Length];
            int index = 0;
            Array.Copy(blockData, 0, data, index, blockData.Length);
            index += blockData.Length;
            Array.Copy(metadata, 0, data, index, metadata.Length);
            index += metadata.Length;
            Array.Copy(blockLight, 0, data, index, blockLight.Length);
            index += blockLight.Length;
            Array.Copy(skyLight, 0, data, index, skyLight.Length);
            index += skyLight.Length;
            Array.Copy(chunk.Biomes, 0, data, index, chunk.Biomes.Length);

            // Compress the array
            var result = ZlibStream.CompressBuffer(data);
            var GroundUpContiguous = true;

            return new ChunkDataPacket(X, Z, GroundUpContiguous, PrimaryBitMap, AddBitMap, result);
        }
Esempio n. 11
0
        public void Handle(int id, MemoryStream ms)
        {
            if (_loginSucces)
            {
                IPacket packet = null;
                switch (id)
                {
                case BlockChangePacket.PACKET_ID:
                    packet = new BlockChangePacket(ms);
                    break;

                case ChatMessagePacket.PACKET_ID:
                    packet = new ChatMessagePacket(ms);
                    break;

                case UpdateHealthPacket.PACKET_ID:
                    packet = new UpdateHealthPacket(ms);
                    break;

                case ChunkDataPacket.PACKET_ID:
                    packet = new ChunkDataPacket(ms);
                    break;

                case DisconnectPacket.PACKET_ID:
                    packet = new DisconnectPacket(ms);
                    break;

                case KeepAlivePacket.PACKET_ID:
                    packet = new KeepAlivePacket(ms);
                    break;

                case PlayerAbilitiesPacket.PACKET_ID:
                    packet = new PlayerAbilitiesPacket(ms);
                    break;

                case PlayerPositionAndLookPacket.PACKET_ID:
                    packet = new PlayerPositionAndLookPacket(ms);
                    break;

                case SpawnExperienceOrbPacket.PACKET_ID:
                    packet = new SpawnExperienceOrbPacket(ms);
                    break;

                case SpawnGlobalEntityPacket.PACKET_ID:
                    packet = new SpawnGlobalEntityPacket(ms);
                    break;

                case SpawnObjectPacket.PACKET_ID:
                    packet = new SpawnObjectPacket(ms);
                    break;

                case UnloadChunkPacket.PACKET_ID:
                    packet = new UnloadChunkPacket(ms);
                    break;

                case SpawnPositionPacket.PACKET_ID:
                    packet = new SpawnPositionPacket(ms);
                    break;
                }

                if (packet != null && PlayPacketReceivedEvent != null)
                {
                    this.PlayPacketReceivedEvent(packet);
                }
            }
            else
            {
                IPacket packet = null;
                switch (id)
                {
                case Packet.Clientbound.Login.DisconnectPacket.PACKET_ID:
                    packet = new Packet.Clientbound.Login.DisconnectPacket(ms);
                    break;

                case Packet.Clientbound.Login.LoginSuccessPacket.PACKET_ID:
                    packet = new Packet.Clientbound.Login.LoginSuccessPacket(ms);
                    break;

                case Packet.Clientbound.Login.SetCompressionPacket.PACKET_ID:
                    packet = new Packet.Clientbound.Login.SetCompressionPacket(ms);
                    break;
                }

                if (packet != null && LoginPacketReceivedEvent != null)
                {
                    this.LoginPacketReceivedEvent(packet);
                }
            }
            ms.Dispose();
        }
Esempio n. 12
0
 /// <summary>
 /// Creates a chunk from a <see cref="ChunkDataPacket"/> in the specified world
 /// </summary>
 /// <param name="packet"></param>
 /// <param name="world"></param>
 public Chunk(ChunkDataPacket packet, World world)
 {
     Position = packet.Position;
     World    = world;
     AddChunkData(packet);
 }
Esempio n. 13
0
    /// <summary>
    /// Adds chunk data to the world
    /// </summary>
    /// <param name="chunkData"></param>
    public IEnumerator AddChunkDataCoroutine(ChunkDataPacket chunkData)
    {
        Chunk chunk;

        lock (_chunks)
        {
            // if the chunk already exists, add data
            // otherwise, make a new chunk
            chunk = _chunks.Find(c => c.Position.Equals(chunkData.Position));
            if (chunk != null)              // chunk already exists
            {
                if (chunkData.GroundUpContinuous)
                {
                    Debug.LogWarning($"Packet data for chunk at {chunkData.Position} tried to load GroundUpContinuous for already loaded chunk!");
                    yield break;
                }
            }
            else
            {
                // need to create a new chunk
                chunk = new Chunk(chunkData.ChunkX, chunkData.ChunkZ, this);
                _chunks.Add(chunk);
                ChunkRenderer.AddChunk(chunk);
            }
        }

        while (_packetDecodeTasks.Count >= SystemInfo.processorCount)
        {
            yield return(null);
        }

        // add chunk data to chunk in another thread
        var task = Task.Run(() =>
        {
            Profiler.BeginThreadProfiling("Add chunk data", "chunk decoder worker");
            Profiler.BeginSample($"Add chunk data {chunk.ToString()}");
            chunk.AddChunkData(chunkData);
            Profiler.EndSample();
            Profiler.EndThreadProfiling();
        });

        _packetDecodeTasks.Add(task);

        // wait for task to complete
        while (!task.IsCompleted)
        {
            yield return(null);
        }

        _packetDecodeTasks.Remove(task);

        // check for exceptions
        if (task.IsFaulted)
        {
            throw task.Exception;
        }

        // regenerate chunk sections

        /* we don't use the bitmask provided in the packet here becase we want
         * to "render" all chunks, including empty ones, so that the game
         * knows they exist and aren't unloaded
         *
         * plus, the renderer won't render chunks above the bitmask provided in
         * this packet anyways due to the Chunk.MaxHeight property
         * */
        ChunkRenderer.MarkChunkForRegeneration(chunk, ChunkRenderer.ALL_SECTIONS);
    }