Search in sources :

Example 1 with ITileEntityRefreshBehavior

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

LanternBlockType (org.lanternpowered.server.block.LanternBlockType)1 TileEntityProvider (org.lanternpowered.server.block.TileEntityProvider)1 ITileEntityRefreshBehavior (org.lanternpowered.server.block.tile.ITileEntityRefreshBehavior)1 LanternTileEntity (org.lanternpowered.server.block.tile.LanternTileEntity)1 LanternWorld (org.lanternpowered.server.world.LanternWorld)1 BlockState (org.spongepowered.api.block.BlockState)1 World (org.spongepowered.api.world.World)1