package net.glowstone.block.blocktype; import net.glowstone.block.GlowBlock; import net.glowstone.block.GlowBlockState; import net.glowstone.entity.GlowPlayer; import org.bukkit.Material; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import java.util.*; public class BlockRails extends BlockNeedsAttached { private static final int NORTH = 0; private static final int SOUTH = 1; private static final int EAST = 2; private static final int WEST = 3; private static final int ASCENDING_NORTH = 4; private static final int ASCENDING_SOUTH = 5; private static final int ASCENDING_EAST = 6; private static final int ASCENDING_WEST = 7; @Override public Collection<ItemStack> getDrops(GlowBlock block, ItemStack tool) { return Arrays.asList(new ItemStack(block.getType())); } @Override public void placeBlock(GlowPlayer player, GlowBlockState state, BlockFace face, ItemStack holding, Vector clickedLoc) { super.placeBlock(player, state, face, holding, clickedLoc); GlowBlock block = state.getBlock(); RailDirection direction = getRailDirection(block); state.setRawData((byte) direction.ordinal()); state.update(true, false); updateNeighbors(block, direction); } private void updateNeighbors(GlowBlock block, RailDirection direction) { direction.getNeighborRails(block).forEach(rail -> { // check if the rail is stable if (isUnstable(rail, block) && !isConnected(rail, block)) { rail.setData((byte) getRailDirection(rail).ordinal()); } }); } private static boolean isConnected(GlowBlock rail, GlowBlock neighborRail) { return RailDirection.getRailDirection(rail).getNeighborRails(rail).contains(neighborRail) && RailDirection.getRailDirection(neighborRail).getNeighborRails(neighborRail).contains(rail); } private static boolean isUnstable(GlowBlock block, GlowBlock neighborRail) { if (!isRailBlock(block)) { return false; } Set<GlowBlock> neighborRails = RailDirection.getRailDirection(block).getNeighborRails(block); // equals because blocks at the same location are not the same at the moment. // TODO: !rail.equals(neighborRail) -> rail != neighborRail return neighborRails.stream().filter(rail -> !rail.equals(neighborRail) && isConnected(block, rail)).count() != 2; } private static RailDirection getRailDirection(GlowBlock rail) { // north - 0, south - 1, east - 2, west - 3, ascending_north - 4, ascending_south - 5, ascending_east - 6, ascending_west - 7 boolean[] unstableRails = new boolean[8]; GlowBlock north = rail.getRelative(BlockFace.NORTH); GlowBlock south = rail.getRelative(BlockFace.SOUTH); GlowBlock east = rail.getRelative(BlockFace.EAST); GlowBlock west = rail.getRelative(BlockFace.WEST); unstableRails[NORTH] = isUnstable(north, rail) || isUnstable(north.getRelative(BlockFace.DOWN), rail); unstableRails[SOUTH] = isUnstable(south, rail) || isUnstable(south.getRelative(BlockFace.DOWN), rail); unstableRails[EAST] = isUnstable(east, rail) || isUnstable(east.getRelative(BlockFace.DOWN), rail); unstableRails[WEST] = isUnstable(west, rail) || isUnstable(west.getRelative(BlockFace.DOWN), rail); unstableRails[ASCENDING_NORTH] = isUnstable(north.getRelative(BlockFace.UP), rail); unstableRails[ASCENDING_SOUTH] = isUnstable(south.getRelative(BlockFace.UP), rail); unstableRails[ASCENDING_WEST] = isUnstable(east.getRelative(BlockFace.UP), rail); unstableRails[ASCENDING_EAST] = isUnstable(west.getRelative(BlockFace.UP), rail); // north && east || ascending_north && ascending_east || north && ascending_east || ascending_north && east if (unstableRails[NORTH] && unstableRails[EAST] || unstableRails[ASCENDING_NORTH] && unstableRails[ASCENDING_EAST] || unstableRails[NORTH] && unstableRails[ASCENDING_EAST] || unstableRails[ASCENDING_NORTH] && unstableRails[EAST]) { return RailDirection.NORTH_EAST; } // north && west || ascending_north && ascending_west || north && ascending_west || ascending_north && west if (unstableRails[NORTH] && unstableRails[WEST] || unstableRails[ASCENDING_NORTH] && unstableRails[ASCENDING_WEST] || unstableRails[NORTH] && unstableRails[ASCENDING_WEST] || unstableRails[ASCENDING_NORTH] && unstableRails[WEST]) { return RailDirection.NORTH_WEST; } // south && west || ascending_south && ascending_west || south && ascending_west || ascending_south && west if (unstableRails[SOUTH] && unstableRails[WEST] || unstableRails[ASCENDING_SOUTH] && unstableRails[ASCENDING_WEST] || unstableRails[SOUTH] && unstableRails[ASCENDING_WEST] || unstableRails[ASCENDING_SOUTH] && unstableRails[WEST]) { return RailDirection.SOUTH_WEST; } // south && east || ascending_south && ascending_east || south && ascending_east || ascending_south && east if (unstableRails[SOUTH] && unstableRails[EAST] || unstableRails[ASCENDING_SOUTH] && unstableRails[ASCENDING_EAST] || unstableRails[SOUTH] && unstableRails[ASCENDING_EAST] || unstableRails[ASCENDING_SOUTH] && unstableRails[EAST]) { return RailDirection.SOUTH_EAST; } // ascending_north && south || ascending_north if (unstableRails[ASCENDING_NORTH] && unstableRails[SOUTH] || unstableRails[ASCENDING_NORTH]) { return RailDirection.ASCENDING_NORTH; } // ascending_south && north || ascending_south if (unstableRails[ASCENDING_SOUTH] && unstableRails[NORTH] || unstableRails[ASCENDING_SOUTH]) { return RailDirection.ASCENDING_SOUTH; } // ascending_east && west || ascending_east if (unstableRails[ASCENDING_EAST] && unstableRails[WEST] || unstableRails[ASCENDING_EAST]) { return RailDirection.ASCENDING_EAST; } // ascending_west && east || ascending_west if (unstableRails[ASCENDING_WEST] && unstableRails[EAST] || unstableRails[ASCENDING_WEST]) { return RailDirection.ASCENDING_WEST; } // north || south if (unstableRails[NORTH] || unstableRails[SOUTH]) { return RailDirection.NORTH_SOUTH; } // east || west if (unstableRails[EAST] || unstableRails[WEST]) { return RailDirection.EAST_WEST; } // return current rail direction. return RailDirection.getRailDirection(rail); } private static boolean isRailBlock(GlowBlock block) { return block.getType() == Material.RAILS; } private enum RailDirection { NORTH_SOUTH { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock north = rail.getRelative(BlockFace.NORTH); GlowBlock south = rail.getRelative(BlockFace.SOUTH); if (isRailBlock(north)) { rails.add(north); } if (isRailBlock(south)) { rails.add(south); } if (rails.size() != 2) { GlowBlock descendingNorth = north.getRelative(BlockFace.DOWN); GlowBlock descendingSouth = south.getRelative(BlockFace.DOWN); if (isRailBlock(descendingNorth)) { rails.add(descendingNorth); } if (isRailBlock(descendingSouth)) { rails.add(descendingSouth); } } return rails; } }, EAST_WEST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock east = rail.getRelative(BlockFace.EAST); GlowBlock west = rail.getRelative(BlockFace.WEST); if (isRailBlock(east)) { rails.add(east); } if (isRailBlock(west)) { rails.add(west); } if (rails.size() != 2) { GlowBlock descendingEast = east.getRelative(BlockFace.DOWN); GlowBlock descendingWest = west.getRelative(BlockFace.DOWN); if (isRailBlock(descendingEast)) { rails.add(descendingEast); } if (isRailBlock(descendingWest)) { rails.add(descendingWest); } } return rails; } }, ASCENDING_EAST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock west = rail.getRelative(BlockFace.WEST); GlowBlock ascendingEast = rail.getRelative(BlockFace.EAST).getRelative(BlockFace.UP); GlowBlock descendingWest = west.getRelative(BlockFace.DOWN); if (isRailBlock(ascendingEast)) { rails.add(ascendingEast); } if (isRailBlock(descendingWest)) { rails.add(descendingWest); } if (rails.size() != 2) { if (isRailBlock(west)) { rails.add(west); } } return rails; } }, ASCENDING_WEST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock east = rail.getRelative(BlockFace.EAST); GlowBlock ascendingWest = rail.getRelative(BlockFace.WEST).getRelative(BlockFace.UP); GlowBlock descendingEast = east.getRelative(BlockFace.DOWN); if (isRailBlock(ascendingWest)) { rails.add(ascendingWest); } if (isRailBlock(descendingEast)) { rails.add(descendingEast); } if (rails.size() != 2) { if (isRailBlock(east)) { rails.add(east); } } return rails; } }, ASCENDING_NORTH { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock south = rail.getRelative(BlockFace.SOUTH); GlowBlock ascendingNorth = rail.getRelative(BlockFace.NORTH).getRelative(BlockFace.UP); GlowBlock descendingSouth = south.getRelative(BlockFace.DOWN); if (isRailBlock(ascendingNorth)) { rails.add(ascendingNorth); } if (isRailBlock(descendingSouth)) { rails.add(descendingSouth); } if (rails.size() != 2) { if (isRailBlock(south)) { rails.add(south); } } return rails; } }, ASCENDING_SOUTH { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock north = rail.getRelative(BlockFace.NORTH); GlowBlock ascendingSouth = rail.getRelative(BlockFace.SOUTH).getRelative(BlockFace.UP); GlowBlock descendingNorth = north.getRelative(BlockFace.DOWN); if (isRailBlock(ascendingSouth)) { rails.add(ascendingSouth); } if (isRailBlock(descendingNorth)) { rails.add(descendingNorth); } if (rails.size() != 2) { if (isRailBlock(north)) { rails.add(north); } } return rails; } }, SOUTH_EAST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock south = rail.getRelative(BlockFace.SOUTH); GlowBlock east = rail.getRelative(BlockFace.EAST); if (isRailBlock(south)) { rails.add(south); } if (isRailBlock(east)) { rails.add(east); } if (rails.size() != 2) { GlowBlock descendingSouth = south.getRelative(BlockFace.DOWN); GlowBlock descendingEast = east.getRelative(BlockFace.DOWN); if (isRailBlock(descendingSouth)) { rails.add(descendingSouth); } if (isRailBlock(descendingEast)) { rails.add(descendingEast); } } return rails; } }, SOUTH_WEST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock south = rail.getRelative(BlockFace.SOUTH); GlowBlock west = rail.getRelative(BlockFace.WEST); if (isRailBlock(south)) { rails.add(south); } if (isRailBlock(west)) { rails.add(west); } if (rails.size() != 2) { GlowBlock descendingSouth = south.getRelative(BlockFace.DOWN); GlowBlock descendingWest = west.getRelative(BlockFace.DOWN); if (isRailBlock(descendingSouth)) { rails.add(descendingSouth); } if (isRailBlock(descendingWest)) { rails.add(descendingWest); } } return rails; } }, NORTH_WEST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock north = rail.getRelative(BlockFace.NORTH); GlowBlock west = rail.getRelative(BlockFace.WEST); if (isRailBlock(north)) { rails.add(north); } if (isRailBlock(west)) { rails.add(west); } if (rails.size() != 2) { GlowBlock descendingNorth = north.getRelative(BlockFace.DOWN); GlowBlock descendingWest = west.getRelative(BlockFace.DOWN); if (isRailBlock(descendingNorth)) { rails.add(descendingNorth); } if (isRailBlock(descendingWest)) { rails.add(descendingWest); } } return rails; } }, NORTH_EAST { @Override public Set<GlowBlock> getNeighborRails(GlowBlock rail) { Set<GlowBlock> rails = new HashSet<>(); GlowBlock north = rail.getRelative(BlockFace.NORTH); GlowBlock east = rail.getRelative(BlockFace.EAST); if (isRailBlock(north)) { rails.add(north); } if (isRailBlock(east)) { rails.add(east); } if (rails.size() != 2) { GlowBlock descendingNorth = north.getRelative(BlockFace.DOWN); GlowBlock descendingEast = east.getRelative(BlockFace.DOWN); if (isRailBlock(descendingNorth)) { rails.add(descendingNorth); } if (isRailBlock(descendingEast)) { rails.add(descendingEast); } } return rails; } }; private static final Map<Byte, RailDirection> dataValues = new HashMap<>(); static { for (RailDirection direction : RailDirection.values()) { dataValues.put((byte) direction.ordinal(), direction); } } public abstract Set<GlowBlock> getNeighborRails(GlowBlock rail); public static RailDirection getRailDirection(GlowBlock rail) { return dataValues.get(rail.getData()); } } }