diff --git a/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java b/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java index 9412969..9351bc8 100644 --- a/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java +++ b/src/main/java/com/bgsoftware/wildloaders/WildLoadersPlugin.java @@ -2,6 +2,7 @@ package com.bgsoftware.wildloaders; import com.bgsoftware.wildloaders.api.WildLoaders; import com.bgsoftware.wildloaders.command.CommandsHandler; +import com.bgsoftware.wildloaders.handlers.DataHandler; import com.bgsoftware.wildloaders.handlers.LoadersHandler; import com.bgsoftware.wildloaders.handlers.NPCHandler; import com.bgsoftware.wildloaders.handlers.SettingsHandler; @@ -18,6 +19,7 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { private SettingsHandler settingsHandler; private LoadersHandler loadersHandler; private NPCHandler npcHandler; + private DataHandler dataHandler; private NMSAdapter nmsAdapter; @@ -30,6 +32,7 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { loadNMSAdapter(); + dataHandler = new DataHandler(this); loadersHandler = new LoadersHandler(this); npcHandler = new NPCHandler(this); settingsHandler = new SettingsHandler(this); @@ -55,6 +58,7 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { @Override public void onDisable() { + dataHandler.saveDatabase(); loadersHandler.removeChunkLoaders(); npcHandler.killAllNPCs(); } @@ -86,6 +90,10 @@ public final class WildLoadersPlugin extends JavaPlugin implements WildLoaders { return nmsAdapter; } + public DataHandler getDataHandler() { + return dataHandler; + } + public static void log(String message){ plugin.getLogger().info(message); } diff --git a/src/main/java/com/bgsoftware/wildloaders/command/CommandsHandler.java b/src/main/java/com/bgsoftware/wildloaders/command/CommandsHandler.java index b3919a0..caa7588 100644 --- a/src/main/java/com/bgsoftware/wildloaders/command/CommandsHandler.java +++ b/src/main/java/com/bgsoftware/wildloaders/command/CommandsHandler.java @@ -3,6 +3,7 @@ package com.bgsoftware.wildloaders.command; import com.bgsoftware.wildloaders.Locale; import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.command.commands.CmdGive; +import com.bgsoftware.wildloaders.command.commands.CmdSave; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; @@ -18,6 +19,7 @@ public final class CommandsHandler implements CommandExecutor, TabCompleter { public CommandsHandler(WildLoadersPlugin plugin){ this.plugin = plugin; subCommands.add(new CmdGive()); + subCommands.add(new CmdSave()); } @Override diff --git a/src/main/java/com/bgsoftware/wildloaders/command/commands/CmdSave.java b/src/main/java/com/bgsoftware/wildloaders/command/commands/CmdSave.java new file mode 100644 index 0000000..a52a551 --- /dev/null +++ b/src/main/java/com/bgsoftware/wildloaders/command/commands/CmdSave.java @@ -0,0 +1,59 @@ +package com.bgsoftware.wildloaders.command.commands; + +import com.bgsoftware.wildloaders.WildLoadersPlugin; +import com.bgsoftware.wildloaders.command.ICommand; +import com.bgsoftware.wildloaders.utils.threads.Executor; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +import java.util.ArrayList; +import java.util.List; + +public final class CmdSave implements ICommand { + + @Override + public String getLabel() { + return "save"; + } + + @Override + public String getUsage() { + return "loader save"; + } + + @Override + public String getPermission() { + return "wildloaders.save"; + } + + @Override + public String getDescription() { + return "Save all the chunk-loaders into the database."; + } + + @Override + public int getMinArgs() { + return 1; + } + + @Override + public int getMaxArgs() { + return 1; + } + + @Override + public void perform(WildLoadersPlugin plugin, CommandSender sender, String[] args) { + Executor.data(() -> { + long startTime = System.currentTimeMillis(); + sender.sendMessage(ChatColor.YELLOW + "Saving all chunk loaders..."); + plugin.getDataHandler().saveDatabase(); + sender.sendMessage(ChatColor.YELLOW + "Saving chunk loaders done! (Took " + (System.currentTimeMillis() - startTime) + "ms)"); + }); + } + + @Override + public List tabComplete(WildLoadersPlugin plugin, CommandSender sender, String[] args) { + return new ArrayList<>(); + } + +} diff --git a/src/main/java/com/bgsoftware/wildloaders/handlers/DataHandler.java b/src/main/java/com/bgsoftware/wildloaders/handlers/DataHandler.java new file mode 100644 index 0000000..36e9223 --- /dev/null +++ b/src/main/java/com/bgsoftware/wildloaders/handlers/DataHandler.java @@ -0,0 +1,121 @@ +package com.bgsoftware.wildloaders.handlers; + +import com.bgsoftware.wildloaders.WildLoadersPlugin; +import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; +import com.bgsoftware.wildloaders.api.loaders.LoaderData; +import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; +import com.bgsoftware.wildloaders.loaders.WChunkLoader; +import com.bgsoftware.wildloaders.npc.NPCIdentifier; +import com.bgsoftware.wildloaders.utils.database.Query; +import com.bgsoftware.wildloaders.utils.database.SQLHelper; +import com.bgsoftware.wildloaders.utils.database.StatementHolder; +import com.bgsoftware.wildloaders.utils.locations.LocationUtils; +import com.bgsoftware.wildloaders.utils.threads.Executor; +import org.bukkit.Bukkit; +import org.bukkit.Location; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public final class DataHandler { + + private final WildLoadersPlugin plugin; + + public DataHandler(WildLoadersPlugin plugin){ + this.plugin = plugin; + Executor.sync(() -> { + try { + SQLHelper.init(new File(plugin.getDataFolder(), "database.db")); + loadDatabase(); + }catch (Exception ex){ + ex.printStackTrace(); + Bukkit.getPluginManager().disablePlugin(plugin); + } + }, 2L); + } + + public void loadDatabase(){ + SQLHelper.executeUpdate("CREATE TABLE IF NOT EXISTS npc_identifiers (location TEXT NOT NULL PRIMARY KEY, uuid TEXT NOT NULL);"); + SQLHelper.executeQuery("SELECT * FROM npc_identifiers;", resultSet -> { + while (resultSet.next()) { + Location location = LocationUtils.getLocation(resultSet.getString("location")); + UUID uuid = UUID.fromString(resultSet.getString("uuid")); + plugin.getNPCs().registerUUID(location, uuid); + } + }); + + SQLHelper.executeUpdate("CREATE TABLE IF NOT EXISTS chunk_loaders (location TEXT NOT NULL PRIMARY KEY, placer TEXT NOT NULL, loader_data TEXT NOT NULL, timeLeft BIGINT NOT NULL);"); + SQLHelper.executeQuery("SELECT * FROM chunk_loaders;", resultSet -> { + while(resultSet.next()){ + Location location = LocationUtils.getLocation(resultSet.getString("location")); + UUID placer = UUID.fromString(resultSet.getString("placer")); + Optional loaderData = plugin.getLoaders().getLoaderData(resultSet.getString("loader_data")); + long timeLeft = resultSet.getLong("timeLeft"); + + if(!loaderData.isPresent()) + continue; + + if(location.getBlock().getType() != loaderData.get().getLoaderItem().getType()){ + WildLoadersPlugin.log("The chunk-loader at " + LocationUtils.getLocation(location) + " is invalid."); + continue; + } + + plugin.getLoaders().addChunkLoader(loaderData.get(), placer, location, timeLeft); + } + }); + } + + public void saveDatabase(){ + List chunkLoaderList = plugin.getLoaders().getChunkLoaders(); + Map chunkLoaderNPCList = plugin.getNPCs().getNPCs(); + + { + StatementHolder chunkLoadersHolder = Query.INSERT_CHUNK_LOADER.getStatementHolder(); + chunkLoadersHolder.prepareBatch(); + chunkLoaderList.stream().filter(chunkLoader -> chunkLoader.getTimeLeft() > 0).forEach(chunkLoader -> + ((WChunkLoader) chunkLoader).updateInsertStatement(chunkLoadersHolder).addBatch()); + chunkLoadersHolder.execute(false); + } + + { + StatementHolder chunkLoadersHolder = Query.DELETE_CHUNK_LOADER.getStatementHolder(); + chunkLoadersHolder.prepareBatch(); + chunkLoaderList.stream().filter(chunkLoader -> chunkLoader.getTimeLeft() <= 0).forEach(chunkLoader -> + chunkLoadersHolder.setLocation(chunkLoader.getLocation()).addBatch()); + chunkLoadersHolder.execute(false); + } + + { + StatementHolder npcIdentifierHolder = Query.INSERT_NPC_IDENTIFIER.getStatementHolder(); + npcIdentifierHolder.prepareBatch(); + chunkLoaderNPCList.forEach((identifier, npc) -> npcIdentifierHolder + .setLocation(identifier.getSpawnLocation()).setString(npc.getUniqueId().toString()).addBatch()); + npcIdentifierHolder.execute(false); + } + + } + + public void saveChunkLoadersTimes(){ + List chunkLoaderList = plugin.getLoaders().getChunkLoaders(); + + { + StatementHolder chunkLoadersHolder = Query.UPDATE_CHUNK_LOADER_TIME_LEFT.getStatementHolder(); + chunkLoadersHolder.prepareBatch(); + chunkLoaderList.stream().filter(chunkLoader -> chunkLoader.getTimeLeft() > 0).forEach(chunkLoader -> + chunkLoadersHolder.setLong(chunkLoader.getTimeLeft()).setLocation(chunkLoader.getLocation()).addBatch()); + chunkLoadersHolder.execute(false); + } + + { + StatementHolder chunkLoadersHolder = Query.DELETE_CHUNK_LOADER.getStatementHolder(); + chunkLoadersHolder.prepareBatch(); + chunkLoaderList.stream().filter(chunkLoader -> chunkLoader.getTimeLeft() <= 0).forEach(chunkLoader -> + chunkLoadersHolder.setLocation(chunkLoader.getLocation()).addBatch()); + chunkLoadersHolder.execute(false); + } + } + +} diff --git a/src/main/java/com/bgsoftware/wildloaders/handlers/LoadersHandler.java b/src/main/java/com/bgsoftware/wildloaders/handlers/LoadersHandler.java index 5e90118..053f12d 100644 --- a/src/main/java/com/bgsoftware/wildloaders/handlers/LoadersHandler.java +++ b/src/main/java/com/bgsoftware/wildloaders/handlers/LoadersHandler.java @@ -7,7 +7,9 @@ import com.bgsoftware.wildloaders.api.loaders.LoaderData; import com.bgsoftware.wildloaders.loaders.WChunkLoader; import com.bgsoftware.wildloaders.loaders.WLoaderData; import com.bgsoftware.wildloaders.utils.chunks.ChunkPosition; +import com.bgsoftware.wildloaders.utils.database.Query; import com.google.common.collect.Maps; +import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -18,9 +20,12 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.UUID; public final class LoadersHandler implements LoadersManager { + private static final long TIMERS_UPDATE_INTERVAL = 300L; + private final Map chunkLoaders = Maps.newConcurrentMap(); private final Map chunkLoadersByChunks = Maps.newConcurrentMap(); private final Map loadersData = Maps.newConcurrentMap(); @@ -28,6 +33,8 @@ public final class LoadersHandler implements LoadersManager { public LoadersHandler(WildLoadersPlugin plugin){ this.plugin = plugin; + + Bukkit.getScheduler().runTaskTimer(plugin, plugin.getDataHandler()::saveChunkLoadersTimes, TIMERS_UPDATE_INTERVAL, TIMERS_UPDATE_INTERVAL); } @Override @@ -57,10 +64,17 @@ public final class LoadersHandler implements LoadersManager { @Override public ChunkLoader addChunkLoader(LoaderData loaderData, Player whoPlaced, Location location, long timeLeft) { - ChunkLoader chunkLoader = new WChunkLoader(loaderData.getName(), whoPlaced, location, timeLeft); + WChunkLoader chunkLoader = addChunkLoader(loaderData, whoPlaced.getUniqueId(), location, timeLeft); + chunkLoader.updateInsertStatement(Query.INSERT_CHUNK_LOADER.getStatementHolder()).execute(true); + return chunkLoader; + } + + public WChunkLoader addChunkLoader(LoaderData loaderData, UUID placer, Location location, long timeLeft){ + WChunkLoader chunkLoader = new WChunkLoader(loaderData.getName(), placer, location, timeLeft); chunkLoaders.put(location, chunkLoader); chunkLoadersByChunks.put(ChunkPosition.of(location), chunkLoader); plugin.getNPCs().createNPC(location); + System.out.println("Adding chunk loader for " + location); return chunkLoader; } @@ -70,6 +84,10 @@ public final class LoadersHandler implements LoadersManager { chunkLoaders.remove(location); chunkLoadersByChunks.remove(ChunkPosition.of(location)); chunkLoader.getNPC().ifPresent(npc -> plugin.getNPCs().killNPC(npc)); + + Query.DELETE_CHUNK_LOADER.getStatementHolder() + .setLocation(location) + .execute(true); } @Override @@ -85,6 +103,7 @@ public final class LoadersHandler implements LoadersManager { @Override public void removeChunkLoaders() { + chunkLoaders.values().forEach(chunkLoader -> plugin.getNMSAdapter().removeLoader(chunkLoader, false)); chunkLoaders.clear(); chunkLoadersByChunks.clear(); } diff --git a/src/main/java/com/bgsoftware/wildloaders/handlers/NPCHandler.java b/src/main/java/com/bgsoftware/wildloaders/handlers/NPCHandler.java index 4622c84..3301dfb 100644 --- a/src/main/java/com/bgsoftware/wildloaders/handlers/NPCHandler.java +++ b/src/main/java/com/bgsoftware/wildloaders/handlers/NPCHandler.java @@ -3,19 +3,15 @@ package com.bgsoftware.wildloaders.handlers; import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.api.managers.NPCManager; import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; +import com.bgsoftware.wildloaders.npc.NPCIdentifier; import com.bgsoftware.wildloaders.utils.ServerVersion; -import com.bgsoftware.wildloaders.utils.locations.LocationUtils; -import com.bgsoftware.wildloaders.utils.threads.Executor; +import com.bgsoftware.wildloaders.utils.database.Query; import com.google.common.collect.Maps; -import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.LivingEntity; -import java.io.File; +import java.util.Collections; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -29,7 +25,6 @@ public final class NPCHandler implements NPCManager { public NPCHandler(WildLoadersPlugin plugin){ this.plugin = plugin; - loadUUIDs(); } @Override @@ -55,7 +50,10 @@ public final class NPCHandler implements NPCManager { npcs.remove(identifier); npcUUIDs.remove(identifier); - saveUUIDs(); + + Query.DELETE_NPC_IDENTIFIER.getStatementHolder() + .setLocation(identifier.getSpawnLocation()) + .execute(true); npc.die(); } @@ -70,20 +68,12 @@ public final class NPCHandler implements NPCManager { npcs.clear(); } - private void loadUUIDs(){ - File file = new File(plugin.getDataFolder(), "uuids.yml"); + public Map getNPCs() { + return Collections.unmodifiableMap(npcs); + } - if(!file.exists()) - return; - - YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); - - for(String location : cfg.getConfigurationSection("").getKeys(false)){ - try{ - Location _location = LocationUtils.getLocation(location); - npcUUIDs.put(new NPCIdentifier(_location), UUID.fromString(cfg.getString(location))); - }catch(Exception ignored){} - } + public void registerUUID(Location location, UUID uuid){ + npcUUIDs.put(new NPCIdentifier(location), uuid); } private UUID getUUID(NPCIdentifier identifier){ @@ -98,67 +88,12 @@ public final class NPCHandler implements NPCManager { npcUUIDs.put(identifier, uuid); - saveUUIDs(); + Query.INSERT_NPC_IDENTIFIER.getStatementHolder() + .setLocation(identifier.getSpawnLocation()) + .setString(uuid.toString()) + .execute(true); return uuid; } - @SuppressWarnings("ResultOfMethodCallIgnored") - private void saveUUIDs(){ - if(Bukkit.isPrimaryThread()){ - Executor.async(this::saveUUIDs); - return; - } - - File file = new File(plugin.getDataFolder(), "uuids.yml"); - - if(!file.exists()) - file.delete(); - - YamlConfiguration cfg = new YamlConfiguration(); - - for(Map.Entry entry : npcUUIDs.entrySet()) - cfg.set(LocationUtils.getLocation(entry.getKey().getSpawnLocation()), entry.getValue() + ""); - - try{ - file.getParentFile().mkdirs(); - file.createNewFile(); - cfg.save(file); - }catch(Exception ex){ - ex.printStackTrace(); - } - } - - private static final class NPCIdentifier{ - - private final Object identifier; - - NPCIdentifier(Location location){ - this.identifier = PER_WORLD_NPCS ? location.getWorld() : location; - } - - Location getSpawnLocation(){ - return PER_WORLD_NPCS ? ((World) identifier).getSpawnLocation() : (Location) identifier; - } - - @Override - public String toString() { - return PER_WORLD_NPCS ? ((World) identifier).getName() : identifier.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - NPCIdentifier that = (NPCIdentifier) o; - return Objects.equals(identifier, that.identifier); - } - - @Override - public int hashCode() { - return Objects.hash(identifier); - } - - } - } diff --git a/src/main/java/com/bgsoftware/wildloaders/loaders/WChunkLoader.java b/src/main/java/com/bgsoftware/wildloaders/loaders/WChunkLoader.java index 5cf7d36..5c12f7f 100644 --- a/src/main/java/com/bgsoftware/wildloaders/loaders/WChunkLoader.java +++ b/src/main/java/com/bgsoftware/wildloaders/loaders/WChunkLoader.java @@ -4,12 +4,12 @@ import com.bgsoftware.wildloaders.WildLoadersPlugin; import com.bgsoftware.wildloaders.api.loaders.ChunkLoader; import com.bgsoftware.wildloaders.api.loaders.LoaderData; import com.bgsoftware.wildloaders.api.npc.ChunkLoaderNPC; +import com.bgsoftware.wildloaders.utils.database.StatementHolder; import com.bgsoftware.wildloaders.utils.threads.Executor; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.util.Optional; @@ -26,9 +26,9 @@ public final class WChunkLoader implements ChunkLoader { private boolean active = true; private long timeLeft; - public WChunkLoader(String loaderName, Player whoPlaced, Location location, long timeLeft){ + public WChunkLoader(String loaderName, UUID whoPlaced, Location location, long timeLeft){ this.loaderName = loaderName; - this.whoPlaced = whoPlaced.getUniqueId(); + this.whoPlaced = whoPlaced; this.location = location.clone(); this.timeLeft = timeLeft; plugin.getNMSAdapter().createLoader(this); @@ -91,4 +91,13 @@ public final class WChunkLoader implements ChunkLoader { return plugin.getNMSAdapter().setTag(itemStack, "loader-time", getTimeLeft()); } + public StatementHolder updateInsertStatement(StatementHolder statementHolder){ + statementHolder.setLocation(getLocation()) + .setString(whoPlaced.toString()) + .setString(getLoaderData().getName()) + .setLong(getTimeLeft()); + + return statementHolder; + } + } diff --git a/src/main/java/com/bgsoftware/wildloaders/npc/NPCIdentifier.java b/src/main/java/com/bgsoftware/wildloaders/npc/NPCIdentifier.java new file mode 100644 index 0000000..bb78a72 --- /dev/null +++ b/src/main/java/com/bgsoftware/wildloaders/npc/NPCIdentifier.java @@ -0,0 +1,41 @@ +package com.bgsoftware.wildloaders.npc; + +import com.bgsoftware.wildloaders.utils.ServerVersion; +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.Objects; + +public final class NPCIdentifier { + + private static final boolean PER_WORLD_NPCS = ServerVersion.isLessThan(ServerVersion.v1_14); + + private final Object identifier; + + public NPCIdentifier(Location location){ + this.identifier = PER_WORLD_NPCS ? location.getWorld() : location; + } + + public Location getSpawnLocation(){ + return PER_WORLD_NPCS ? new Location((World) identifier, 0, 1, 0) : (Location) identifier; + } + + @Override + public String toString() { + return PER_WORLD_NPCS ? ((World) identifier).getName() : identifier.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NPCIdentifier that = (NPCIdentifier) o; + return Objects.equals(identifier, that.identifier); + } + + @Override + public int hashCode() { + return Objects.hash(identifier); + } + +} diff --git a/src/main/java/com/bgsoftware/wildloaders/utils/database/Query.java b/src/main/java/com/bgsoftware/wildloaders/utils/database/Query.java new file mode 100644 index 0000000..c9faa2c --- /dev/null +++ b/src/main/java/com/bgsoftware/wildloaders/utils/database/Query.java @@ -0,0 +1,25 @@ +package com.bgsoftware.wildloaders.utils.database; + +public enum Query { + + UPDATE_CHUNK_LOADER_TIME_LEFT("UPDATE chunk_loaders SET timeLeft=? WHERE location=?;"), + INSERT_CHUNK_LOADER("REPLACE INTO chunk_loaders(location, placer, loader_data, timeLeft) VALUES(?,?,?,?);"), + DELETE_CHUNK_LOADER("DELETE FROM chunk_loaders WHERE location=?;"), + + INSERT_NPC_IDENTIFIER("REPLACE INTO npc_identifiers(location, uuid) VALUES(?,?);"), + DELETE_NPC_IDENTIFIER("DELETE FROM npc_identifiers WHERE location=?;"); + + private final String query; + + Query(String query) { + this.query = query; + } + + public String getStatement(){ + return query; + } + + public StatementHolder getStatementHolder(){ + return new StatementHolder(this); + } +} diff --git a/src/main/java/com/bgsoftware/wildloaders/utils/database/SQLHelper.java b/src/main/java/com/bgsoftware/wildloaders/utils/database/SQLHelper.java new file mode 100644 index 0000000..029fd09 --- /dev/null +++ b/src/main/java/com/bgsoftware/wildloaders/utils/database/SQLHelper.java @@ -0,0 +1,110 @@ +package com.bgsoftware.wildloaders.utils.database; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.function.Consumer; + +@SuppressWarnings("WeakerAccess") +public final class SQLHelper { + + private static final Object mutex = new Object(); + private static Connection conn; + + private SQLHelper(){} + + @SuppressWarnings("ResultOfMethodCallIgnored") + public static void init(File file) throws ClassNotFoundException, SQLException { + if(!file.exists()){ + try { + file.getParentFile().mkdirs(); + file.createNewFile(); + }catch(Exception ex){ + ex.printStackTrace(); + return; + } + } + + Class.forName("org.sqlite.JDBC"); + String sqlURL = "jdbc:sqlite:" + file.getAbsolutePath().replace("\\", "/"); + conn = DriverManager.getConnection(sqlURL); + } + + public static Object getMutex(){ + return mutex; + } + + public static void executeUpdate(String statement){ + try(PreparedStatement preparedStatement = conn.prepareStatement(statement)){ + preparedStatement.executeUpdate(); + }catch(SQLException ex){ + ex.printStackTrace(); + } + } + + public static boolean doesConditionExist(StatementHolder statementHolder){ + boolean ret = false; + + try(PreparedStatement preparedStatement = statementHolder.getStatement(); ResultSet resultSet = preparedStatement.executeQuery()){ + ret = resultSet.next(); + }catch(SQLException ex){ + ex.printStackTrace(); + } + + return ret; + } + + public static void executeQuery(String statement, QueryCallback callback){ + executeQuery(statement, callback, null); + } + + public static void executeQuery(String statement, QueryCallback callback, Consumer onFailure){ + try(PreparedStatement preparedStatement = conn.prepareStatement(statement); ResultSet resultSet = preparedStatement.executeQuery()){ + callback.run(resultSet); + }catch(SQLException ex){ + if(onFailure == null) + ex.printStackTrace(); + else + onFailure.accept(ex); + } + } + + public static void setAutoCommit(boolean autoCommit){ + try { + conn.setAutoCommit(autoCommit); + }catch(SQLException ex){ + ex.printStackTrace(); + } + } + + public static void commit(){ + try { + conn.commit(); + }catch(SQLException ex){ + ex.printStackTrace(); + } + } + + public static void close(){ + try{ + conn.close(); + }catch(SQLException ex){ + ex.printStackTrace(); + } + } + + public static PreparedStatement buildStatement(String query) throws SQLException { + return conn.prepareStatement(query); + } + + public interface QueryCallback{ + + void run(ResultSet resultSet) throws SQLException; + + } + +} + diff --git a/src/main/java/com/bgsoftware/wildloaders/utils/database/StatementHolder.java b/src/main/java/com/bgsoftware/wildloaders/utils/database/StatementHolder.java new file mode 100644 index 0000000..41a8dc6 --- /dev/null +++ b/src/main/java/com/bgsoftware/wildloaders/utils/database/StatementHolder.java @@ -0,0 +1,114 @@ +package com.bgsoftware.wildloaders.utils.database; + +import com.bgsoftware.wildloaders.WildLoadersPlugin; +import com.bgsoftware.wildloaders.utils.locations.LocationUtils; +import com.bgsoftware.wildloaders.utils.threads.Executor; +import org.bukkit.Location; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("WeakerAccess") +public class StatementHolder { + + private final List> batches = new ArrayList<>(); + private boolean batchStatus = false; + + private final String query; + private final Map values = new HashMap<>(); + private int currentIndex = 1; + + StatementHolder(Query query){ + this.query = query.getStatement(); + } + + public StatementHolder setString(String value){ + values.put(currentIndex++, value); + return this; + } + + public StatementHolder setInt(int value){ + values.put(currentIndex++, value); + return this; + } + + public StatementHolder setDouble(double value){ + values.put(currentIndex++, value); + return this; + } + + public StatementHolder setLong(long value){ + values.put(currentIndex++, value); + return this; + } + + public StatementHolder setBoolean(boolean value){ + values.put(currentIndex++, value); + return this; + } + + public StatementHolder setLocation(Location loc){ + values.put(currentIndex++, loc == null ? "" : LocationUtils.getLocation(loc)); + return this; + } + + public void prepareBatch(){ + batchStatus = true; + } + + public void addBatch(){ + batches.add(new HashMap<>(values)); + values.clear(); + currentIndex = 1; + } + + public PreparedStatement getStatement() throws SQLException { + PreparedStatement preparedStatement = SQLHelper.buildStatement(query); + for(Map.Entry entry : values.entrySet()) { + preparedStatement.setObject(entry.getKey(), entry.getValue()); + } + return preparedStatement; + } + + public void execute(boolean async) { + if(async){ + Executor.data(() -> execute(false)); + return; + } + + synchronized (SQLHelper.getMutex()) { + String errorQuery = query; + try (PreparedStatement preparedStatement = SQLHelper.buildStatement(query)) { + if (!batches.isEmpty()) { + SQLHelper.setAutoCommit(false); + for (Map values : batches) { + for (Map.Entry entry : values.entrySet()) { + preparedStatement.setObject(entry.getKey(), entry.getValue()); + errorQuery = errorQuery.replaceFirst("\\?", entry.getValue() + ""); + } + preparedStatement.addBatch(); + } + preparedStatement.executeBatch(); + SQLHelper.commit(); + SQLHelper.setAutoCommit(true); + } else if (!batchStatus) { + for (Map.Entry entry : values.entrySet()) { + preparedStatement.setObject(entry.getKey(), entry.getValue()); + errorQuery = errorQuery.replaceFirst("\\?", entry.getValue() + ""); + } + preparedStatement.executeUpdate(); + } + } catch (SQLException ex) { + WildLoadersPlugin.log("Failed to execute query " + errorQuery); + ex.printStackTrace(); + } finally { + batchStatus = false; + } + } + } + +} diff --git a/src/main/java/com/bgsoftware/wildloaders/utils/locations/LocationUtils.java b/src/main/java/com/bgsoftware/wildloaders/utils/locations/LocationUtils.java index 05ef976..8a9efb5 100644 --- a/src/main/java/com/bgsoftware/wildloaders/utils/locations/LocationUtils.java +++ b/src/main/java/com/bgsoftware/wildloaders/utils/locations/LocationUtils.java @@ -8,7 +8,12 @@ public final class LocationUtils { private LocationUtils(){} public static String getLocation(Location location){ - return location.getWorld().getName() + "," + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ(); + try { + return location.getWorld().getName() + "," + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ(); + }catch (Exception ex){ + System.out.println(location); + throw ex; + } } public static Location getLocation(String location){