Paste #59289: Untitled Paste

Date: 2019/10/23 13:13:08 UTC-07:00
Type: Plain Text

View Raw Paste Download This Paste
Copy Link


package com.denizenscript.denizen.nms.v1_14.impl.network.handlers;

import com.denizenscript.denizen.nms.util.ReflectionHelper;
import com.denizenscript.denizen.utilities.blocks.FakeBlock;
import com.denizenscript.denizen.utilities.debugging.Debug;
import io.netty.buffer.Unpooled;
import net.minecraft.server.v1_14_R1.*;
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;

import java.lang.reflect.Field;
import java.util.List;

public class FakeBlockHelper {

    public static Field BITMASK_MAPCHUNK = ReflectionHelper.getFields(PacketPlayOutMapChunk.class).get("c");
    public static Field HEIGHTMAPS_MAPCHUNK = ReflectionHelper.getFields(PacketPlayOutMapChunk.class).get("d");
    public static Field DATA_MAPCHUNK = ReflectionHelper.getFields(PacketPlayOutMapChunk.class).get("e");
    public static Field BLOCKENTITIES_MAPCHUNK = ReflectionHelper.getFields(PacketPlayOutMapChunk.class).get("f");

    public static IBlockData getNMSState(FakeBlock block) {
        return ((CraftBlockData) block.material.getModernData().data).getState();
    }

    public static boolean anyBlocksInSection(List<FakeBlock> blocks, int y) {
        int minY = y << 4;
        int maxY = (y << 4) + 16;
        for (FakeBlock block : blocks) {
            int blockY = block.location.getBlockY();
            if (blockY >= minY && blockY < maxY) {
                return true;
            }
        }
        return false;
    }

    public static void pushByteArrayToLongArray(byte[] bits, long[] longs) {
        for (int i = 0; i < bits.length; i++) {
            int longIndex = i >> 8;
            int startBit = longIndex * 8;
            longs[longIndex] |= ((long) bits[i]) << (i - startBit);
        }
    }

    public static IBlockData blockInPalette(int paletteId) {
        return ChunkSection.GLOBAL_PALETTE.a(paletteId);
    }

    public static void handleMapChunkPacket(PacketPlayOutMapChunk packet, List<FakeBlock> blocks) {
        try {
            // TODO: properly update HeightMap?
            int bitmask = BITMASK_MAPCHUNK.getInt(packet);
            byte[] data = (byte[]) DATA_MAPCHUNK.get(packet);
            PacketDataSerializer serial = new PacketDataSerializer(Unpooled.wrappedBuffer(data));
            PacketDataSerializer outputSerial = new PacketDataSerializer(Unpooled.buffer(data.length));
            byte[] blockDataHelper = new byte[8 * 16 * 16 * 16];
            boolean isFull = packet.f();
            List<NBTTagCompound> blockEntities = (List<NBTTagCompound>) BLOCKENTITIES_MAPCHUNK.get(packet);
            NBTTagList blockEntitiesList = new NBTTagList();
            blockEntitiesList.addAll(blockEntities);
            for (int y = 0; y < 16; y++) {
                if ((bitmask & (1 << y)) != 0) {
                    int blockCount = serial.readShort();
                    int width = serial.readUnsignedByte();
                    int paletteLen = serial.i(); // readVarInt
                    int[] palette = new int[paletteLen];
                    for (int p = 0; p < paletteLen; p++) {
                        palette[p] = serial.i();
                    }
                    int dataLen = serial.i();
                    Debug.log("y: " + y + " count: " + blockCount + ", width: " + width + ", paletteLen: " + paletteLen + ", dataLen: " + dataLen);
                    serial.readBytes(blockDataHelper, 0, 512 * width);
                    outputSerial.writeShort(blockCount);
                    if (!anyBlocksInSection(blocks, y)) {
                        outputSerial.writeByte(width);
                        outputSerial.d(paletteLen); // writeVarInt
                        for (int p = 0; p < paletteLen; p++) {
                            outputSerial.d(palette[p]);
                        }
                        outputSerial.d(dataLen);
                        outputSerial.writeBytes(blockDataHelper, 0, 512 * width);
                        continue;
                    }
                    long[] blockListHelper = new long[width * (512 / 8)];
                    pushByteArrayToLongArray(blockDataHelper, blockListHelper);
                    DataPaletteBlock<IBlockData> blockPalette = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE,
                            Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData());
                    for (int p = 0; p < paletteLen; p++) {
                        // Workaround to stick the existing types into the palette
                        blockPalette.setBlock(0, 0, 0, blockInPalette(palette[p]));
                    }
                    blockPalette.a(blockEntitiesList, blockListHelper);
                    int minY = y << 4;
                    int maxY = (y << 4) + 16;
                    for (FakeBlock block : blocks) {
                        int blockY = block.location.getBlockY();
                        if (blockY >= minY && blockY < maxY) {
                            int blockX = block.location.getBlockX();
                            int blockZ = block.location.getBlockZ();
                            blockX -= (blockX >> 4) * 16;
                            blockY -= (blockY >> 4) * 16;
                            blockZ -= (blockZ >> 4) * 16;
                            blockPalette.setBlock(blockX, blockY, blockZ, getNMSState(block));
                        }
                    }
                    blockPalette.b(outputSerial);
                }
            }
            if (isFull) {
                // biomes
                outputSerial.writeBytes(serial, 256 * 4);
            }
            byte[] outputBytes = outputSerial.array();
            DATA_MAPCHUNK.set(packet, outputBytes);
        }
        catch (Exception ex) {
            Debug.echoError(ex);
        }
    }
}