diff --git a/build.gradle b/build.gradle index 4600616..af79678 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ dependencies { compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT") compileOnly 'io.th0rgal:oraxen:1.184.1' compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.15") + implementation("com.google.guava:guava:10.0.1") implementation("org.xerial:sqlite-jdbc:3.50.3.0") implementation("com.j256.ormlite:ormlite-jdbc:6.1") } diff --git a/src/main/java/dev/lotus/studio/Main.java b/src/main/java/dev/lotus/studio/Main.java index 14a127e..2375c27 100644 --- a/src/main/java/dev/lotus/studio/Main.java +++ b/src/main/java/dev/lotus/studio/Main.java @@ -1,13 +1,10 @@ package dev.lotus.studio; -import com.j256.ormlite.support.ConnectionSource; import dev.lotus.studio.database.DatabaseInitializer; import dev.lotus.studio.database.playerdata.PlayerDataService; import org.bukkit.event.HandlerList; import org.bukkit.plugin.java.JavaPlugin; -import dev.lotus.studio.database.playerdata.PlayerDataServiceImpl; -import dev.lotus.studio.database.savezone.SaveZoneDataService; -import dev.lotus.studio.database.savezone.SaveZoneDataServiceImpl; +import dev.lotus.studio.database.savezone.SafeZoneDataService; import dev.lotus.studio.event.EatEvent; import dev.lotus.studio.event.JoinLeaveEvent; import dev.lotus.studio.item.CustomItemManager; @@ -17,22 +14,15 @@ import dev.lotus.studio.playerdata.PlayerManager; import dev.lotus.studio.safezone.SafeZoneManager; -import java.sql.SQLException; - public final class Main extends JavaPlugin { private static Main instance; private CustomItemManager itemManager; - - - private PlayerDataService playerDataBase; - private SaveZoneDataService saveZoneDataService; + private SafeZoneDataService safeZoneDataService; private DatabaseInitializer databaseInitializer; - - @Override public void onEnable() { @@ -42,7 +32,7 @@ public void onEnable() { itemManager = new CustomItemManager(); databaseInitializer = new DatabaseInitializer(this); playerDataBase = databaseInitializer.getPlayerDataBase(); - saveZoneDataService = databaseInitializer.getSaveZoneDataService(); + safeZoneDataService = databaseInitializer.getSaveZoneDataService(); @@ -55,15 +45,16 @@ public void onEnable() { new PlayerBar(this,itemManager); - new MainCommand("lotus", itemManager,saveZoneDataService); + new MainCommand("lotus", itemManager); - SafeZoneManager.getInstance().initializeZones(saveZoneDataService); + SafeZoneManager.getInstance().initialize(safeZoneDataService); } @Override public void onDisable() { PlayerManager.getInstance().getGlobalTask().cancel(); + SafeZoneManager.getInstance().getPreloaded().stopTask(); // Закриття DataBase if (databaseInitializer != null) { databaseInitializer.closeConnection(); diff --git a/src/main/java/dev/lotus/studio/command/MainCommand.java b/src/main/java/dev/lotus/studio/command/MainCommand.java index da7256f..2c8c652 100644 --- a/src/main/java/dev/lotus/studio/command/MainCommand.java +++ b/src/main/java/dev/lotus/studio/command/MainCommand.java @@ -4,7 +4,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import dev.lotus.studio.database.savezone.SaveZoneDataService; +import dev.lotus.studio.database.savezone.SafeZoneDataService; import dev.lotus.studio.item.CustomItemManager; import java.util.ArrayList; @@ -14,10 +14,10 @@ public class MainCommand extends AbstractCommand { private final CustomItemManager itemManager; private final SafeZoneCommand saveZoneCommand; - public MainCommand(String command, CustomItemManager itemManager, SaveZoneDataService saveZoneDataService) { + public MainCommand(String command, CustomItemManager itemManager) { super(command); this.itemManager = itemManager; - this.saveZoneCommand =new SafeZoneCommand(saveZoneDataService); + this.saveZoneCommand =new SafeZoneCommand(); } @Override @@ -286,20 +286,6 @@ private void sendEatHelp(Player player, String label) { } - - - - - - - - - - - - - - @Override public List complete(CommandSender sender, String[] args) { List suggestions = new ArrayList<>(); @@ -313,7 +299,7 @@ public List complete(CommandSender sender, String[] args) { suggestions.addAll(List.of("armor", "view", "eat", "help")); } else if ("savezone".equals(category)) { - suggestions.addAll(List.of("pos1", "pos2", "save","list")); + suggestions.addAll(List.of("pos1", "pos2", "save","list","remove")); } } else if (args.length == 3) { String category = args[0].toLowerCase(); diff --git a/src/main/java/dev/lotus/studio/command/SafeZoneCommand.java b/src/main/java/dev/lotus/studio/command/SafeZoneCommand.java index 2b15641..38dd1d7 100644 --- a/src/main/java/dev/lotus/studio/command/SafeZoneCommand.java +++ b/src/main/java/dev/lotus/studio/command/SafeZoneCommand.java @@ -1,24 +1,27 @@ package dev.lotus.studio.command; - +import dev.lotus.studio.database.savezone.SafeZoneDataBase; +import dev.lotus.studio.database.savezone.SafeZoneDataService; +import dev.lotus.studio.safezone.SafeZone; +import dev.lotus.studio.safezone.SafeZoneManager; +import net.kyori.adventure.text.Component; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import dev.lotus.studio.database.savezone.SafeZoneDataBase; -import dev.lotus.studio.database.savezone.SaveZoneDataService; import java.util.HashMap; import java.util.List; +import static dev.lotus.studio.utils.MapperUtils.formatLocation; + public class SafeZoneCommand { - private final SaveZoneDataService service; + private final SafeZoneManager safeZoneManager = SafeZoneManager.getInstance(); private Location pos1 = null; private Location pos2 = null; - public SafeZoneCommand(SaveZoneDataService service) { - this.service = service; - } public boolean execute(CommandSender sender, String label, String[] args) { if (!(sender instanceof Player player)) { @@ -37,12 +40,12 @@ public boolean execute(CommandSender sender, String label, String[] args) { switch (args[1].toLowerCase()) { case "pos1": pos1 = player.getLocation(); - player.sendMessage("fist point: " + formatLocation(pos1)); + player.sendMessage("first point: " + formatLocation(pos1)); break; case "pos2": pos2 = player.getLocation(); - player.sendMessage("second points: " + formatLocation(pos2)); + player.sendMessage("second point: " + formatLocation(pos2)); break; case "save": @@ -50,70 +53,62 @@ public boolean execute(CommandSender sender, String label, String[] args) { player.sendMessage("set name to savezone: /lotus savezone save <назва>"); return true; } - saveZoneToDB(player, pos1, pos2, args[2]); + saveZone(player, pos1, pos2, args[2]); break; + case "list": - player.sendMessage("Укажіть назву для зони. Наприклад: /<команда> save <назва>"); - listZoneToDB(player); + listZones(player); return true; + case "remove": if (args.length < 3) { - player.sendMessage("Укажіть назву для зони. Наприклад: /<команда> save <назва>"); + player.sendMessage("Укажіть ID зони: /lotus savezone remove "); return true; } - removeZoneToDB(player, Integer.parseInt(args[1])); + removeZone(player, Integer.parseInt(args[2])); break; + default: - player.sendMessage("Невідома команда. Використовуйте: pos1, pos2 або save."); + player.sendMessage("Невідома команда. Використовуйте: pos1, pos2, save, list, remove."); } return true; } - private void removeZoneToDB(Player player, int id) { - service.getAllSaveZones().forEach(safeZoneDataBase -> { - if (safeZoneDataBase.getSafeZoneId() == id){ - player.sendMessage("Сейв зону удаленно с названием: " + safeZoneDataBase.getSafeZoneName() + " ID: " + safeZoneDataBase.getSafeZoneId()); - } - }); - service.removeProtectZone(id); + private void saveZone(Player player, Location pos1, Location pos2, String zoneName) { + if (pos1 != null && pos2 != null) { + Pair zoneLoc = new ImmutablePair<>(pos1, pos2); + SafeZone safeZone = new SafeZone(zoneName, zoneLoc); + + // runtime + safeZoneManager.addSafeZone(safeZone); + + player.sendMessage("Зона '" + zoneName + "' успішно збережена."); + } else { + player.sendMessage("Будь ласка, спочатку встановіть обидві точки (pos1 і pos2)."); + } } - private void listZoneToDB(Player player) { - // Отримуємо всі збережені зони з бази даних - List safeZoneDataBases = service.getAllSaveZones(); + private void listZones(Player player) { + List safeZones = safeZoneManager.getDataZones(); - // Якщо зон немає, повідомляємо гравця - if (safeZoneDataBases.isEmpty()) { - player.sendMessage("нет зон."); + if (safeZones.isEmpty()) { + player.sendMessage("немає зон."); return; } - // Формуємо мапу з імен зон і їх ідентифікаторів HashMap saveId = new HashMap<>(); - safeZoneDataBases.forEach(saveZoneData -> saveId.put(saveZoneData.getSafeZoneName(), saveZoneData.getSafeZoneId())); + safeZones.forEach(zone -> saveId.put(zone.getSafeZoneName(), zone.getSafeZoneId())); - // Виводимо гравцю список зон player.sendMessage("Список зон:"); saveId.forEach((name, id) -> - player.sendMessage(" - Имя: " + name + ", ID: " + id) + player.sendMessage(" - Назва: " + name + ", ID: " + id) ); } + private void removeZone(Player player, int id) { + // runtime + safeZoneManager.removeSafeZone(id); - private void saveZoneToDB(Player player, Location pos1, Location pos2, String zoneName) { - if (pos1 != null && pos2 != null) { - String positionData = formatLocation(pos1) + "|" + formatLocation(pos2); - service.saveProtectZone(zoneName, positionData); - player.sendMessage("Зона '" + zoneName + "' успішно збережена."); - } else { - player.sendMessage("Будь ласка, спочатку встановіть обидві точки (pos1 і pos2)."); - } + player.sendMessage(Component.text("Safe zone with ID " + id + " deleted!")); } - - private String formatLocation(Location location) { - return location.getBlockX() + "," + - location.getBlockY() + "," + - location.getBlockZ(); - } - } diff --git a/src/main/java/dev/lotus/studio/database/DatabaseInitializer.java b/src/main/java/dev/lotus/studio/database/DatabaseInitializer.java index 243967e..42a33d2 100644 --- a/src/main/java/dev/lotus/studio/database/DatabaseInitializer.java +++ b/src/main/java/dev/lotus/studio/database/DatabaseInitializer.java @@ -7,8 +7,8 @@ import dev.lotus.studio.database.playerdata.PlayerDataService; import dev.lotus.studio.database.playerdata.PlayerDataServiceImpl; import dev.lotus.studio.database.savezone.SafeZoneDataBase; -import dev.lotus.studio.database.savezone.SaveZoneDataService; -import dev.lotus.studio.database.savezone.SaveZoneDataServiceImpl; +import dev.lotus.studio.database.savezone.SafeZoneDataService; +import dev.lotus.studio.database.savezone.SafeZoneDataServiceImpl; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; @@ -25,7 +25,7 @@ public class DatabaseInitializer { private PlayerDataService playerDataBase; - private SaveZoneDataService saveZoneDataService; + private SafeZoneDataService safeZoneDataService; public DatabaseInitializer(JavaPlugin plugin) { this.plugin = plugin; @@ -70,17 +70,12 @@ public void initialDataService() { try { ConnectionSource connectionSource = openConnection(); this.playerDataBase = new PlayerDataServiceImpl(connectionSource); - this.saveZoneDataService = new SaveZoneDataServiceImpl(connectionSource); + this.safeZoneDataService = new SafeZoneDataServiceImpl(connectionSource); } catch (SQLException e) { throw new RuntimeException(e); } } - - - - - /** * Повертає ORMLite ConnectionSource */ @@ -127,11 +122,12 @@ public void closeConnection() { public PlayerDataService getPlayerDataBase() { return playerDataBase; } + /** * This method * @return SaveZoneDataService */ - public SaveZoneDataService getSaveZoneDataService() { - return saveZoneDataService; + public SafeZoneDataService getSaveZoneDataService() { + return safeZoneDataService; } } diff --git a/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataRepository.java b/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataRepository.java new file mode 100644 index 0000000..843b40f --- /dev/null +++ b/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataRepository.java @@ -0,0 +1,73 @@ +package dev.lotus.studio.database.savezone; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import org.apache.commons.lang3.tuple.Pair; +import org.bukkit.Bukkit; +import org.bukkit.Location; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class SafeZoneDataRepository { + + private final Dao safeZoneDao; + + public SafeZoneDataRepository(ConnectionSource connectionSource) throws SQLException { + this.safeZoneDao = DaoManager.createDao(connectionSource, SafeZoneDataBase.class); + } + + public void removeProtectZone(int id) throws SQLException { + safeZoneDao.deleteById(id); + } + + public void saveZoneDataBase(SafeZoneDataBase safeZoneDataBase) throws SQLException { + safeZoneDao.createOrUpdate(safeZoneDataBase); + } + + public List getAllZoneDataBase() throws SQLException { + return safeZoneDao.queryForAll(); + } + + /** Новий метод */ + public SafeZoneDataBase getZoneById(int id) throws SQLException { + return safeZoneDao.queryForId(id); + } + + /** + * Отримати всі зони у вигляді пар локацій + */ + public List> getSafeZoneDataZones() throws SQLException { + List> zones = new ArrayList<>(); + List structures = getAllZoneDataBase(); + + for (SafeZoneDataBase structure : structures) { + zones.add(parseZone(structure.getLocationValue())); + } + return zones; + } + + private Pair parseZone(String raw) { + String[] coordinates = raw.split("\\|"); + String[] loc1 = coordinates[0].split(","); + String[] loc2 = coordinates[1].split(","); + + Location location1 = new Location( + Bukkit.getWorld("world"), + Double.parseDouble(loc1[0].trim()), + Double.parseDouble(loc1[1].trim()), + Double.parseDouble(loc1[2].trim()) + ); + + Location location2 = new Location( + Bukkit.getWorld("world"), + Double.parseDouble(loc2[0].trim()), + Double.parseDouble(loc2[1].trim()), + Double.parseDouble(loc2[2].trim()) + ); + + return Pair.of(location1, location2); + } +} diff --git a/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataService.java b/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataService.java similarity index 73% rename from src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataService.java rename to src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataService.java index cf751fc..1128419 100644 --- a/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataService.java +++ b/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataService.java @@ -5,12 +5,15 @@ import java.util.List; -public interface SaveZoneDataService { +public interface SafeZoneDataService { void saveProtectZone(String name, String location); void removeProtectZone(int id); + SafeZoneDataBase getZoneById(int id); + List getNearbyZoneIds(Location predicted); + List getAllSaveZones(); boolean isProtectZone(Location playerLocation); diff --git a/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataServiceImpl.java b/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataServiceImpl.java new file mode 100644 index 0000000..5844e04 --- /dev/null +++ b/src/main/java/dev/lotus/studio/database/savezone/SafeZoneDataServiceImpl.java @@ -0,0 +1,154 @@ +package dev.lotus.studio.database.savezone; + +import com.j256.ormlite.support.ConnectionSource; +import org.apache.commons.lang3.tuple.Pair; +import org.bukkit.Location; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class SafeZoneDataServiceImpl implements SafeZoneDataService { + + private final SafeZoneDataRepository safeZoneDataRepository; + + public SafeZoneDataServiceImpl(ConnectionSource connectionSource) throws SQLException { + this.safeZoneDataRepository = new SafeZoneDataRepository(connectionSource); + } + + @Override + public void saveProtectZone(String name, String location) { + try { + SafeZoneDataBase safeZoneDataBase = new SafeZoneDataBase(name, location); + safeZoneDataRepository.saveZoneDataBase(safeZoneDataBase); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void removeProtectZone(int id) { + try { + safeZoneDataRepository.removeProtectZone(id); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** Реалізація getZoneById */ + @Override + public SafeZoneDataBase getZoneById(int id) { + try { + return safeZoneDataRepository.getZoneById(id); + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public List getAllSaveZones() { + try { + return safeZoneDataRepository.getAllZoneDataBase(); + } catch (SQLException e) { + e.printStackTrace(); + return List.of(); + } + } + + @Override + public boolean isProtectZone(Location playerLocation) { + try { + List> saveZoneDataZones = safeZoneDataRepository.getSafeZoneDataZones(); + for (Pair zone : saveZoneDataZones) { + if (isLocationInZone(playerLocation, zone.getLeft(), zone.getRight())) { + return true; + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public List> getSaveZones() { + try { + return safeZoneDataRepository.getSafeZoneDataZones(); + } catch (SQLException e) { + e.printStackTrace(); + return List.of(); + } + } + + /** ✅ Новий метод */ + public List getNearbyZoneIds(Location predicted) { + List result = new ArrayList<>(); + try { + List zones = safeZoneDataRepository.getAllZoneDataBase(); + for (SafeZoneDataBase zone : zones) { + Pair locPair = parseZone(zone.getLocationValue()); + if (isNear(predicted, locPair.getLeft(), locPair.getRight(), 20)) { // радіус 20 блоків + result.add(zone.getSafeZoneId()); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return result; + } + + private boolean isLocationInZone(Location location, Location loc1, Location loc2) { + int x1 = Math.min(loc1.getBlockX(), loc2.getBlockX()); + int y1 = Math.min(loc1.getBlockY(), loc2.getBlockY()); + int z1 = Math.min(loc1.getBlockZ(), loc2.getBlockZ()); + + int x2 = Math.max(loc1.getBlockX(), loc2.getBlockX()); + int y2 = Math.max(loc1.getBlockY(), loc2.getBlockY()); + int z2 = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); + + int px = location.getBlockX(); + int py = location.getBlockY(); + int pz = location.getBlockZ(); + + return (px >= x1 && px <= x2) && + (py >= y1 && py <= y2) && + (pz >= z1 && pz <= z2); + } + + private boolean isNear(Location player, Location l1, Location l2, int radius) { + int x1 = Math.min(l1.getBlockX(), l2.getBlockX()) - radius; + int y1 = Math.min(l1.getBlockY(), l2.getBlockY()) - radius; + int z1 = Math.min(l1.getBlockZ(), l2.getBlockZ()) - radius; + + int x2 = Math.max(l1.getBlockX(), l2.getBlockX()) + radius; + int y2 = Math.max(l1.getBlockY(), l2.getBlockY()) + radius; + int z2 = Math.max(l1.getBlockZ(), l2.getBlockZ()) + radius; + + int px = player.getBlockX(); + int py = player.getBlockY(); + int pz = player.getBlockZ(); + + return (px >= x1 && px <= x2) && + (py >= y1 && py <= y2) && + (pz >= z1 && pz <= z2); + } + + private Pair parseZone(String raw) { + String[] coordinates = raw.split("\\|"); + String[] loc1 = coordinates[0].split(","); + String[] loc2 = coordinates[1].split(","); + + Location location1 = new Location(null, + Double.parseDouble(loc1[0].trim()), + Double.parseDouble(loc1[1].trim()), + Double.parseDouble(loc1[2].trim())); + + Location location2 = new Location(null, + Double.parseDouble(loc2[0].trim()), + Double.parseDouble(loc2[1].trim()), + Double.parseDouble(loc2[2].trim())); + + return Pair.of(location1, location2); + } +} diff --git a/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataRepository.java b/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataRepository.java deleted file mode 100644 index 565a97f..0000000 --- a/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataRepository.java +++ /dev/null @@ -1,76 +0,0 @@ -package dev.lotus.studio.database.savezone; - -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.DaoManager; -import com.j256.ormlite.support.ConnectionSource; -import org.apache.commons.lang3.tuple.Pair; -import org.bukkit.Bukkit; -import org.bukkit.Location; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -public class SaveZoneDataRepository { - - private final Dao safeZoneDao; - - public SaveZoneDataRepository(ConnectionSource connectionSource) throws SQLException { - this.safeZoneDao = DaoManager.createDao(connectionSource, SafeZoneDataBase.class); - } - - /** - * Видалити зону по id - */ - public void removeProtectZone(int id) throws SQLException { - safeZoneDao.deleteById(id); - } - - /** - * Зберегти/оновити структуру - */ - public void saveStructureData(SafeZoneDataBase safeZoneDataBase) throws SQLException { - safeZoneDao.createOrUpdate(safeZoneDataBase); - } - - /** - * Отримати всі структури - */ - public List getAllStructuresData() throws SQLException { - return safeZoneDao.queryForAll(); - } - - /** - * Повертає список зон у форматі пар локацій (лок1, лок2) - */ - public List> getSaveZoneDataZones() throws SQLException { - List> zones = new ArrayList<>(); - List structures = getAllStructuresData(); - - for (SafeZoneDataBase structure : structures) { - String[] coordinates = structure.getLocationValue().split("\\|"); - if (coordinates.length == 2) { - String[] loc1 = coordinates[0].split(","); - String[] loc2 = coordinates[1].split(","); - - Location location1 = new Location( - Bukkit.getWorld("world"), // або передавати динамічно - Double.parseDouble(loc1[0].trim()), - Double.parseDouble(loc1[1].trim()), - Double.parseDouble(loc1[2].trim()) - ); - - Location location2 = new Location( - Bukkit.getWorld("world"), - Double.parseDouble(loc2[0].trim()), - Double.parseDouble(loc2[1].trim()), - Double.parseDouble(loc2[2].trim()) - ); - - zones.add(Pair.of(location1, location2)); - } - } - - return zones; - } -} diff --git a/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataServiceImpl.java b/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataServiceImpl.java deleted file mode 100644 index dfee2b6..0000000 --- a/src/main/java/dev/lotus/studio/database/savezone/SaveZoneDataServiceImpl.java +++ /dev/null @@ -1,89 +0,0 @@ -package dev.lotus.studio.database.savezone; - -import com.j256.ormlite.support.ConnectionSource; -import org.apache.commons.lang3.tuple.Pair; -import org.bukkit.Location; - -import java.sql.SQLException; -import java.util.List; - -public class SaveZoneDataServiceImpl implements SaveZoneDataService { - - private final SaveZoneDataRepository saveZoneDataRepository; - - public SaveZoneDataServiceImpl(ConnectionSource connectionSource) throws SQLException { - this.saveZoneDataRepository = new SaveZoneDataRepository(connectionSource); - } - - @Override - public void saveProtectZone(String name, String location) { - try { - SafeZoneDataBase safeZoneDataBase = new SafeZoneDataBase(name, location); - saveZoneDataRepository.saveStructureData(safeZoneDataBase); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - @Override - public void removeProtectZone(int id) { - try { - saveZoneDataRepository.removeProtectZone(id); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - @Override - public List getAllSaveZones() { - try { - return saveZoneDataRepository.getAllStructuresData(); - } catch (SQLException e) { - e.printStackTrace(); - return List.of(); - } - } - - @Override - public boolean isProtectZone(Location playerLocation) { - try { - List> saveZoneDataZones = saveZoneDataRepository.getSaveZoneDataZones(); - for (Pair zone : saveZoneDataZones) { - if (isLocationInZone(playerLocation, zone.getLeft(), zone.getRight())) { - return true; - } - } - } catch (SQLException e) { - e.printStackTrace(); - } - return false; - } - - @Override - public List> getSaveZones() { - try { - return saveZoneDataRepository.getSaveZoneDataZones(); - } catch (SQLException e) { - e.printStackTrace(); - return List.of(); - } - } - - private boolean isLocationInZone(Location location, Location loc1, Location loc2) { - int x1 = Math.min(loc1.getBlockX(), loc2.getBlockX()); - int y1 = Math.min(loc1.getBlockY(), loc2.getBlockY()); - int z1 = Math.min(loc1.getBlockZ(), loc2.getBlockZ()); - - int x2 = Math.max(loc1.getBlockX(), loc2.getBlockX()); - int y2 = Math.max(loc1.getBlockY(), loc2.getBlockY()); - int z2 = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); - - int px = location.getBlockX(); - int py = location.getBlockY(); - int pz = location.getBlockZ(); - - return (px >= x1 && px <= x2) && - (py >= y1 && py <= y2) && - (pz >= z1 && pz <= z2); - } -} diff --git a/src/main/java/dev/lotus/studio/safezone/SafeZone.java b/src/main/java/dev/lotus/studio/safezone/SafeZone.java index 8357854..b5b7b43 100644 --- a/src/main/java/dev/lotus/studio/safezone/SafeZone.java +++ b/src/main/java/dev/lotus/studio/safezone/SafeZone.java @@ -15,12 +15,15 @@ public SafeZone(String zoneName, Pair locationPair) { } - public void setZoneName(String zoneName) { + public SafeZone(int id, String zoneName, Pair locationPair) { + this.zoneID = id; this.zoneName = zoneName; + this.locationPair = locationPair; + } - public void setZoneID(int zoneID) { - this.zoneID = zoneID; + public void setZoneName(String zoneName) { + this.zoneName = zoneName; } public Pair getLocationPair() { diff --git a/src/main/java/dev/lotus/studio/safezone/SafeZoneManager.java b/src/main/java/dev/lotus/studio/safezone/SafeZoneManager.java index 137f43e..596bd81 100644 --- a/src/main/java/dev/lotus/studio/safezone/SafeZoneManager.java +++ b/src/main/java/dev/lotus/studio/safezone/SafeZoneManager.java @@ -1,150 +1,98 @@ package dev.lotus.studio.safezone; -import org.apache.commons.lang3.tuple.Pair; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import dev.lotus.studio.utils.SafeZoneUtils; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import dev.lotus.studio.Main; import dev.lotus.studio.database.savezone.SafeZoneDataBase; -import dev.lotus.studio.database.savezone.SaveZoneDataService; +import dev.lotus.studio.database.savezone.SafeZoneDataService; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; public class SafeZoneManager { private static final SafeZoneManager instance = new SafeZoneManager(); - private final List safeZones = new ArrayList<>(); private final Plugin plugin = Main.getInstance(); + + private SafeZoneDataService safeZoneDataService; + + // Кеш із TTL (щоб вивантажувати непотрібні зони) + private final Cache zoneCache = CacheBuilder.newBuilder() + .expireAfterAccess(5, TimeUnit.MINUTES) + .maximumSize(500) // захист від переповнення + .build(); + + private SafeZonePreloaded preloader; + public static SafeZoneManager getInstance() { return instance; } - // Добавление новой зоны - public void addSafeZone(SafeZone safeZone) { - safeZones.add(safeZone); - } + public void initialize(SafeZoneDataService safeZoneDataService) { + this.safeZoneDataService = safeZoneDataService; + this.preloader = new SafeZonePreloaded(this, safeZoneDataService, plugin); - // Удаление зоны по ID - public boolean removeSafeZone(int zoneID) { - return safeZones.removeIf(zone -> zone.getZoneID() == zoneID); + plugin.getLogger().info("SafeZoneManager ініціалізовано з lazy-загрузкою та кешем."); } - // Поиск зоны по имени - public SafeZone getSafeZoneByName(String name) { - return safeZones.stream() - .filter(zone -> zone.getZoneName().equalsIgnoreCase(name)) - .findFirst() - .orElse(null); + // Додавання нової зони + public void addSafeZone(SafeZone safeZone) { + zoneCache.put(safeZone.getZoneID(), safeZone); + safeZoneDataService.saveProtectZone( + safeZone.getZoneName(), + SafeZoneUtils.serializeZone(safeZone.getLocationPair()) + ); } - // Проверка, находится ли игрок в какой-либо зоне - public SafeZone getZoneContainingPlayer(Player player) { - Location playerLocation = player.getLocation(); - return safeZones.stream() - .filter(zone -> isLocationInZone(playerLocation, - zone.getLocationPair().getLeft(), - zone.getLocationPair().getRight())) - .findFirst() - .orElse(null); + // Видалення + public void removeSafeZone(int zoneID) { + zoneCache.invalidate(zoneID); + safeZoneDataService.removeProtectZone(zoneID); } - // Проверка, находится ли игрок в какой-либо зоне - public boolean isPlayerInAnyZone(Player player) { - Location playerLocation = player.getLocation(); - return safeZones.stream() - .anyMatch(zone -> isLocationInZone(playerLocation, - zone.getLocationPair().getLeft(), - zone.getLocationPair().getRight())); - } + // Отримання зони з кешу (або БД, якщо немає в кеші) + public void getZoneById(int zoneID) { + SafeZone cached = zoneCache.getIfPresent(zoneID); + if (cached != null) { + return; + } - public void initializeZones(SaveZoneDataService saveZoneDataService) { - List zonesData = saveZoneDataService.getAllSaveZones(); - - try { - for (SafeZoneDataBase data : zonesData) { - try { - // Парсим данные координат - List> parsedZones = parseZonesFromString(data.getLocationValue()); - if (!parsedZones.isEmpty()) { - // Берём первую пару координат для SafeZone - Pair zoneCoordinates = parsedZones.get(0); - SafeZone safeZone = new SafeZone( - data.getSafeZoneName(), - zoneCoordinates - ); - addSafeZone(safeZone); // Добавляем загруженную зону в менеджер - - // Успешная инициализация - plugin.getLogger().info("Успешно инициализирована зона: " - + data.getSafeZoneName() + " (ID: " + data.getSafeZoneId() + ")"); - } - } catch (Exception e) { - plugin.getLogger().warning("Ошибка при инициализации зоны: " - + data.getSafeZoneName() + " (ID: " + data.getSafeZoneId() + ")"); - e.printStackTrace(); - } - } - } catch (Exception e) { - plugin.getLogger().severe("Ошибка при загрузке данных зон безопасности."); - e.printStackTrace(); - } finally { - plugin.getLogger().info("Процесс инициализации зон завершён."); + SafeZoneDataBase dbData = safeZoneDataService.getZoneById(zoneID); + if (dbData != null) { + SafeZone zone = SafeZoneUtils.fromDatabase(dbData); + zoneCache.put(zoneID, zone); + + plugin.getLogger().info("[SafeZoneManager] Loaded zone from DB and cached: " + + zone.getZoneName() + " (ID: " + zone.getZoneID() + ")"); + } else { + plugin.getLogger().warning("[SafeZoneManager] Zone " + zoneID + " not found in DB."); } } - public List> parseZonesFromString(String data) { - List> zones = new ArrayList<>(); - try { - String[] zoneEntries = data.split(";"); // Разделяем по ';', чтобы получить отдельные зоны - for (String entry : zoneEntries) { - String[] coordinates = entry.split("\\|"); // Разделяем первую и вторую координаты - if (coordinates.length == 2) { - String[] loc1 = coordinates[0].split(","); // Координаты первой точки - String[] loc2 = coordinates[1].split(","); // Координаты второй точки - - Location location1 = new Location(null, // `null` - добавьте мир, если необходимо - Integer.parseInt(loc1[0].trim()), - Integer.parseInt(loc1[1].trim()), - Integer.parseInt(loc1[2].trim())); - - Location location2 = new Location(null, - Integer.parseInt(loc2[0].trim()), - Integer.parseInt(loc2[1].trim()), - Integer.parseInt(loc2[2].trim())); - - zones.add(Pair.of(location1, location2)); - } + + // Перевірка чи гравець в якійсь зоні + public boolean isPlayerInAnyZone(Player player) { + Location playerLoc = player.getLocation(); + for (SafeZone zone : zoneCache.asMap().values()) { + if (SafeZoneUtils.isLocationInZone(playerLoc, + zone.getLocationPair().getLeft(), + zone.getLocationPair().getRight())) { + return true; } - } catch (Exception e) { - e.printStackTrace(); } - return zones; + return false; } - - - // Проверка, находится ли местоположение внутри зоны - private boolean isLocationInZone(Location playerLoc, Location posLoc1, Location posLoc2) { - int x1 = Math.min(posLoc1.getBlockX(), posLoc2.getBlockX()); - int y1 = Math.min(posLoc1.getBlockY(), posLoc2.getBlockY()); - int z1 = Math.min(posLoc1.getBlockZ(), posLoc2.getBlockZ()); - - int x2 = Math.max(posLoc1.getBlockX(), posLoc2.getBlockX()); - int y2 = Math.max(posLoc1.getBlockY(), posLoc2.getBlockY()); - int z2 = Math.max(posLoc1.getBlockZ(), posLoc2.getBlockZ()); - - int px = playerLoc.getBlockX(); - int py = playerLoc.getBlockY(); - int pz = playerLoc.getBlockZ(); - - return (px >= x1 && px <= x2) && - (py >= y1 && py <= y2) && - (pz >= z1 && pz <= z2); + public List getDataZones(){ + return safeZoneDataService.getAllSaveZones(); } - // Получение всех зон - public List getAllSafeZones() { - return new ArrayList<>(safeZones); + + public SafeZonePreloaded getPreloaded() { + return preloader; } } diff --git a/src/main/java/dev/lotus/studio/safezone/SafeZonePreloaded.java b/src/main/java/dev/lotus/studio/safezone/SafeZonePreloaded.java new file mode 100644 index 0000000..20aa699 --- /dev/null +++ b/src/main/java/dev/lotus/studio/safezone/SafeZonePreloaded.java @@ -0,0 +1,56 @@ +package dev.lotus.studio.safezone; + +import dev.lotus.studio.database.savezone.SafeZoneDataService; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.List; + +public class SafeZonePreloaded { + + private final SafeZoneManager manager; + private final SafeZoneDataService dataService; + private final Plugin plugin; + + private BukkitTask preloadTask; // зберігаємо таску + + public SafeZonePreloaded(SafeZoneManager manager, SafeZoneDataService dataService, Plugin plugin) { + this.manager = manager; + this.dataService = dataService; + this.plugin = plugin; + startTask(); + } + + private void startTask() { + // Запускаємо і зберігаємо таску + this.preloadTask = new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + preloadZonesForPlayer(player); + } + } + }.runTaskTimerAsynchronously(plugin, 20L, 40L); // кожні 2 сек + } + + public void stopTask() { + if (preloadTask != null && !preloadTask.isCancelled()) { + preloadTask.cancel(); + plugin.getLogger().info("[SafeZonePreloaded] Preload task stopped."); + } + } + + private void preloadZonesForPlayer(Player player) { + Location current = player.getLocation(); + Location velocity = player.getVelocity().toLocation(player.getWorld()); + + Location predicted = current.clone().add(velocity.multiply(3)); + List nearbyZoneIds = dataService.getNearbyZoneIds(predicted); + for (int zoneId : nearbyZoneIds) { + manager.getZoneById(zoneId); + } + } +} diff --git a/src/main/java/dev/lotus/studio/utils/MapperUtils.java b/src/main/java/dev/lotus/studio/utils/MapperUtils.java new file mode 100644 index 0000000..412028d --- /dev/null +++ b/src/main/java/dev/lotus/studio/utils/MapperUtils.java @@ -0,0 +1,13 @@ +package dev.lotus.studio.utils; + +import org.bukkit.Location; + +public class MapperUtils { + + + public static String formatLocation(Location location) { + return location.getBlockX() + "," + + location.getBlockY() + "," + + location.getBlockZ(); + } +} diff --git a/src/main/java/dev/lotus/studio/utils/SafeZoneUtils.java b/src/main/java/dev/lotus/studio/utils/SafeZoneUtils.java new file mode 100644 index 0000000..e4044c4 --- /dev/null +++ b/src/main/java/dev/lotus/studio/utils/SafeZoneUtils.java @@ -0,0 +1,59 @@ +package dev.lotus.studio.utils; + + +import dev.lotus.studio.safezone.SafeZone; +import org.apache.commons.lang3.tuple.Pair; +import org.bukkit.Location; +import dev.lotus.studio.database.savezone.SafeZoneDataBase; + +public class SafeZoneUtils { + + public static boolean isLocationInZone(Location playerLoc, Location posLoc1, Location posLoc2) { + int x1 = Math.min(posLoc1.getBlockX(), posLoc2.getBlockX()); + int y1 = Math.min(posLoc1.getBlockY(), posLoc2.getBlockY()); + int z1 = Math.min(posLoc1.getBlockZ(), posLoc2.getBlockZ()); + + int x2 = Math.max(posLoc1.getBlockX(), posLoc2.getBlockX()); + int y2 = Math.max(posLoc1.getBlockY(), posLoc2.getBlockY()); + int z2 = Math.max(posLoc1.getBlockZ(), posLoc2.getBlockZ()); + + int px = playerLoc.getBlockX(); + int py = playerLoc.getBlockY(); + int pz = playerLoc.getBlockZ(); + + return (px >= x1 && px <= x2) && + (py >= y1 && py <= y2) && + (pz >= z1 && pz <= z2); + } + + public static String serializeZone(Pair pair) { + return formatLoc(pair.getLeft()) + "|" + formatLoc(pair.getRight()); + } + + private static String formatLoc(Location loc) { + return loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ(); + } + + public static SafeZone fromDatabase(SafeZoneDataBase dbData) { + Pair coords = parseZone(dbData.getLocationValue()); + return new SafeZone(dbData.getSafeZoneId(), dbData.getSafeZoneName(), coords); + } + + private static Pair parseZone(String value) { + String[] parts = value.split("\\|"); + String[] loc1 = parts[0].split(","); + String[] loc2 = parts[1].split(","); + + Location l1 = new Location(null, + Integer.parseInt(loc1[0]), + Integer.parseInt(loc1[1]), + Integer.parseInt(loc1[2])); + + Location l2 = new Location(null, + Integer.parseInt(loc2[0]), + Integer.parseInt(loc2[1]), + Integer.parseInt(loc2[2])); + + return Pair.of(l1, l2); + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7cb9b90..4ed9bf1 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -6,6 +6,7 @@ soft-depend: [Oraxen] libraries: - org.xerial:sqlite-jdbc:3.50.3.0 - com.j256.ormlite:ormlite-jdbc:6.1 + - com.google.guava:guava:10.0.1 commands: lotus: description: Перезагрузка конфигурации плагина.