Search in sources :

Example 1 with Short2ObjectMap

use of it.unimi.dsi.fastutil.shorts.Short2ObjectMap in project LanternServer by LanternPowered.

the class AnvilChunkIOService method read.

@Override
public boolean read(LanternChunk chunk) throws IOException {
    final int x = chunk.getX();
    final int z = chunk.getZ();
    final RegionFile region = this.cache.getRegionFileByChunk(x, z);
    final int regionX = x & REGION_MASK;
    final int regionZ = z & REGION_MASK;
    final DataInputStream is = region.getChunkDataInputStream(regionX, regionZ);
    if (is == null) {
        return false;
    }
    final DataView levelDataView;
    try (NbtDataContainerInputStream nbt = new NbtDataContainerInputStream(is)) {
        levelDataView = nbt.read().getView(LEVEL).get();
    }
    // read the vertical sections
    final List<DataView> sectionList = levelDataView.getViewList(SECTIONS).get();
    final ChunkSection[] sections = new ChunkSection[16];
    // noinspection unchecked
    final Short2ObjectOpenHashMap<LanternTileEntity>[] tileEntitySections = new Short2ObjectOpenHashMap[sections.length];
    for (DataView sectionTag : sectionList) {
        final int y = sectionTag.getInt(Y).get();
        final byte[] rawTypes = (byte[]) sectionTag.get(BLOCKS).get();
        final byte[] extTypes = sectionTag.contains(BLOCKS_EXTRA) ? (byte[]) sectionTag.get(BLOCKS_EXTRA).get() : null;
        final byte[] data = (byte[]) sectionTag.get(DATA).get();
        final byte[] blockLight = (byte[]) sectionTag.get(BLOCK_LIGHT).get();
        final byte[] skyLight = (byte[]) sectionTag.get(SKY_LIGHT).get();
        final NibbleArray dataArray = new NibbleArray(rawTypes.length, data, true);
        final NibbleArray extTypesArray = extTypes == null ? null : new NibbleArray(rawTypes.length, extTypes, true);
        final short[] types = new short[rawTypes.length];
        for (int i = 0; i < rawTypes.length; i++) {
            types[i] = (short) ((extTypesArray == null ? 0 : extTypesArray.get(i)) << 12 | ((rawTypes[i] & 0xff) << 4) | dataArray.get(i));
        }
        tileEntitySections[y] = new Short2ObjectOpenHashMap<>();
        sections[y] = new ChunkSection(types, new NibbleArray(rawTypes.length, skyLight, true), new NibbleArray(rawTypes.length, blockLight, true), tileEntitySections[y]);
    }
    levelDataView.getViewList(TILE_ENTITIES).ifPresent(tileEntityViews -> {
        final ObjectSerializer<LanternTileEntity> tileEntitySerializer = ObjectSerializerRegistry.get().get(LanternTileEntity.class).get();
        for (DataView tileEntityView : tileEntityViews) {
            final int tileY = tileEntityView.getInt(TILE_ENTITY_Y).get();
            final int section = tileY >> 4;
            if (tileEntitySections[section] == null) {
                continue;
            }
            final int tileZ = tileEntityView.getInt(TILE_ENTITY_Z).get();
            final int tileX = tileEntityView.getInt(TILE_ENTITY_X).get();
            try {
                final LanternTileEntity tileEntity = tileEntitySerializer.deserialize(tileEntityView);
                tileEntity.setLocation(new Location<>(this.world, tileX, tileY, tileZ));
                tileEntity.setValid(true);
                tileEntitySections[section].put((short) ChunkSection.index(tileX & 0xf, tileY & 0xf, tileZ & 0xf), tileEntity);
            } catch (InvalidDataException e) {
                this.logger.warn("Error loading tile entity at ({};{};{}) in the chunk ({},{}) in the world {}", tileX & 0xf, tileY & 0xf, tileZ & 0xf, x, z, getWorldProperties().getWorldName(), e);
            }
        }
    });
    final DataView spongeDataView = levelDataView.getView(DataQueries.SPONGE_DATA).orElse(null);
    final List<DataView> trackerDataViews = spongeDataView == null ? null : levelDataView.getViewList(TRACKER_DATA_TABLE).orElse(null);
    // noinspection unchecked
    final Short2ObjectMap<LanternChunk.TrackerData>[] trackerData = chunk.getTrackerData().getRawObjects();
    if (trackerDataViews != null) {
        for (DataView dataView : trackerDataViews) {
            final Optional<Short> optIndex = dataView.getShort(TRACKER_BLOCK_POS);
            if (!optIndex.isPresent()) {
                continue;
            }
            final int creatorId = dataView.getInt(TRACKER_ENTRY_CREATOR).orElse(-1);
            final int notifierId = dataView.getInt(TRACKER_ENTRY_NOTIFIER).orElse(-1);
            // index = z << 12 | y << 4 | x
            int index = optIndex.get() & 0xffff;
            final int section = (index >> 8) & 0xf;
            // Convert the index to the section based system
            // index = y << 8 | z << 4 | x
            index = ChunkSection.index(index & 0xf, (index >> 4) & 0xf, index >> 12);
            trackerData[section].put((short) index, new LanternChunk.TrackerData(creatorId, notifierId));
        }
    }
    // initialize the chunk
    chunk.initializeSections(sections);
    chunk.setPopulated(levelDataView.getInt(TERRAIN_POPULATED).orElse(0) > 0);
    if (levelDataView.contains(BIOMES)) {
        final byte[] biomes = (byte[]) levelDataView.get(BIOMES).get();
        final byte[] biomesExtra = (byte[]) (levelDataView.contains(BIOMES_EXTRA) ? levelDataView.get(BIOMES_EXTRA).get() : null);
        final short[] newBiomes = new short[biomes.length];
        for (int i = 0; i < biomes.length; i++) {
            newBiomes[i] = (short) ((biomesExtra == null ? 0 : biomesExtra[i]) << 8 | biomes[i]);
        }
        chunk.initializeBiomes(newBiomes);
    }
    final Object heightMap;
    if (levelDataView.contains(HEIGHT_MAP) && (heightMap = levelDataView.get(HEIGHT_MAP).get()) instanceof int[]) {
        chunk.initializeHeightMap((int[]) heightMap);
    } else {
        chunk.initializeHeightMap(null);
    }
    levelDataView.getLong(INHABITED_TIME).ifPresent(time -> chunk.setInhabitedTime(time.intValue()));
    chunk.setLightPopulated(levelDataView.getInt(LIGHT_POPULATED).orElse(0) > 0);
    chunk.initializeLight();
    levelDataView.getViewList(ENTITIES).ifPresent(entityViews -> {
        final ObjectSerializer<LanternEntity> entitySerializer = ObjectSerializerRegistry.get().get(LanternEntity.class).get();
        for (DataView entityView : entityViews) {
            try {
                final LanternEntity entity = entitySerializer.deserialize(entityView);
                final int ySection = fixEntityYSection(entity.getPosition().getFloorY() >> 4);
                chunk.addEntity(entity, ySection);
            } catch (InvalidDataException e) {
                this.logger.warn("Error loading entity in the chunk ({},{}) in the world {}", x, z, getWorldProperties().getWorldName(), e);
            }
        }
    });
    return true;
}
Also used : NbtDataContainerInputStream(org.lanternpowered.server.data.persistence.nbt.NbtDataContainerInputStream) Short2ObjectOpenHashMap(it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap) LanternChunk(org.lanternpowered.server.world.chunk.LanternChunk) NibbleArray(org.lanternpowered.server.util.collect.array.NibbleArray) InvalidDataException(org.spongepowered.api.data.persistence.InvalidDataException) LanternEntity(org.lanternpowered.server.entity.LanternEntity) DataInputStream(java.io.DataInputStream) Short2ObjectMap(it.unimi.dsi.fastutil.shorts.Short2ObjectMap) DataView(org.spongepowered.api.data.DataView) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity) ChunkSection(org.lanternpowered.server.world.chunk.LanternChunk.ChunkSection)

Example 2 with Short2ObjectMap

use of it.unimi.dsi.fastutil.shorts.Short2ObjectMap in project LanternServer by LanternPowered.

the class CodecPlayOutChunkData method encode.

@Override
public ByteBuffer encode(CodecContext context, MessagePlayOutChunkData message) throws CodecException {
    final MessagePlayOutChunkData.Section[] sections = message.getSections();
    final byte[] biomes = message.getBiomes();
    final int x = message.getX();
    final int z = message.getZ();
    final ByteBuffer buf = context.byteBufAlloc().buffer();
    buf.writeInteger(message.getX());
    buf.writeInteger(message.getZ());
    buf.writeBoolean(biomes != null);
    int sectionBitmask = 0;
    final ByteBuffer dataBuf = context.byteBufAlloc().buffer();
    ByteBuffer tileEntitiesBuf = null;
    int tileEntitiesCount = 0;
    for (int i = 0; i < sections.length; i++) {
        if (sections[i] == null) {
            continue;
        }
        sectionBitmask |= 1 << i;
        final MessagePlayOutChunkData.Section section = sections[i];
        final VariableValueArray types = section.getTypes();
        dataBuf.writeByte((byte) types.getBitsPerValue());
        final int[] palette = section.getPalette();
        if (palette != null) {
            dataBuf.writeVarInt(palette.length);
            for (int value : palette) {
                dataBuf.writeVarInt(value);
            }
        } else {
            // Using global palette
            dataBuf.writeVarInt(0);
        }
        final long[] backing = types.getBacking();
        dataBuf.writeVarInt(backing.length);
        final byte[] blockLight = section.getBlockLight();
        final byte[] skyLight = section.getSkyLight();
        dataBuf.ensureWritable(backing.length * 8 + blockLight.length + (skyLight != null ? skyLight.length : 0));
        for (long value : backing) {
            dataBuf.writeLong(value);
        }
        dataBuf.writeBytes(blockLight);
        if (skyLight != null) {
            dataBuf.writeBytes(skyLight);
        }
        final Short2ObjectMap<DataView> tileEntities = section.getTileEntities();
        if (!tileEntities.isEmpty() && tileEntitiesBuf == null) {
            tileEntitiesBuf = context.byteBufAlloc().buffer();
        }
        for (Short2ObjectMap.Entry<DataView> tileEntityEntry : tileEntities.short2ObjectEntrySet()) {
            tileEntitiesCount++;
            final int index = tileEntityEntry.getShortKey() & 0xffff;
            final DataView dataView = tileEntityEntry.getValue();
            dataView.set(X, x * 16 + (index & 0xf));
            dataView.set(Y, i << 4 | index >> 8);
            dataView.set(Z, z * 16 + ((index >> 4) & 0xf));
            // noinspection ConstantConditions
            tileEntitiesBuf.writeDataView(dataView);
        }
    }
    if (biomes != null) {
        dataBuf.writeBytes(biomes);
    }
    buf.writeVarInt(sectionBitmask);
    buf.writeVarInt(dataBuf.writerIndex());
    try {
        buf.writeBytes(dataBuf);
    } finally {
        dataBuf.release();
    }
    buf.writeVarInt(tileEntitiesCount);
    if (tileEntitiesBuf != null) {
        try {
            buf.writeBytes(tileEntitiesBuf);
        } finally {
            tileEntitiesBuf.release();
        }
    }
    return buf;
}
Also used : VariableValueArray(org.lanternpowered.server.util.collect.array.VariableValueArray) MessagePlayOutChunkData(org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayOutChunkData) ByteBuffer(org.lanternpowered.server.network.buffer.ByteBuffer) Short2ObjectMap(it.unimi.dsi.fastutil.shorts.Short2ObjectMap) DataView(org.spongepowered.api.data.DataView)

Example 3 with Short2ObjectMap

use of it.unimi.dsi.fastutil.shorts.Short2ObjectMap in project LanternServer by LanternPowered.

the class AnvilChunkIOService method write.

@Override
public void write(LanternChunk chunk) throws IOException {
    final int x = chunk.getX();
    final int z = chunk.getZ();
    final RegionFile region = this.cache.getRegionFileByChunk(x, z);
    final int regionX = x & REGION_MASK;
    final int regionZ = z & REGION_MASK;
    final DataContainer rootView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
    final DataView levelDataView = rootView.createView(LEVEL);
    // Core properties
    levelDataView.set(VERSION, (byte) 1);
    levelDataView.set(X, chunk.getX());
    levelDataView.set(Z, chunk.getZ());
    levelDataView.set(TERRAIN_POPULATED, (byte) (chunk.isPopulated() ? 1 : 0));
    levelDataView.set(LIGHT_POPULATED, (byte) (chunk.isLightPopulated() ? 1 : 0));
    levelDataView.set(LAST_UPDATE, 0L);
    levelDataView.set(INHABITED_TIME, chunk.getLongInhabitedTime());
    // Chunk sections
    final ChunkSectionSnapshot[] sections = chunk.getSectionSnapshots(true);
    final List<DataView> sectionDataViews = new ArrayList<>();
    final List<DataView> tileEntityDataViews = new ArrayList<>();
    for (byte i = 0; i < sections.length; ++i) {
        final ChunkSectionSnapshot section = sections[i];
        if (section == null) {
            continue;
        }
        final DataContainer sectionDataView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
        sectionDataView.set(Y, i);
        final byte[] rawTypes = new byte[section.types.length];
        final short[] types = section.types;
        NibbleArray extTypes = null;
        final NibbleArray data = new NibbleArray(rawTypes.length);
        for (int j = 0; j < rawTypes.length; j++) {
            rawTypes[j] = (byte) ((types[j] >> 4) & 0xff);
            byte extType = (byte) (types[j] >> 12);
            if (extType != 0) {
                if (extTypes == null) {
                    extTypes = new NibbleArray(rawTypes.length);
                }
                extTypes.set(j, extType);
            }
            data.set(j, (byte) (types[j] & 0xf));
        }
        sectionDataView.set(BLOCKS, rawTypes);
        if (extTypes != null) {
            sectionDataView.set(BLOCKS_EXTRA, extTypes.getPackedArray());
        }
        sectionDataView.set(DATA, data.getPackedArray());
        sectionDataView.set(BLOCK_LIGHT, section.lightFromBlock);
        final byte[] lightFromSky = section.lightFromSky;
        if (lightFromSky != null) {
            sectionDataView.set(SKY_LIGHT, lightFromSky);
        }
        sectionDataViews.add(sectionDataView);
        // noinspection unchecked
        final ObjectSerializer<LanternTileEntity> tileEntitySerializer = ObjectSerializerRegistry.get().get(LanternTileEntity.class).get();
        // Serialize the tile entities
        for (Short2ObjectMap.Entry<LanternTileEntity> tileEntityEntry : section.tileEntities.short2ObjectEntrySet()) {
            if (!tileEntityEntry.getValue().isValid()) {
                continue;
            }
            final DataView dataView = tileEntitySerializer.serialize(tileEntityEntry.getValue());
            final short pos = tileEntityEntry.getShortKey();
            dataView.set(TILE_ENTITY_X, x * 16 + (pos & 0xf));
            dataView.set(TILE_ENTITY_Y, (i << 4) | (pos >> 8));
            dataView.set(TILE_ENTITY_Z, z * 16 + ((pos >> 4) & 0xf));
            tileEntityDataViews.add(dataView);
        }
    }
    levelDataView.set(TILE_ENTITIES, tileEntityDataViews);
    levelDataView.set(SECTIONS, sectionDataViews);
    levelDataView.set(HEIGHT_MAP, chunk.getHeightMap());
    // noinspection unchecked
    final Short2ObjectMap<LanternChunk.TrackerData>[] trackerData = chunk.getTrackerData().getRawObjects();
    final List<DataView> trackerDataViews = new ArrayList<>();
    for (int i = 0; i < trackerData.length; i++) {
        final Short2ObjectMap<LanternChunk.TrackerData> trackerDataSection = trackerData[i];
        for (Short2ObjectMap.Entry<LanternChunk.TrackerData> entry : trackerDataSection.short2ObjectEntrySet()) {
            // index = y << 8 | z << 4 | x
            int index = entry.getShortKey() & 0xffff;
            // Convert the index to the column based system
            // index = z << 12 | y << 4 | x
            index = ((index >> 4) & 0xf) << 12 | i << 8 | (index >> 4) & 0xf0 | index & 0xf;
            final DataView trackerDataView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
            trackerDataView.set(TRACKER_BLOCK_POS, (short) index);
            trackerDataView.set(TRACKER_ENTRY_NOTIFIER, entry.getValue().getNotifierId());
            trackerDataView.set(TRACKER_ENTRY_CREATOR, entry.getValue().getCreatorId());
            trackerDataViews.add(trackerDataView);
        }
    }
    if (!trackerDataViews.isEmpty()) {
        levelDataView.createView(DataQueries.SPONGE_DATA).set(TRACKER_DATA_TABLE, trackerDataViews);
    }
    final short[] biomes = chunk.getBiomes();
    final byte[] biomes0 = new byte[biomes.length];
    byte[] biomes1 = null;
    for (int i = 0; i < biomes.length; i++) {
        biomes0[i] = (byte) (biomes[i] & 0xff);
        byte value = (byte) ((biomes[i] >> 4) & 0xff);
        if (value != 0) {
            if (biomes1 == null) {
                biomes1 = new byte[biomes0.length];
            }
            biomes1[i] = value;
        }
    }
    levelDataView.set(BIOMES, biomes0);
    if (biomes1 != null) {
        levelDataView.set(BIOMES_EXTRA, biomes1);
    }
    // noinspection unchecked
    final List<LanternEntity> entities = new ArrayList(chunk.getEntities(entity -> !(entity instanceof Player)));
    final ObjectSerializer<LanternEntity> entitySerializer = ObjectSerializerRegistry.get().get(LanternEntity.class).get();
    final List<DataView> entityViews = new ArrayList<>();
    for (LanternEntity entity : entities) {
        if (entity.getRemoveState() == LanternEntity.RemoveState.DESTROYED) {
            continue;
        }
        final DataView entityView = entitySerializer.serialize(entity);
        entityViews.add(entityView);
    }
    levelDataView.set(ENTITIES, entityViews);
    try (NbtDataContainerOutputStream nbt = new NbtDataContainerOutputStream(region.getChunkDataOutputStream(regionX, regionZ))) {
        nbt.write(rootView);
        nbt.flush();
    }
}
Also used : DataInputStream(java.io.DataInputStream) REGION_SIZE(org.lanternpowered.server.data.io.anvil.RegionFileCache.REGION_SIZE) ObjectSerializerRegistry(org.lanternpowered.server.data.io.store.ObjectSerializerRegistry) LanternEntity(org.lanternpowered.server.entity.LanternEntity) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity) ChunkSection(org.lanternpowered.server.world.chunk.LanternChunk.ChunkSection) Inject(com.google.inject.Inject) LanternChunk(org.lanternpowered.server.world.chunk.LanternChunk) CompletableFuture(java.util.concurrent.CompletableFuture) DataQuery(org.spongepowered.api.data.DataQuery) DataQueries(org.lanternpowered.server.data.DataQueries) ArrayList(java.util.ArrayList) Matcher(java.util.regex.Matcher) DirectoryKeys(org.lanternpowered.server.game.DirectoryKeys) LanternScheduler(org.lanternpowered.server.scheduler.LanternScheduler) ChunkIOService(org.lanternpowered.server.data.io.ChunkIOService) NoSuchElementException(java.util.NoSuchElementException) LanternChunk.fixEntityYSection(org.lanternpowered.server.world.chunk.LanternChunk.fixEntityYSection) Path(java.nio.file.Path) Nullable(javax.annotation.Nullable) Location(org.spongepowered.api.world.Location) Short2ObjectOpenHashMap(it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap) Logger(org.slf4j.Logger) ObjectSerializer(org.lanternpowered.server.data.io.store.ObjectSerializer) Files(java.nio.file.Files) NibbleArray(org.lanternpowered.server.util.collect.array.NibbleArray) DataContainer(org.spongepowered.api.data.DataContainer) InvalidDataException(org.spongepowered.api.data.persistence.InvalidDataException) IOException(java.io.IOException) REGION_AREA(org.lanternpowered.server.data.io.anvil.RegionFileCache.REGION_AREA) ChunkSectionSnapshot(org.lanternpowered.server.world.chunk.LanternChunk.ChunkSectionSnapshot) ChunkDataStream(org.spongepowered.api.world.storage.ChunkDataStream) List(java.util.List) Short2ObjectMap(it.unimi.dsi.fastutil.shorts.Short2ObjectMap) REGION_MASK(org.lanternpowered.server.data.io.anvil.RegionFileCache.REGION_MASK) NbtDataContainerInputStream(org.lanternpowered.server.data.persistence.nbt.NbtDataContainerInputStream) DataView(org.spongepowered.api.data.DataView) Vector3i(com.flowpowered.math.vector.Vector3i) World(org.spongepowered.api.world.World) WorldProperties(org.spongepowered.api.world.storage.WorldProperties) Optional(java.util.Optional) Named(com.google.inject.name.Named) Player(org.spongepowered.api.entity.living.player.Player) NbtDataContainerOutputStream(org.lanternpowered.server.data.persistence.nbt.NbtDataContainerOutputStream) Singleton(com.google.inject.Singleton) ArrayList(java.util.ArrayList) LanternChunk(org.lanternpowered.server.world.chunk.LanternChunk) DataContainer(org.spongepowered.api.data.DataContainer) NibbleArray(org.lanternpowered.server.util.collect.array.NibbleArray) NbtDataContainerOutputStream(org.lanternpowered.server.data.persistence.nbt.NbtDataContainerOutputStream) ChunkSectionSnapshot(org.lanternpowered.server.world.chunk.LanternChunk.ChunkSectionSnapshot) LanternEntity(org.lanternpowered.server.entity.LanternEntity) Player(org.spongepowered.api.entity.living.player.Player) Short2ObjectMap(it.unimi.dsi.fastutil.shorts.Short2ObjectMap) DataView(org.spongepowered.api.data.DataView) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity)

Aggregations

Short2ObjectMap (it.unimi.dsi.fastutil.shorts.Short2ObjectMap)3 DataView (org.spongepowered.api.data.DataView)3 Short2ObjectOpenHashMap (it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap)2 DataInputStream (java.io.DataInputStream)2 LanternTileEntity (org.lanternpowered.server.block.tile.LanternTileEntity)2 NbtDataContainerInputStream (org.lanternpowered.server.data.persistence.nbt.NbtDataContainerInputStream)2 LanternEntity (org.lanternpowered.server.entity.LanternEntity)2 NibbleArray (org.lanternpowered.server.util.collect.array.NibbleArray)2 LanternChunk (org.lanternpowered.server.world.chunk.LanternChunk)2 ChunkSection (org.lanternpowered.server.world.chunk.LanternChunk.ChunkSection)2 Vector3i (com.flowpowered.math.vector.Vector3i)1 Inject (com.google.inject.Inject)1 Singleton (com.google.inject.Singleton)1 Named (com.google.inject.name.Named)1 IOException (java.io.IOException)1 Files (java.nio.file.Files)1 Path (java.nio.file.Path)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 NoSuchElementException (java.util.NoSuchElementException)1