Cześć, ostanio zacząłem pisać plugin na silniku serwerowym Spigot. Plugin miał w założeniu działać tak, że mamy menu, wybieramy sobie typ struktury i w miejsu w które patrzymy stawia się najpierw "blueprint", a następnie jak klikniemy stawia się fizyczna struktura. Wszystko udało mi się zaimplementować, ale przy tworzeniu ścian natknąłem się na pewien problem, bo o ile przy fundamencie nie ma znaczenia w którym kierunku go postawimy, bo jest kwadratem, to przy ścianach już się problem pojawił. A mianowicie chodzi tutaj o dopasowywanie struktur do innych struktur. W przypadku fundamentów tego problemu nie ma bo operujemy tylko na dwóch osiach X i Z i mam mechanizm który mi dopasowuje do siatki elementy, ale w osi Y nie mam siatki, a mimo wszystko chciałbym, aby elementy się dopasowywały.

Kopiuj
public class GridUtil {
    public static Location calculateGridCenter(Location location) {
        int coreX = ((location.getBlockX() / 4) * 4) + (location.getBlockX() >= 0 ? 2 : -2);
        int coreZ = ((location.getBlockZ() / 4) * 4) + (location.getBlockZ() >= 0 ? 2 : -2);
        return new Location(location.getWorld(), coreX, location.getY(), coreZ);
    }
}

public class DirectionUtil {
    public static Direction yawToDirection(float yaw) {
//        return Direction.values()[Math.round(((yaw < 0) ? yaw + 360 : yaw) / 90f) & 0x3];
        return Direction.values()[Math.round(((yaw < 0) ? yaw + 360 : yaw) / 90f) % 4];
    }
}

public enum SchemaType {
    FOUNDATION {
        @Override
        public void blueprint(BuildSession session, Location lookLocation) {
            final Vector[] CORNER_OFFSETS = {
                    new Vector(-2, 0, -2),
                    new Vector(-2, 0, 2),
                    new Vector(2, 0, -2),
                    new Vector(2, 0, 2)
            };

            Set<Location> legBlocks = new HashSet<>();

            for (Vector offset : CORNER_OFFSETS) {
                boolean localHasSolidSupport = false;
                Location cornerLocation = lookLocation.clone().add(offset);

                for (int i = 1; i <= 4; i++) {
                    Location legLocation = cornerLocation.clone().subtract(0, i, 0);
                    Block legBlock = legLocation.getBlock();

                    if (legBlock.isSolid()) {
                        if (StructureManager.contains(StructureElementType.FRAME, legLocation)) {
                            return;
                        }

                        localHasSolidSupport = true;
                        break;
                    }

                    legBlocks.add(legLocation);
                }

                if (!localHasSolidSupport) {
                    return;
                }
            }

            legBlocks.forEach(loc -> {
                BlockDisplay display = (BlockDisplay) loc.getWorld().spawnEntity(loc, EntityType.BLOCK_DISPLAY);
                display.setBlock(Material.LIGHT_BLUE_STAINED_GLASS.createBlockData());
                session.add(StructureElementType.LEG, display);
            });

            for (int x = -2; x <= 2; x++) {
                for (int z = -2; z <= 2; z++) {
                    Location location = lookLocation.clone().add(x, 0, z);
                    Block block = location.getBlock();
                    boolean isBlockOverlapStructure = StructureManager.contains(StructureElementType.FRAME, block.getLocation());

                    if (!block.getType().equals(Material.AIR)) {
                        if (!isBlockOverlapStructure || StructureManager.contains(StructureElementType.LEG, block.getLocation())) {
                            session.clearBlueprint();
                            return;
                        }
                    }

                    if (!isBlockOverlapStructure) {
                        BlockDisplay display = (BlockDisplay) location.getWorld().spawnEntity(location, EntityType.BLOCK_DISPLAY);
                        display.setBlock(Material.LIGHT_BLUE_STAINED_GLASS.createBlockData());
                        session.add((Math.abs(x) <= 1 && Math.abs(z) <= 1) ? StructureElementType.CORE : StructureElementType.FRAME, display);
                    }
                }
            }
        }
    },
    WALL {
        @Override
        public void blueprint(BuildSession session, Location lookLocation) {
            for (int y = -2; y <= 2; y++) {
                for (int x = -2; x <= 2; x++) {
                    Location loc = lookLocation.clone();
                    session.getDirection().addOffset(loc, x, y);

                    if (y == -2) {
                        if (!StructureManager.contains(StructureElementType.FRAME, loc)) {
                            session.clearBlueprint();
                            return;
                        }
                    }

                    BlockDisplay display = (BlockDisplay) loc.getWorld().spawnEntity(loc, EntityType.BLOCK_DISPLAY);
                    display.setBlock(Material.LIGHT_BLUE_STAINED_GLASS.createBlockData());
                    session.add((Math.abs(x) <= 1 && Math.abs(y) <= 1) ? StructureElementType.CORE : StructureElementType.FRAME, display);
                }
            }

        }
    };

    public abstract void blueprint(BuildSession session, Location lookLocation);
}

@Getter
@AllArgsConstructor
public enum Direction {
    NORTH {
        @Override
        public void addOffset(Location loc, int x, int y) {
             loc.add(x, y, -2);
        }
    },
    EAST {
        @Override
        public void addOffset(Location loc, int x, int y) {
            loc.add(2, y, x);
        }
    },
    SOUTH {
        @Override
        public void addOffset(Location loc, int x, int y) {
            loc.add(x, y, 2);
        }
    },
    WEST {
        @Override
        public void addOffset(Location loc, int x, int y) {
            loc.add(-2, y, x);
        }
    };

    public abstract void addOffset(Location loc, int x, int y);
}

public class OnPlayerMoveListeners implements Listener {


    @EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        Player player = event.getPlayer();
        ItemStack itemInMainHand = player.getInventory().getItemInMainHand();

        if (itemInMainHand.getType().equals(Material.BLAZE_ROD)) {
            BuildSession session = BuildSessionManager.getSession(player.getUniqueId());
            Location lookLocation = GridUtil.calculateGridCenter(getTargetBlock(player, 3).getLocation());

            if (session.getLastLocation() == null || !session.getLastLocation().equals(lookLocation)) {
                if (session.getSchemaType().equals(SchemaType.WALL)) {
                    session.setDirection(DirectionUtil.yawToDirection(player.getYaw()));
                    System.out.println(session.getDirection().name());
                }

                session.clearBlueprint();
                session.setLastLocation(lookLocation);
                session.getSchemaType().blueprint(session, lookLocation);
            }

        } else {
            BuildSessionManager.removeSession(player.getUniqueId());
        }
    }

    public Block getTargetBlock(Player player, int range) {
        BlockIterator iter = new BlockIterator(player, range);
        Block lastBlock = iter.next();
        while (iter.hasNext()) {
            lastBlock = iter.next();
            if (lastBlock.getType() == Material.AIR) {
                continue;
            }
            break;
        }
        return lastBlock;
    }
}

- tutaj jest filmik który przedstawia efekt, który chciałbym uzyskać.
Czy ktoś mógłby mi podrzucić pomysł jak można było by wykonać podobne przyciąganie się elementów do siebie?