1.4.0 Update

Feature Update:
- SQL Support (MySQL, REDIS, SQLite)
- Global Verbosity Control
- Reimplemented Experimental OreVein
This commit is contained in:
Paldiu 2024-04-15 21:17:10 -05:00
parent cd2c90dc7a
commit 0cccf50a85
19 changed files with 884 additions and 81 deletions

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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<String, Object> 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;
}
}
}

View File

@ -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<UUID, PlayerConfig> 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<UUID, PlayerConfig> getConfigMap()
{
private MySQL mysql;
private SQLite sqlite;
private Redis Redis;
private boolean shouldLoadPhysical = false;
public Map<UUID, PlayerConfig> 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;
}
}

View File

@ -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<Block> getOresInArea(@NotNull Block block) {
Stream.Builder<Block> streamBuilder = Stream.builder();
Location start = block.getLocation();
World world = block.getWorld();
List<Tag<Material>> 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<Block> getOresInArea(@NotNull Block block, Material minedBlockType) {
Set<Block> blocks = new HashSet<>();
Queue<Block> queue = new LinkedList<>();
Set<Location> 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;
}
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)

View File

@ -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());

View File

@ -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());

View File

@ -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);
}
}
}
}

View File

@ -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<String> 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());
}
}

View File

@ -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;
};
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -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()));
}
}

View File

@ -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);
}
}
}

View File

@ -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
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