Search in sources :

Example 1 with LanternTileEntity

use of org.lanternpowered.server.block.tile.LanternTileEntity 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 LanternTileEntity

use of org.lanternpowered.server.block.tile.LanternTileEntity in project LanternServer by LanternPowered.

the class TileEntitySerializer method serialize.

@Override
public DataView serialize(LanternTileEntity object) {
    final DataView dataView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
    dataView.set(ID, object.getType().getId());
    // noinspection unchecked
    final ObjectStore<LanternTileEntity> store = (ObjectStore) ObjectStoreRegistry.get().get(object.getClass()).get();
    store.serialize(object, dataView);
    return dataView;
}
Also used : DataView(org.spongepowered.api.data.DataView) ObjectStore(org.lanternpowered.server.data.io.store.ObjectStore) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity)

Example 3 with LanternTileEntity

use of org.lanternpowered.server.block.tile.LanternTileEntity in project LanternServer by LanternPowered.

the class TileEntitySerializer method deserialize.

@Override
public LanternTileEntity deserialize(DataView dataView) throws InvalidDataException {
    final String id = fixTileId(dataView, dataView.getString(ID).get());
    dataView.remove(ID);
    final LanternTileEntityType tileEntityType = (LanternTileEntityType) Sponge.getRegistry().getType(TileEntityType.class, id).orElseThrow(() -> new InvalidDataException("Unknown tile entity id: " + id));
    // noinspection unchecked
    final ObjectStore<LanternTileEntity> store = (ObjectStore) ObjectStoreRegistry.get().get(tileEntityType.getTileEntityType()).get();
    // noinspection unchecked
    final LanternTileEntity entity = (LanternTileEntity) tileEntityType.getTileEntityConstructor().get();
    store.deserialize(entity, dataView);
    return entity;
}
Also used : ObjectStore(org.lanternpowered.server.data.io.store.ObjectStore) LanternTileEntityType(org.lanternpowered.server.block.tile.LanternTileEntityType) InvalidDataException(org.spongepowered.api.data.persistence.InvalidDataException) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity)

Example 4 with LanternTileEntity

use of org.lanternpowered.server.block.tile.LanternTileEntity in project LanternServer by LanternPowered.

the class LanternChunk method pulse.

public void pulse() {
    // The update entry
    LanternScheduledBlockUpdate update;
    while ((update = this.scheduledBlockUpdateQueue.peek()) != null && update.getTicks() <= 0) {
        // Remove the entry from the queue
        this.scheduledBlockUpdateQueue.poll();
    // TODO: Update
    }
    final CauseStack causeStack = CauseStack.current();
    // Add the chunk that is being pulsed
    causeStack.pushCause(this);
    getTileEntities().forEach(tileEntity -> {
        // Add the tile entity to the cause
        causeStack.pushCause(tileEntity);
        try {
            ((LanternTileEntity) tileEntity).pulse();
        } catch (Throwable t) {
            final Vector3i pos = tileEntity.getLocation().getBlockPosition();
            Lantern.getLogger().error("Failed to pulse TileEntity at ({};{};{})", pos.getX(), pos.getY(), pos.getZ(), t);
        } finally {
            // Pop the tile entity
            causeStack.popCause();
        }
    });
    // Pop the chunk
    causeStack.popCause();
}
Also used : CauseStack(org.lanternpowered.server.event.CauseStack) LanternScheduledBlockUpdate(org.lanternpowered.server.block.LanternScheduledBlockUpdate) Vector3i(com.flowpowered.math.vector.Vector3i) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity)

Example 5 with LanternTileEntity

use of org.lanternpowered.server.block.tile.LanternTileEntity in project LanternServer by LanternPowered.

the class LanternChunk method setBlock.

@Override
public boolean setBlock(int x, int y, int z, BlockState block, BlockChangeFlag flag) {
    checkNotNull(block, "block");
    checkNotNull(flag, "flag");
    checkVolumeBounds(x, y, z);
    if (!this.loaded) {
        return false;
    }
    final short type = BlockRegistryModule.get().getStateInternalIdAndData(block);
    final short type1;
    // Air doesn't have metadata values
    if (type >> 4 == 0 && type != 0) {
        type1 = 0;
    } else {
        type1 = type;
    }
    final BlockState[] changeData = new BlockState[1];
    final int rx = x & 0xf;
    final int rz = z & 0xf;
    this.chunkSections.work(y >> 4, section -> {
        if (section == null) {
            // so we can fail fast
            if (type1 == 0) {
                return section;
            }
            // Create a new section
            section = new ChunkSection();
        }
        final int index = ChunkSection.index(rx, y & 0xf, rz);
        final short oldType = section.types[index];
        if (oldType == type1) {
            return section;
        }
        if (oldType != 0) {
            short count = section.typesCountMap.get(oldType);
            if (count > 0) {
                if (--count <= 0) {
                    section.typesCountMap.remove(oldType);
                } else {
                    section.typesCountMap.put(oldType, count);
                }
            }
        }
        if (type1 != 0) {
            section.typesCountMap.put(type1, (short) (section.typesCountMap.get(type1) + 1));
            if (oldType == 0) {
                section.nonAirCount++;
            }
        } else {
            section.nonAirCount--;
        }
        final BlockState oldState = BlockRegistryModule.get().getStateByInternalIdAndData(oldType).get();
        changeData[0] = oldState;
        // The section is empty, destroy it
        if (section.nonAirCount <= 0) {
            return null;
        }
        final LanternTileEntity tileEntity = section.tileEntities.get((short) index);
        boolean remove = false;
        boolean refresh = false;
        final Optional<TileEntityProvider> tileEntityProvider = ((LanternBlockType) block.getType()).getTileEntityProvider();
        if (tileEntity != null) {
            if (oldType == 0 || type1 == 0) {
                remove = true;
            } else if (tileEntity instanceof ITileEntityRefreshBehavior) {
                if (((ITileEntityRefreshBehavior) tileEntity).shouldRefresh(oldState, block)) {
                    remove = true;
                    refresh = true;
                }
            } else if (oldType >> 4 != type1 >> 4) {
                // The default behavior will only refresh if the
                // block type is changed and not the block state
                remove = true;
                refresh = true;
            }
            if (refresh && !tileEntityProvider.isPresent()) {
                refresh = false;
            }
        } else if (tileEntityProvider.isPresent()) {
            refresh = true;
        }
        if (remove) {
            tileEntity.setValid(false);
        }
        if (refresh) {
            final Location<World> location = tileEntity != null ? tileEntity.getLocation() : new Location<>(this.world, x, y, z);
            final LanternTileEntity newTileEntity = (LanternTileEntity) tileEntityProvider.get().get(block, location, null);
            section.tileEntities.put((short) index, newTileEntity);
            newTileEntity.setLocation(location);
            newTileEntity.setValid(true);
        } else if (remove) {
            section.tileEntities.remove((short) index);
        }
        section.types[index] = type1;
        return section;
    });
    final int index = rz << 4 | rx;
    long stamp = this.heightMapLock.writeLock();
    try {
        // TODO: Check first and then use the write lock?
        if (type != 0 && (this.heightMap[index] & 0xff) < y) {
            this.heightMap[index] = (byte) y;
            this.heightMapUpdateFlags.clear(index);
        } else if (type == 0 && (this.heightMap[index] & 0xff) == y) {
            this.heightMapUpdateFlags.set(index);
        }
    } finally {
        this.heightMapLock.unlock(stamp);
    }
    if (changeData[0] != null) {
        this.world.getEventListener().onBlockChange(x, y, z, changeData[0], block);
    }
    return true;
}
Also used : TileEntityProvider(org.lanternpowered.server.block.TileEntityProvider) World(org.spongepowered.api.world.World) LanternWorld(org.lanternpowered.server.world.LanternWorld) LanternBlockType(org.lanternpowered.server.block.LanternBlockType) BlockState(org.spongepowered.api.block.BlockState) ITileEntityRefreshBehavior(org.lanternpowered.server.block.tile.ITileEntityRefreshBehavior) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity)

Aggregations

LanternTileEntity (org.lanternpowered.server.block.tile.LanternTileEntity)7 DataView (org.spongepowered.api.data.DataView)3 InvalidDataException (org.spongepowered.api.data.persistence.InvalidDataException)3 Vector3i (com.flowpowered.math.vector.Vector3i)2 Short2ObjectMap (it.unimi.dsi.fastutil.shorts.Short2ObjectMap)2 Short2ObjectOpenHashMap (it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap)2 DataInputStream (java.io.DataInputStream)2 ObjectStore (org.lanternpowered.server.data.io.store.ObjectStore)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 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