From 0cccf50a8579a14206652266afe804f279a2c84d Mon Sep 17 00:00:00 2001 From: Paldiu Date: Mon, 15 Apr 2024 21:17:10 -0500 Subject: [PATCH] 1.4.0 Update Feature Update: - SQL Support (MySQL, REDIS, SQLite) - Global Verbosity Control - Reimplemented Experimental OreVein --- build.gradle | 3 +- .../io/github/simplex/api/LuckContainer.java | 52 +++++- .../java/io/github/simplex/lib/Messages.java | 3 +- .../java/io/github/simplex/luck/Config.java | 105 +++++++++++- .../io/github/simplex/luck/FeelingLucky.java | 150 +++++++++++++----- .../github/simplex/luck/listener/OreVein.java | 70 ++++---- .../simplex/luck/player/DynamicConfig.java | 51 ++++++ .../io/github/simplex/luck/player/Luck.java | 9 +- .../simplex/luck/player/PlayerConfig.java | 41 ++++- .../simplex/luck/player/PlayerHandler.java | 3 +- .../io/github/simplex/luck/util/LuckCMD.java | 6 + .../java/io/github/simplex/sql/MySQL.java | 94 +++++++++++ .../java/io/github/simplex/sql/Redis.java | 77 +++++++++ .../java/io/github/simplex/sql/SQLType.java | 17 ++ .../java/io/github/simplex/sql/SQLite.java | 83 ++++++++++ .../github/simplex/sql/users/MySQLUser.java | 67 ++++++++ .../github/simplex/sql/users/RedisUser.java | 37 +++++ .../github/simplex/sql/users/SQLiteUser.java | 65 ++++++++ src/main/resources/config.yml | 32 +++- 19 files changed, 884 insertions(+), 81 deletions(-) create mode 100644 src/main/java/io/github/simplex/luck/player/DynamicConfig.java create mode 100644 src/main/java/io/github/simplex/sql/MySQL.java create mode 100644 src/main/java/io/github/simplex/sql/Redis.java create mode 100644 src/main/java/io/github/simplex/sql/SQLType.java create mode 100644 src/main/java/io/github/simplex/sql/SQLite.java create mode 100644 src/main/java/io/github/simplex/sql/users/MySQLUser.java create mode 100644 src/main/java/io/github/simplex/sql/users/RedisUser.java create mode 100644 src/main/java/io/github/simplex/sql/users/SQLiteUser.java diff --git a/build.gradle b/build.gradle index d18acb1..170c06e 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,8 @@ repositories { } dependencies { - compileOnly("io.papermc.paper:paper-api:1.20.3-R0.1-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT") + implementation 'redis.clients:jedis:3.7.0' } def targetJavaVersion = 17 diff --git a/src/main/java/io/github/simplex/api/LuckContainer.java b/src/main/java/io/github/simplex/api/LuckContainer.java index 9a8e12f..f6cb481 100644 --- a/src/main/java/io/github/simplex/api/LuckContainer.java +++ b/src/main/java/io/github/simplex/api/LuckContainer.java @@ -3,20 +3,66 @@ package io.github.simplex.api; import java.io.Serializable; import org.bukkit.entity.Player; -public interface LuckContainer extends Serializable -{ +/** + * The LuckContainer interface represents a container for player luck. + * It provides methods to get and set the verbosity of the luck container, + * check if a number matches or is close to the luck value, get the multiplier, + * get the associated player, and get the luck value. + * + * This interface is Serializable, which means it can be written to a stream + * and restored. + */ +public interface LuckContainer extends Serializable { + /** + * Checks if the luck container is verbose. + * + * @return true if the luck container is verbose, false otherwise. + */ boolean isVerbose(); + /** + * Sets the verbosity of the luck container. + * + * @param verbose the verbosity to set. + */ void setVerbose(boolean verbose); + /** + * Checks if a number matches the luck value. + * + * @param number the number to check. + * @return true if the number matches the luck value, false otherwise. + */ boolean isMatch(double number); + /** + * Checks if a number is close to the luck value within a certain range. + * + * @param number the number to check. + * @param range the range within which the number is considered close. + * @return true if the number is close to the luck value, false otherwise. + */ boolean isClose(double number, int range); + /** + * Gets the multiplier of the luck container. + * + * @return the multiplier. + */ double multiplier(); + /** + * Gets the player associated with the luck container. + * + * @return the associated player. + */ Player associatedPlayer(); + /** + * Gets the luck value of the luck container. + * + * @return the luck value. + */ double getValue(); -} +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/lib/Messages.java b/src/main/java/io/github/simplex/lib/Messages.java index 51abc66..0f79218 100644 --- a/src/main/java/io/github/simplex/lib/Messages.java +++ b/src/main/java/io/github/simplex/lib/Messages.java @@ -8,7 +8,8 @@ public enum Messages NOT_FROM_CONSOLE(MiniComponent.err("This command may only be used in game.")), NO_PERMISSION(MiniComponent.err("You do not have permission to use this command.")), NO_PLAYER(MiniComponent.warn("That player cannot be found.")), - OUT_OF_BOUNDS(MiniComponent.err("Number must be between -1024.0 and 1024.0")); + OUT_OF_BOUNDS(MiniComponent.err("Number must be between -1024.0 and 1024.0")), + VERBOSE_DISABLED(MiniComponent.err("Verbose mode is currently disabled globally.")); private final ComponentLike message; diff --git a/src/main/java/io/github/simplex/luck/Config.java b/src/main/java/io/github/simplex/luck/Config.java index 81025ef..0f7c3df 100644 --- a/src/main/java/io/github/simplex/luck/Config.java +++ b/src/main/java/io/github/simplex/luck/Config.java @@ -6,10 +6,12 @@ import io.github.simplex.luck.util.SneakyWorker; import java.io.File; import java.util.HashMap; import java.util.Map; +import java.util.Objects; + +import io.github.simplex.sql.SQLType; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; -@SuppressWarnings("ResultOfMethodCallIgnored") public class Config extends YamlConfiguration { private final Map configEntries = new HashMap<>() @@ -17,6 +19,7 @@ public class Config extends YamlConfiguration put("high_rarity_chance", 512.0); put("medium_rarity_chance", 128.0); put("low_rarity_chance", 64.0); + put("global_verbosity", true); put("block_drops", "LOW"); put("bonemeal", "MED"); put("cheat_death", "MED"); @@ -32,7 +35,7 @@ public class Config extends YamlConfiguration put("take_damage", "MED"); put("unbreakable", "HIGH"); }}; - private File configFile; + private final File configFile; public Config(FeelingLucky plugin) { @@ -113,4 +116,102 @@ public class Config extends YamlConfiguration { return getDouble(path); } + + public boolean isVerboseGlobal() { + return getBoolean("global_verbosity"); + } + + public SQLType getSQLType() { + return SQLType.fromString(Objects.requireNonNull(getString("database_type"))); + } + + public SQLiteWrapper getSQLite() { + return new SQLiteWrapper(); + } + + public RedisWrapper getRedis() { + return new RedisWrapper(); + } + + public MySQLWrapper getMySQL() { + return new MySQLWrapper(); + } + + public final class SQLiteWrapper { + private final String path; + + public SQLiteWrapper() { + this.path = getString("sqlite.path"); + } + + public String getPath() { + return path; + } + } + + public final class RedisWrapper { + private final String host; + private final String port; + private final String password; + private final int database; + + public RedisWrapper() { + this.host = getString("redis.host"); + this.port = getString("redis.port"); + this.password = getString("redis.password"); + this.database = getInt("redis.database"); + } + + public String getHost() { + return host; + } + + public String getPort() { + return port; + } + + public String getPassword() { + return password; + } + + public int getDatabase() { + return database; + } + } + + public final class MySQLWrapper { + private final String host; + private final int port; + private final String database; + private final String username; + private final String password; + + public MySQLWrapper() { + this.host = getString("mysql.host"); + this.port = getInt("mysql.port"); + this.database = getString("mysql.database"); + this.username = getString("mysql.username"); + this.password = getString("mysql.password"); + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public String getDatabase() { + return database; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + } } diff --git a/src/main/java/io/github/simplex/luck/FeelingLucky.java b/src/main/java/io/github/simplex/luck/FeelingLucky.java index e60143e..0ef20f7 100644 --- a/src/main/java/io/github/simplex/luck/FeelingLucky.java +++ b/src/main/java/io/github/simplex/luck/FeelingLucky.java @@ -3,23 +3,30 @@ package io.github.simplex.luck; import io.github.simplex.luck.listener.*; import io.github.simplex.luck.player.PlayerConfig; import io.github.simplex.luck.player.PlayerHandler; +import io.github.simplex.luck.util.Logs; import io.github.simplex.luck.util.LuckCMD; import io.github.simplex.luck.util.RegenerateConfigCMD; import io.github.simplex.luck.util.SpecialFootItem; import io.github.simplex.metrics.Metrics; + import java.io.File; +import java.sql.SQLException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; + +import io.github.simplex.sql.MySQL; +import io.github.simplex.sql.Redis; +import io.github.simplex.sql.SQLType; +import io.github.simplex.sql.SQLite; import net.kyori.adventure.chat.ChatType; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandMap; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; -public final class FeelingLucky extends JavaPlugin -{ +public final class FeelingLucky extends JavaPlugin { private final Map configMap = new HashMap<>(); private final File playerDirectory = new File(getDataFolder(), "players"); private final SpecialFootItem specialFootItem = new SpecialFootItem(); @@ -27,22 +34,28 @@ public final class FeelingLucky extends JavaPlugin private PlayerHandler handler; private Config config; - public Map getConfigMap() - { + private MySQL mysql; + private SQLite sqlite; + private Redis Redis; + + private boolean shouldLoadPhysical = false; + + public Map getConfigMap() { return configMap; } @Override - public void onEnable() - { + public void onEnable() { getLogger().info("Initializing metrics..."); new Metrics(this, 15054); - getLogger().info("Metrics loaded. Initializing the PlayerHandler..."); - handler = new PlayerHandler(this); + getLogger().info("Metrics loaded. Initializing SQL..."); + initSQL(); getLogger().info("Initialization complete! Attempting to register the Listeners..."); registerListeners(); - getLogger().info("Registration complete! Attempting to load all player configuration files..."); + getLogger().info("Registration complete! Attempting to load all saved player configurations..."); loadPlayerConfigurations(); + getLogger().info("Player configurations loaded! Initializing PlayerHandler..."); + handler = new PlayerHandler(this); getLogger().info("Attempting to load the main configuration..."); config = new Config(this); getLogger().info("Main Config loaded successfully! Loading commands..."); @@ -54,8 +67,7 @@ public final class FeelingLucky extends JavaPlugin } @Override - public void onDisable() - { + public void onDisable() { getLogger().info("Saving all player configurations..."); configMap.values().forEach(PlayerConfig::save); getLogger().info("Complete! Saving the main config..."); @@ -63,35 +75,98 @@ public final class FeelingLucky extends JavaPlugin getLogger().info("Complete! Goodbye! :)"); } - private void loadPlayerConfigurations() - { - if (!playerDirectory.exists()) - { + private void initSQL() { + switch (config.getSQLType()) { + case MYSQL -> { + try { + mysql = new MySQL(this); + } catch (Exception e) { + getLogger().severe("Failed to initialize MySQL. Falling back to standard plugin configuration."); + Logs.error(e); + shouldLoadPhysical(true); + } + } + case SQLITE -> { + try { + sqlite = new SQLite(this); + } catch (SQLException e) { + getLogger().severe("Failed to initialize SQLite. Falling back to standard plugin configuration."); + Logs.error(e); + shouldLoadPhysical(true); + } + } + case REDIS -> { + Redis = new Redis(this); + } + } + } + + private void saveToSQL() { + switch (config.getSQLType()) { + case MYSQL -> { + mysql.savePlayers(); + } + case SQLITE -> { + try { + sqlite.savePlayers(); + } catch (Exception e) { + Logs.error(e); + } + } + case REDIS -> { + Redis = new Redis(this); + Redis.savePlayers(); + } + } + } + + private void loadPlayersFromSQL() { + switch (config.getSQLType()) { + case MYSQL -> { + mysql.loadPlayers(); + } + case SQLITE -> { + try { + sqlite.loadPlayers(); + } catch (SQLException e) { + Logs.error(e); + } + } + case REDIS -> { + Redis.loadPlayers(); + } + } + } + + private void loadPlayerConfigurations() { + if (!playerDirectory.exists()) { getLogger().info("No directory exists. Creating..."); playerDirectory.mkdirs(); getLogger().info("Created new directory \"FeelingLucky/players\"."); return; } + if (config.getSQLType() != SQLType.NONE && !shouldLoadPhysical()) { + loadPlayersFromSQL(); + getLogger().info("Successfully loaded all configurations from SQL!"); + return; + } + File[] files = playerDirectory.listFiles(); - if (files != null) - { + if (files != null) { Arrays.stream(files).forEach(file -> - { - UUID uuid = UUID.fromString(file.getName().split("\\.")[0]); - configMap.put(uuid, PlayerConfig.initFrom(this, file)); - }); + { + UUID uuid = UUID.fromString(file.getName().split("\\.")[0]); + configMap.put(uuid, PlayerConfig.initFromFile(this, file)); + }); configMap.forEach((u, pc) -> pc.load()); getLogger().info("Successfully loaded all configurations!"); - } - else - { + } else { getLogger().info("There are no player configurations to load."); } } - private void registerListeners() - { + private void registerListeners() { new BlockDrops(this); new BonemealFullCrop(this); new CheatDeath(this); @@ -111,30 +186,33 @@ public final class FeelingLucky extends JavaPlugin new VillagerInventory(this); } - public PlayerHandler getHandler() - { + public PlayerHandler getHandler() { return handler; } @Override @NotNull - public Config getConfig() - { + public Config getConfig() { return config; } - public SpecialFootItem getFoot() - { + public SpecialFootItem getFoot() { return specialFootItem; } - public CommandMap getCommandMap() - { + private void shouldLoadPhysical(boolean state) { + shouldLoadPhysical = state; + } + + private boolean shouldLoadPhysical() { + return shouldLoadPhysical; + } + + public CommandMap getCommandMap() { return getServer().getCommandMap(); } - public ChatType.Bound bind() - { + public ChatType.Bound bind() { return bind; } } diff --git a/src/main/java/io/github/simplex/luck/listener/OreVein.java b/src/main/java/io/github/simplex/luck/listener/OreVein.java index 4378504..f9368ec 100644 --- a/src/main/java/io/github/simplex/luck/listener/OreVein.java +++ b/src/main/java/io/github/simplex/luck/listener/OreVein.java @@ -3,25 +3,23 @@ package io.github.simplex.luck.listener; import io.github.simplex.lib.MiniComponent; import io.github.simplex.luck.FeelingLucky; import io.github.simplex.luck.player.Luck; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.block.BlockBreakEvent; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; -/** - * This class is currently unstable. - */ -@Deprecated @ApiStatus.Experimental public class OreVein extends AbstractListener { @@ -35,31 +33,45 @@ public class OreVein extends AbstractListener { Player player = event.getPlayer(); Luck luck = plugin.getHandler().getLuckContainer(player); if (luck.quickRNG(luck.getValue()) && doesQualify("ore_vein", luck.getValue()) && event.getBlock().isValidTool(player.getInventory().getItemInMainHand())) { - getOresInArea(event.getBlock()).forEach(Block::breakNaturally); - player.sendMessage(MiniComponent.info("Your luck has let you mine all the blocks with one swing.")); + Material minedBlockType = event.getBlock().getType(); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + getOresInArea(event.getBlock(), minedBlockType).forEach(Block::breakNaturally); + player.sendMessage(MiniComponent.info("Your luck has let you mine all the blocks with one swing.")); + }); } } - public List getOresInArea(@NotNull Block block) { - Stream.Builder streamBuilder = Stream.builder(); - Location start = block.getLocation(); - World world = block.getWorld(); - List> materialList = List.of( - Tag.COAL_ORES, Tag.COPPER_ORES, Tag.DIAMOND_ORES, - Tag.GOLD_ORES, Tag.IRON_ORES, Tag.EMERALD_ORES, - Tag.LAPIS_ORES, Tag.REDSTONE_ORES - ); - for (int x = start.getBlockX() - 15; x <= start.getBlockX() + 15; x++) { - for (int y = start.getBlockY() - 15; y <= start.getBlockY() + 15; y++) { - for (int z = start.getBlockZ() - 15; z <= start.getBlockZ() + 15; z++) { - Location location = new Location(world, x, y, z); - Material blockType = location.getBlock().getType(); - if (materialList.stream().anyMatch(tag -> tag.isTagged(blockType))) { - streamBuilder.add(location.getBlock()); - } + public Set getOresInArea(@NotNull Block block, Material minedBlockType) { + Set blocks = new HashSet<>(); + Queue queue = new LinkedList<>(); + Set visited = new HashSet<>(); + Location initialLocation = block.getLocation(); + + queue.add(block); + visited.add(initialLocation); + + while (!queue.isEmpty()) { + Block currentBlock = queue.poll(); + Location currentLocation = currentBlock.getLocation(); + + // Check if the current block is within the maximum radius from the initial block + if (initialLocation.distance(currentLocation) > 16) { + continue; + } + + blocks.add(currentBlock); + + for (BlockFace face : BlockFace.values()) { + Block neighbour = currentBlock.getRelative(face); + Location neighbourLocation = neighbour.getLocation(); + + if (!visited.contains(neighbourLocation) && neighbour.getType().equals(minedBlockType)) { + queue.add(neighbour); + visited.add(neighbourLocation); } } } - return streamBuilder.build().collect(Collectors.toList()); + + return blocks; } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/luck/player/DynamicConfig.java b/src/main/java/io/github/simplex/luck/player/DynamicConfig.java new file mode 100644 index 0000000..4687495 --- /dev/null +++ b/src/main/java/io/github/simplex/luck/player/DynamicConfig.java @@ -0,0 +1,51 @@ +package io.github.simplex.luck.player; + +import java.util.UUID; + +public class DynamicConfig { + private UUID playerUUID; + private String username; + private double luckValue; + private boolean isVerbose; + private double multiplier; + + public String getPlayerUUID() { + return playerUUID.toString(); + } + + public void setPlayerUUID(UUID playerUUID) { + this.playerUUID = playerUUID; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public double getLuckValue() { + return luckValue; + } + + public void setLuckValue(double luckValue) { + this.luckValue = luckValue; + } + + public boolean isVerbose() { + return isVerbose; + } + + public void setVerbose(boolean isVerbose) { + this.isVerbose = isVerbose; + } + + public double getMultiplier() { + return multiplier; + } + + public void setMultiplier(double multiplier) { + this.multiplier = multiplier; + } +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/luck/player/Luck.java b/src/main/java/io/github/simplex/luck/player/Luck.java index 4bfc4a6..5469001 100644 --- a/src/main/java/io/github/simplex/luck/player/Luck.java +++ b/src/main/java/io/github/simplex/luck/player/Luck.java @@ -88,12 +88,19 @@ public class Luck implements LuckContainer { @Override public void setVerbose(final boolean verbose) { + if (!plugin.getConfig().isVerboseGlobal()) + return; + this.verbose = verbose; } @Override public boolean isVerbose() { - return verbose; + if (plugin.getConfig().isVerboseGlobal()) { + return verbose; + } + + return false; } @Override diff --git a/src/main/java/io/github/simplex/luck/player/PlayerConfig.java b/src/main/java/io/github/simplex/luck/player/PlayerConfig.java index 38472bc..55dc149 100644 --- a/src/main/java/io/github/simplex/luck/player/PlayerConfig.java +++ b/src/main/java/io/github/simplex/luck/player/PlayerConfig.java @@ -20,13 +20,12 @@ public class PlayerConfig private final FeelingLucky plugin; private YamlConfiguration config; - @SuppressWarnings("ResultOfMethodCallIgnored") + public PlayerConfig(FeelingLucky plugin, Player player) { this.plugin = plugin; this.player = player; - final File file = configFile(plugin, player); - configFile = file; + configFile = configFile(plugin, player); config = YamlConfiguration.loadConfiguration(configFile); String tempUsername = config.getString("username"); @@ -36,6 +35,7 @@ public class PlayerConfig config.set("username", player.getName()); config.set("luck", plugin.getHandler().getLuckContainer(player).getDefaultValue()); config.set("multiplier", "1.0"); + config.set("verbose", plugin.getConfig().isVerboseGlobal()); save(); } } @@ -48,14 +48,43 @@ public class PlayerConfig config = YamlConfiguration.loadConfiguration(configFile); } + protected PlayerConfig(FeelingLucky plugin, DynamicConfig user) + { + this.plugin = plugin; + this.player = Bukkit.getOfflinePlayer(UUID.fromString(user.getPlayerUUID())); + configFile = configFile(plugin, player); + config = YamlConfiguration.loadConfiguration(configFile); + } + @Contract("_, _ -> new") - public static PlayerConfig initFrom(FeelingLucky plugin, File file) + public static PlayerConfig initFromFile(FeelingLucky plugin, File file) { return new PlayerConfig(plugin, file); } + public static PlayerConfig fromDynamicConfig(FeelingLucky plugin, DynamicConfig config) + { + PlayerConfig playerConfig = new PlayerConfig(plugin, config); + playerConfig.setUsername(config.getPlayerUUID()); + playerConfig.setLuck(config.getLuckValue()); + playerConfig.setMultiplier(config.getMultiplier()); + playerConfig.setVerbose(config.isVerbose()); + return playerConfig; + } + + public DynamicConfig toDynamicConfig() + { + DynamicConfig dynamicConfig = new DynamicConfig(); + dynamicConfig.setPlayerUUID(player.getUniqueId()); + dynamicConfig.setLuckValue(getLuck()); + dynamicConfig.setVerbose(isVerbose()); + dynamicConfig.setMultiplier(getMultiplier()); + return dynamicConfig; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") @NotNull - private File configFile(FeelingLucky plugin, Player player) + private File configFile(FeelingLucky plugin, OfflinePlayer player) { if (!plugin.getDataFolder().exists()) plugin.getDataFolder().mkdirs(); @@ -72,7 +101,7 @@ public class PlayerConfig v0.set("username", player.getName()); v0.set("luck", 0); v0.set("multiplier", 1.0); - v0.set("verbose", true); + v0.set("verbose", plugin.getConfig().isVerboseGlobal()); v0.save(file); } catch (IOException ex) diff --git a/src/main/java/io/github/simplex/luck/player/PlayerHandler.java b/src/main/java/io/github/simplex/luck/player/PlayerHandler.java index 2acf2c9..f4e0e12 100644 --- a/src/main/java/io/github/simplex/luck/player/PlayerHandler.java +++ b/src/main/java/io/github/simplex/luck/player/PlayerHandler.java @@ -1,6 +1,7 @@ package io.github.simplex.luck.player; import io.github.simplex.luck.FeelingLucky; +import io.github.simplex.sql.SQLType; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -41,7 +42,7 @@ public class PlayerHandler implements Listener { String username = playerConfig.getUsername(); double luck = playerConfig.getLuck(); double multiplier = playerConfig.getMultiplier(); - boolean verbose = playerConfig.isVerbose(); + boolean verbose = plugin.getConfig().isVerboseGlobal() && playerConfig.isVerbose(); if (!player.getName().equalsIgnoreCase(username)) { playerConfig.getConfig().set("username", player.getName()); diff --git a/src/main/java/io/github/simplex/luck/util/LuckCMD.java b/src/main/java/io/github/simplex/luck/util/LuckCMD.java index 4bd97cc..bcdc2f1 100644 --- a/src/main/java/io/github/simplex/luck/util/LuckCMD.java +++ b/src/main/java/io/github/simplex/luck/util/LuckCMD.java @@ -115,6 +115,12 @@ public class LuckCMD extends Command implements TabCompleter, PluginIdentifiable } if (args[0].equalsIgnoreCase("verbose") && sender instanceof Player player) { + + if (!plugin.getConfig().isVerboseGlobal()) { + player.sendMessage(Messages.VERBOSE_DISABLED.get()); + return true; + } + final boolean a1 = Boolean.parseBoolean(args[1]); Luck luck = plugin.getHandler().getLuckContainer(player); PlayerConfig config = plugin.getConfigMap().get(player.getUniqueId()); diff --git a/src/main/java/io/github/simplex/sql/MySQL.java b/src/main/java/io/github/simplex/sql/MySQL.java new file mode 100644 index 0000000..314e45b --- /dev/null +++ b/src/main/java/io/github/simplex/sql/MySQL.java @@ -0,0 +1,94 @@ +package io.github.simplex.sql; + +import io.github.simplex.luck.Config; +import io.github.simplex.luck.FeelingLucky; +import io.github.simplex.luck.player.DynamicConfig; +import io.github.simplex.luck.player.PlayerConfig; +import io.github.simplex.luck.util.Logs; +import io.github.simplex.sql.users.MySQLUser; + +import java.sql.*; +import java.util.UUID; + +public class MySQL { + + private final Connection connection; + private final FeelingLucky plugin; + + public MySQL(FeelingLucky plugin) throws SQLException { + this.plugin = plugin; + + Config.MySQLWrapper mySQLWrapper = plugin.getConfig().getMySQL(); + String host = mySQLWrapper.getHost(); + int port = mySQLWrapper.getPort(); + String database = mySQLWrapper.getDatabase(); + String username = mySQLWrapper.getUsername(); + String password = mySQLWrapper.getPassword(); + + connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database, username, password); + if (connection != null) { + try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS PlayerConfig (playerUUID VARCHAR(36), username VARCHAR(16), luckValue DOUBLE, isVerbose BOOLEAN, multiplier DOUBLE)")) { + statement.execute(); + } + } + } + + public Connection getConnection() { + return connection; + } + + public void loadPlayers() { + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM PlayerConfig"); + ResultSet resultSet = statement.executeQuery()) { + + while (resultSet.next()) { + String playerUUID = resultSet.getString("playerUUID"); + MySQLUser mySQLUser = new MySQLUser(connection, UUID.fromString(playerUUID)); + DynamicConfig userConfig = mySQLUser.loadUserConfig(); + PlayerConfig playerConfig = PlayerConfig.fromDynamicConfig(plugin, userConfig); + plugin.getConfigMap().put(UUID.fromString(playerUUID), playerConfig); + } + } catch (SQLException e) { + Logs.error(e); + } + } + + public void savePlayer(final PlayerConfig playerConfig) { + MySQLUser mySQLUser = new MySQLUser(connection, playerConfig.getPlayer().getUniqueId()); + mySQLUser.saveUserConfig(playerConfig.toDynamicConfig()); + } + + public void loadPlayer(final UUID playerUUID) { + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM PlayerConfig WHERE playerUUID = ?")) { + statement.setString(1, playerUUID.toString()); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + MySQLUser mySQLUser = new MySQLUser(connection, playerUUID); + DynamicConfig userConfig = mySQLUser.loadUserConfig(); + PlayerConfig playerConfig = PlayerConfig.fromDynamicConfig(plugin, userConfig); + plugin.getConfigMap().put(playerUUID, playerConfig); + } + } + } catch (SQLException e) { + Logs.error(e); + } + } + + public void savePlayers() { + for (UUID playerUUID : plugin.getConfigMap().keySet()) { + PlayerConfig playerConfig = plugin.getConfigMap().get(playerUUID); + MySQLUser mySQLUser = new MySQLUser(connection, playerUUID); + mySQLUser.saveUserConfig(playerConfig.toDynamicConfig()); + } + } + + public void closeConnection() { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + Logs.error(e); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/sql/Redis.java b/src/main/java/io/github/simplex/sql/Redis.java new file mode 100644 index 0000000..64d5193 --- /dev/null +++ b/src/main/java/io/github/simplex/sql/Redis.java @@ -0,0 +1,77 @@ +package io.github.simplex.sql; + +import io.github.simplex.luck.Config; +import io.github.simplex.luck.FeelingLucky; +import io.github.simplex.luck.player.DynamicConfig; +import io.github.simplex.luck.player.PlayerConfig; +import io.github.simplex.sql.users.RedisUser; + +import java.util.Set; +import java.util.UUID; + +public class Redis { + + private final redis.clients.jedis.Jedis jedis; + private final FeelingLucky plugin; + + public Redis(final FeelingLucky plugin) { + this.plugin = plugin; + + final Config.RedisWrapper redisWrapper = plugin.getConfig().getRedis(); + final String host = redisWrapper.getHost(); + final String password = redisWrapper.getPassword(); + final String port = redisWrapper.getPort(); + final int database = redisWrapper.getDatabase(); + + jedis = new redis.clients.jedis.Jedis(host, Integer.parseInt(port)); + jedis.auth(password); + jedis.select(database); + } + + public redis.clients.jedis.Jedis getJedis() { + return jedis; + } + + public void closeConnection() { + jedis.close(); + } + + public void loadPlayers() { + Set playerUUIDs = jedis.keys("*"); + for (String playerUUID : playerUUIDs) { + RedisUser redisUser = new RedisUser(jedis, UUID.fromString(playerUUID)); + DynamicConfig userConfig = redisUser.loadUserConfig(); + + // Create a new PlayerConfig instance with the loaded data + PlayerConfig playerConfig = PlayerConfig.fromDynamicConfig(plugin, userConfig); + + // Add the PlayerConfig instance to the map + plugin.getConfigMap().put(UUID.fromString(playerUUID), playerConfig); + } + } + + public void savePlayers() { + for (UUID playerUUID : plugin.getConfigMap().keySet()) { + PlayerConfig playerConfig = plugin.getConfigMap().get(playerUUID); + RedisUser redisUser = new RedisUser(jedis, playerUUID); + redisUser.saveUserConfig(playerConfig.toDynamicConfig()); + } + } + + public void loadPlayer(UUID playerUUID) { + RedisUser redisUser = new RedisUser(jedis, playerUUID); + DynamicConfig userConfig = redisUser.loadUserConfig(); + + // Create a new PlayerConfig instance with the loaded data + PlayerConfig playerConfig = PlayerConfig.fromDynamicConfig(plugin, userConfig); + + // Add the PlayerConfig instance to the map + plugin.getConfigMap().put(playerUUID, playerConfig); + } + + public void savePlayer(UUID playerUUID) { + PlayerConfig playerConfig = plugin.getConfigMap().get(playerUUID); + RedisUser redisUser = new RedisUser(jedis, playerUUID); + redisUser.saveUserConfig(playerConfig.toDynamicConfig()); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/sql/SQLType.java b/src/main/java/io/github/simplex/sql/SQLType.java new file mode 100644 index 0000000..b362014 --- /dev/null +++ b/src/main/java/io/github/simplex/sql/SQLType.java @@ -0,0 +1,17 @@ +package io.github.simplex.sql; + +public enum SQLType { + SQLITE, + MYSQL, + REDIS, + NONE; + + public static SQLType fromString(String type) { + return switch (type.toLowerCase()) { + case "sqlite" -> SQLITE; + case "mysql" -> MYSQL; + case "redis" -> REDIS; + default -> NONE; + }; + } +} diff --git a/src/main/java/io/github/simplex/sql/SQLite.java b/src/main/java/io/github/simplex/sql/SQLite.java new file mode 100644 index 0000000..0cec9aa --- /dev/null +++ b/src/main/java/io/github/simplex/sql/SQLite.java @@ -0,0 +1,83 @@ +package io.github.simplex.sql; + +import io.github.simplex.luck.FeelingLucky; +import io.github.simplex.luck.player.DynamicConfig; +import io.github.simplex.luck.player.PlayerConfig; +import io.github.simplex.luck.util.Logs; +import io.github.simplex.sql.users.SQLiteUser; + +import java.sql.*; +import java.util.UUID; + +public class SQLite { + + private final Connection connection; + private final FeelingLucky plugin; + + public SQLite(final FeelingLucky plugin) throws SQLException { + this.plugin = plugin; + final String databaseFilePath = plugin.getConfig().getSQLite().getPath(); + + connection = DriverManager.getConnection("jdbc:sqlite:" + databaseFilePath); + if (connection != null) createTable(); + } + + public Connection getConnection() { + return connection; + } + + public void closeConnection() throws SQLException { + if (connection != null) { + connection.close(); + } + } + + public void createTable() throws SQLException { + try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS PlayerConfig (playerUUID VARCHAR(36), username VARCHAR(16), luckValue DOUBLE, isVerbose BOOLEAN, multiplier DOUBLE)")) { + statement.execute(); + } + } + + public void loadPlayers() throws SQLException { + try (PreparedStatement statement = connection.prepareStatement("SELECT playerUUID FROM PlayerConfig"); + ResultSet resultSet = statement.executeQuery()) { + + while (resultSet.next()) { + UUID playerUUID = UUID.fromString(resultSet.getString("playerUUID")); + SQLiteUser sqliteUser = new SQLiteUser(connection, playerUUID); + DynamicConfig userConfig = sqliteUser.loadUserConfig(); + + // Create a new PlayerConfig instance with the loaded data + PlayerConfig playerConfig = PlayerConfig.fromDynamicConfig(plugin, userConfig); + + // Add the PlayerConfig instance to the map + plugin.getConfigMap().put(playerUUID, playerConfig); + } + } + } + + public void savePlayers() throws SQLException { + for (UUID playerUUID : plugin.getConfigMap().keySet()) { + PlayerConfig playerConfig = plugin.getConfigMap().get(playerUUID); + SQLiteUser sqliteUser = new SQLiteUser(connection, playerUUID); + sqliteUser.saveUserConfig(playerConfig.toDynamicConfig()); + } + } + + public void loadPlayer(UUID playerUUID) throws SQLException { + SQLiteUser sqliteUser = new SQLiteUser(connection, playerUUID); + DynamicConfig userConfig = sqliteUser.loadUserConfig(); + + // Create a new PlayerConfig instance with the loaded data + PlayerConfig playerConfig = PlayerConfig.fromDynamicConfig(plugin, userConfig); + + // Add the PlayerConfig instance to the map + plugin.getConfigMap().put(playerUUID, playerConfig); + } + + public void savePlayer(UUID playerUUID) throws SQLException { + PlayerConfig playerConfig = plugin.getConfigMap().get(playerUUID); + SQLiteUser sqliteUser = new SQLiteUser(connection, playerUUID); + sqliteUser.saveUserConfig(playerConfig.toDynamicConfig()); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/sql/users/MySQLUser.java b/src/main/java/io/github/simplex/sql/users/MySQLUser.java new file mode 100644 index 0000000..767e37a --- /dev/null +++ b/src/main/java/io/github/simplex/sql/users/MySQLUser.java @@ -0,0 +1,67 @@ +package io.github.simplex.sql.users; + +import io.github.simplex.luck.player.DynamicConfig; +import io.github.simplex.luck.util.Logs; +import org.bukkit.Bukkit; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class MySQLUser { + + private final Connection connection; + private final String playerUUID; + + public MySQLUser(Connection connection, UUID playerUUID) { + this.connection = connection; + this.playerUUID = playerUUID.toString(); + } + + public DynamicConfig loadUserConfig() { + DynamicConfig config = new DynamicConfig(); + try { + PreparedStatement statement = connection.prepareStatement( + "SELECT * FROM PlayerConfig WHERE playerUUID = ?" + ); + statement.setString(1, playerUUID); + + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + config.setPlayerUUID(UUID.fromString(resultSet.getString("uuid"))); + config.setUsername(Bukkit.getOfflinePlayer(UUID.fromString(resultSet.getString("uuid"))).getName()); + config.setLuckValue(resultSet.getInt("luckValue")); + config.setVerbose(resultSet.getBoolean("isVerbose")); + config.setMultiplier(resultSet.getDouble("multiplier")); + } + } catch (SQLException e) { + Logs.error(e); + } + return config; + } + + public void saveUserConfig(DynamicConfig config) { + try { + PreparedStatement statement = connection.prepareStatement( + "INSERT INTO PlayerConfig (playerUUID, username, luckValue, isVerbose, multiplier) VALUES (?, ?, ?, ?, ?) " + + "ON DUPLICATE KEY UPDATE username = ?, luckValue = ?, isVerbose = ?, multiplier = ?" + ); + statement.setString(1, playerUUID); + statement.setString(2, config.getUsername()); + statement.setDouble(3, config.getLuckValue()); + statement.setBoolean(4, config.isVerbose()); + statement.setDouble(5, config.getMultiplier()); + statement.setString(6, config.getUsername()); + statement.setDouble(7, config.getLuckValue()); + statement.setBoolean(8, config.isVerbose()); + statement.setDouble(9, config.getMultiplier()); + + statement.executeUpdate(); + } catch (SQLException e) { + Logs.error(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/sql/users/RedisUser.java b/src/main/java/io/github/simplex/sql/users/RedisUser.java new file mode 100644 index 0000000..d05d258 --- /dev/null +++ b/src/main/java/io/github/simplex/sql/users/RedisUser.java @@ -0,0 +1,37 @@ +package io.github.simplex.sql.users; + +import io.github.simplex.luck.player.DynamicConfig; +import org.bukkit.Bukkit; +import redis.clients.jedis.Jedis; + +import java.util.UUID; + +public class RedisUser { + + private final Jedis jedis; + private final String playerUUID; + + public RedisUser(Jedis jedis, UUID playerUUID) { + this.jedis = jedis; + this.playerUUID = playerUUID.toString(); + } + + public DynamicConfig loadUserConfig() { + DynamicConfig config = new DynamicConfig(); + config.setPlayerUUID(UUID.fromString(jedis.hget(playerUUID, "uuid"))); + config.setUsername(Bukkit.getOfflinePlayer(UUID.fromString(jedis.hget(playerUUID, "username"))).getName()); + config.setLuckValue(Integer.parseInt(jedis.hget(playerUUID, "luckValue"))); + config.setVerbose(Boolean.parseBoolean(jedis.hget(playerUUID, "isVerbose"))); + config.setMultiplier(Double.parseDouble(jedis.hget(playerUUID, "multiplier"))); + + return config; + } + + public void saveUserConfig(DynamicConfig config) { + jedis.hset(playerUUID, "uuid", config.getPlayerUUID()); + jedis.hset(playerUUID, "username", config.getUsername()); + jedis.hset(playerUUID, "luckValue", String.valueOf(config.getLuckValue())); + jedis.hset(playerUUID, "isVerbose", String.valueOf(config.isVerbose())); + jedis.hset(playerUUID, "multiplier", String.valueOf(config.getMultiplier())); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/simplex/sql/users/SQLiteUser.java b/src/main/java/io/github/simplex/sql/users/SQLiteUser.java new file mode 100644 index 0000000..cfffe86 --- /dev/null +++ b/src/main/java/io/github/simplex/sql/users/SQLiteUser.java @@ -0,0 +1,65 @@ +package io.github.simplex.sql.users; + +import io.github.simplex.luck.player.DynamicConfig; +import io.github.simplex.luck.util.Logs; +import org.bukkit.Bukkit; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class SQLiteUser { + + private final Connection connection; + private final String playerUUID; + + public SQLiteUser(Connection connection, UUID playerUUID) { + this.connection = connection; + this.playerUUID = playerUUID.toString(); + } + + public DynamicConfig loadUserConfig() { + DynamicConfig config = new DynamicConfig(); + try { + PreparedStatement statement = connection.prepareStatement( + "SELECT * FROM PlayerConfig WHERE playerUUID = ?" + ); + statement.setString(1, playerUUID); + + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + config.setPlayerUUID(UUID.fromString(resultSet.getString("playerUUID"))); + config.setUsername( + Bukkit.getOfflinePlayer( + UUID.fromString( + resultSet.getString("playerUUID"))) + .getName()); + config.setLuckValue(resultSet.getDouble("luckValue")); + config.setVerbose(resultSet.getBoolean("isVerbose")); + config.setMultiplier(resultSet.getDouble("multiplier")); + } + } catch (SQLException e) { + Logs.error(e); + } + return config; + } + + public void saveUserConfig(DynamicConfig config) { + try { + PreparedStatement statement = connection.prepareStatement( + "INSERT INTO PlayerConfig (playerUUID, username, luckValue, isVerbose, multiplier) VALUES (?, ?, ?, ?, ?)" + ); + statement.setString(1, playerUUID); + statement.setString(2, config.getUsername()); + statement.setDouble(3, config.getLuckValue()); + statement.setBoolean(4, config.isVerbose()); + statement.setDouble(5, config.getMultiplier()); + statement.executeUpdate(); + } catch (SQLException e) { + Logs.error(e); + } + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 69c7524..2223904 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,6 +8,11 @@ high_rarity_chance: 512.0 medium_rarity_chance: 128.0 low_rarity_chance: 64.0 +# Change whether verbosity is enabled globally or not. +# If the verbosity is set to true, then all players will have the option to turn it off for themselves only. +# If the verbosity is set to false, then players will not have the option to turn it on. +global_verbosity: true + # The following entries are for the rarity level of each event trigger. # This will determine which rarity chance to use which ensures players # The following values are accepted: NONE, LOW, MED, HIGH @@ -27,4 +32,29 @@ ore_vein: HIGH random_effect: HIGH restore_hunger: NONE take_damage: MED -unbreakable: HIGH \ No newline at end of file +unbreakable: HIGH + +# This section is for Database storage. +# If you wish to use a database, you must fill out the following information. + +#database_types: MYSQL, SQLITE, REDIS, NONE +database_type: NONE + +# MySQL Database +mysql: + host: localhost + port: 3306 + database: minecraft + username: root + password: password + +# SQLite Database +sqlite: + path: database.db + +# Redis Database +redis: + host: localhost + port: 6379 + password: password + database: 0