diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/artifacts/ReviveTechnicalTest_jar.xml b/.idea/artifacts/ReviveTechnicalTest_jar.xml new file mode 100644 index 0000000..ceba5c4 --- /dev/null +++ b/.idea/artifacts/ReviveTechnicalTest_jar.xml @@ -0,0 +1,12 @@ + + + $PROJECT_DIR$/.. + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..67e1e61 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..6e6f43f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3477929..5ae0492 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,11 @@ 1.18.36 provided + + org.xerial + sqlite-jdbc + 3.42.0.0 + - + \ No newline at end of file diff --git a/src/main/java/fr/revivemc/Main.java b/src/main/java/fr/revivemc/Main.java index 521e16b..b6aec15 100644 --- a/src/main/java/fr/revivemc/Main.java +++ b/src/main/java/fr/revivemc/Main.java @@ -1,13 +1,76 @@ package fr.revivemc; +import fr.revivemc.data.Cache; +import fr.revivemc.events.EntityDamageListener; +import fr.revivemc.events.EntityDeathListener; +import fr.revivemc.events.EntityRegenListener; +import fr.revivemc.events.PlayerJoinListener; +import fr.revivemc.data.Sql; +import fr.revivemc.yaml.ConfigYaml; +import fr.revivemc.yaml.LangYaml; +import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; +import java.io.File; +import java.util.HashMap; +import java.util.UUID; + public class Main extends JavaPlugin { + /** + * Configuration variable, lang or data + */ + public static ConfigYaml config_yaml; + public static LangYaml lang_yaml; + public static Sql sql; + + // Variable for the cache + public static HashMap cache; + + /** + * Create the plugin folder if it hasn't been created + */ + private void loadDataFolder() { + File data_folder = Main.getPlugin(Main.class).getDataFolder(); + + if (!data_folder.exists()) + data_folder.mkdir(); + } + + /** + * Server Startup + */ @Override - public void onEnable() {} + public void onEnable() { + loadDataFolder(); + + sql = new Sql(); + sql.init(); + config_yaml = new ConfigYaml(); + config_yaml.init(); + + lang_yaml = new LangYaml(); + lang_yaml.init(); + + cache = new HashMap<>(); + + Bukkit.getPluginManager().registerEvents(new PlayerJoinListener(), this); + Bukkit.getPluginManager().registerEvents(new EntityDeathListener(), this); + Bukkit.getPluginManager().registerEvents(new EntityDamageListener(), this); + Bukkit.getPluginManager().registerEvents(new EntityRegenListener(), this); + System.out.println("Plugin enabled"); + } + + /** + * Server Stop + */ @Override - public void onDisable() {} + public void onDisable() { + sql.saveData(); + sql.close(); + + System.out.println("Plugin disabled"); + } } diff --git a/src/main/java/fr/revivemc/data/Cache.java b/src/main/java/fr/revivemc/data/Cache.java new file mode 100644 index 0000000..ca6b8bc --- /dev/null +++ b/src/main/java/fr/revivemc/data/Cache.java @@ -0,0 +1,43 @@ +package fr.revivemc.data; + +public class Cache { + + // Kills and Deaths variables + private int kills; + private int deaths; + + /** + * Constructor for cache + * @param kills Number of kills + * @param deaths Number of deaths + */ + public Cache(int kills, int deaths) { + this.kills = kills; + this.deaths = deaths; + } + + /** + * @return Returns the number of kills + */ + public int getKills() { + return (kills); + } + + /** + * @return Returns the number of deaths + */ + public int getDeaths() { + return (deaths); + } + + // Add 1 to kill count + public void addKill() { + kills++; + } + + // Add 1 to death count + public void addDeath() { + deaths++; + } + +} diff --git a/src/main/java/fr/revivemc/data/Sql.java b/src/main/java/fr/revivemc/data/Sql.java new file mode 100644 index 0000000..9d3f48a --- /dev/null +++ b/src/main/java/fr/revivemc/data/Sql.java @@ -0,0 +1,79 @@ +package fr.revivemc.data; + +import fr.revivemc.Main; +import fr.revivemc.data.wrapper.Players; +import org.bukkit.entity.Player; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Map; +import java.util.UUID; + +public class Sql { + + // Information of connection + private Connection connection; + + /** + * This function allows you to create the different tables + * @param stmt A parameter to run SQL commands + * @throws SQLException Returns an exception if a sql error occurred + */ + private void createTable(Statement stmt) throws SQLException { + stmt.execute("CREATE TABLE IF NOT EXISTS players (uuid TEXT PRIMARY KEY, kill INTEGER, death INTEGER)"); + } + + /** + * Allows you to close the db + */ + public void close() { + try { + if (connection != null && !connection.isClosed()) + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** + * Allows you to initialize the db when the server is launched + */ + public void init() { + try { + Class.forName("org.sqlite.JDBC"); + + File data_folder = Main.getPlugin(Main.class).getDataFolder(); + + connection = DriverManager.getConnection("jdbc:sqlite:" + data_folder + "/data.db"); + Statement statement = connection.createStatement(); + createTable(statement); + statement.close(); + System.out.println("Database connection established"); + } catch (SQLException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + + + /** + * Save data in the db + */ + public void saveData() { + for (Map.Entry cache : Main.cache.entrySet()) { + Players.addPlayer(cache.getKey()); + Players.setKillByUuid(cache.getKey(), cache.getValue().getKills()); + Players.setDeathByUuid(cache.getKey(), cache.getValue().getDeaths()); + } + } + + /** + * @return Returns the connection + */ + public Connection getConnection() { + return (connection); + } + +} diff --git a/src/main/java/fr/revivemc/data/wrapper/Players.java b/src/main/java/fr/revivemc/data/wrapper/Players.java new file mode 100644 index 0000000..c5aeba8 --- /dev/null +++ b/src/main/java/fr/revivemc/data/wrapper/Players.java @@ -0,0 +1,128 @@ +package fr.revivemc.data.wrapper; + +import fr.revivemc.Main; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class Players { + + /** + * This function allows the player to be initialized in the table + * @param uuid Player uuid + */ + public static void addPlayer(UUID uuid) { + try { + Connection connection = Main.sql.getConnection(); + + String query = "INSERT INTO players (uuid, kill, death) VALUES (?, 0, 0)"; + PreparedStatement ps = connection.prepareStatement(query); + ps.setString(1, uuid.toString()); + + ps.executeUpdate(); + + } catch (SQLException e) { + System.err.println("Error while executing SQL statement " + e.getMessage()); + } + } + + /** + * This function allows you to add n to the player's kills + * @param uuid Player uuid + * @param n Number to add + */ + public static void setKillByUuid(UUID uuid, int n) { + try { + Connection connection = Main.sql.getConnection(); + + String query = "UPDATE players SET kill = ? WHERE uuid = ?"; + PreparedStatement ps = connection.prepareStatement(query); + ps.setString(1, String.valueOf(n)); + ps.setString(2, uuid.toString()); + + ps.executeUpdate(); + + } catch (SQLException e) { + System.err.println("Error while executing SQL statement " + e.getMessage()); + } + } + + /** + * This function allows you to add n to the player's deaths + * @param uuid Player uuid + * @param n Number to add + */ + public static void setDeathByUuid(UUID uuid, int n) { + try { + Connection connection = Main.sql.getConnection(); + + String query = "UPDATE players SET death = ? WHERE uuid = ?"; + PreparedStatement ps = connection.prepareStatement(query); + ps.setString(1, String.valueOf(n)); + ps.setString(2, uuid.toString()); + + ps.executeUpdate(); + + } catch (SQLException e) { + System.err.println("Error while executing SQL statement " + e.getMessage()); + } + } + + /** + * Function that allows you to retrieve the number of kills in relation to the player's UUID + * @param uuid Player uuid + * @return Returns the correct value or 0 + */ + public static int getKillByUuid(UUID uuid) { + int kills = 0; + + try { + Connection connection = Main.sql.getConnection(); + + String query = "SELECT kill FROM players WHERE uuid=?"; + PreparedStatement ps = connection.prepareStatement(query); + ps.setString(1, uuid.toString()); + + ResultSet row = ps.executeQuery(); + + if (row.next()) + kills = row.getInt("kill"); + + } catch (SQLException e) { + System.err.println("Error while executing SQL statement " + e.getMessage()); + } + + return (kills); + } + + /** + * Function that allows you to retrieve the number of deaths in relation to the player's UUID + * @param uuid Player uuid + * @return Returns the correct value or 0 + */ + public static int getDeathByUuid(UUID uuid) { + int deaths = 0; + + try { + Connection connection = Main.sql.getConnection(); + + String query = "SELECT death FROM players WHERE uuid=?"; + PreparedStatement ps = connection.prepareStatement(query); + ps.setString(1, uuid.toString()); + + ResultSet row = ps.executeQuery(); + + if (row.next()) + deaths = row.getInt("death"); + + } catch (SQLException e) { + System.err.println("Error while executing SQL statement " + e.getMessage()); + } + + return (deaths); + } + +} diff --git a/src/main/java/fr/revivemc/events/EntityDamageListener.java b/src/main/java/fr/revivemc/events/EntityDamageListener.java new file mode 100644 index 0000000..b147788 --- /dev/null +++ b/src/main/java/fr/revivemc/events/EntityDamageListener.java @@ -0,0 +1,22 @@ +package fr.revivemc.events; + +import fr.revivemc.scoreboard.ScoreBoard; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; + +public class EntityDamageListener implements Listener { + + /** + * Function that is triggered when a player takes damage + * @param event All information related to the event + */ + @EventHandler + public void onPlayerDamage(EntityDamageEvent event) { + if (event.getEntity() instanceof Player) { + ScoreBoard.init((Player) event.getEntity(), ((Player) event.getEntity()).getHealth() - event.getDamage()); + } + } + +} diff --git a/src/main/java/fr/revivemc/events/EntityDeathListener.java b/src/main/java/fr/revivemc/events/EntityDeathListener.java new file mode 100644 index 0000000..df7270d --- /dev/null +++ b/src/main/java/fr/revivemc/events/EntityDeathListener.java @@ -0,0 +1,36 @@ +package fr.revivemc.events; + +import fr.revivemc.Main; +import fr.revivemc.data.Cache; +import fr.revivemc.scoreboard.ScoreBoard; +import fr.revivemc.data.wrapper.Players; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDeathEvent; + +public class EntityDeathListener implements Listener { + + /** + * Function that is triggered when an entity dies + * @param event All information related to the event + */ + @EventHandler + public void onEntityDeath(EntityDeathEvent event) { + Player killer = event.getEntity().getKiller(); + Entity victim = event.getEntity(); + + if (killer != null && victim instanceof Player) { + Cache cache = Main.cache.get(killer.getUniqueId()); + cache.addKill(); + ScoreBoard.init(killer, killer.getHealth()); + } + if (victim instanceof Player) { + Cache cache = Main.cache.get(victim.getUniqueId()); + cache.addDeath(); + ScoreBoard.init((Player) victim, ((Player) victim).getHealth()); + } + } + +} diff --git a/src/main/java/fr/revivemc/events/EntityRegenListener.java b/src/main/java/fr/revivemc/events/EntityRegenListener.java new file mode 100644 index 0000000..f3feee2 --- /dev/null +++ b/src/main/java/fr/revivemc/events/EntityRegenListener.java @@ -0,0 +1,22 @@ +package fr.revivemc.events; + +import fr.revivemc.scoreboard.ScoreBoard; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityRegainHealthEvent; + +public class EntityRegenListener implements Listener { + + /** + * Function that is triggered when a player gets a regeneration + * @param event All information related to the event + */ + @EventHandler + public void onPlayerRegen(EntityRegainHealthEvent event) { + if (event.getEntity() instanceof Player) { + ScoreBoard.init((Player) event.getEntity(), ((Player) event.getEntity()).getHealth() + event.getAmount()); + } + } + +} diff --git a/src/main/java/fr/revivemc/events/PlayerJoinListener.java b/src/main/java/fr/revivemc/events/PlayerJoinListener.java new file mode 100644 index 0000000..76a4ab0 --- /dev/null +++ b/src/main/java/fr/revivemc/events/PlayerJoinListener.java @@ -0,0 +1,31 @@ +package fr.revivemc.events; + +import fr.revivemc.Main; +import fr.revivemc.data.Cache; +import fr.revivemc.data.wrapper.Players; +import fr.revivemc.scoreboard.ScoreBoard; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerJoinListener implements Listener { + + /** + * Function that is triggered when a player joins + * @param event All information related to the event + */ + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + Cache cache = Main.cache.get(player.getUniqueId()); + if (cache == null) { + java.util.UUID uuid = player.getUniqueId(); + Main.cache.put(player.getUniqueId(), new Cache(Players.getKillByUuid(uuid), Players.getDeathByUuid(uuid))); + } + + ScoreBoard.init(player, player.getHealth()); + } + +} diff --git a/src/main/java/fr/revivemc/scoreboard/ScoreBoard.java b/src/main/java/fr/revivemc/scoreboard/ScoreBoard.java new file mode 100644 index 0000000..c041a92 --- /dev/null +++ b/src/main/java/fr/revivemc/scoreboard/ScoreBoard.java @@ -0,0 +1,40 @@ +package fr.revivemc.scoreboard; + +import fr.revivemc.Main; +import fr.revivemc.data.Cache; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.*; + +public class ScoreBoard { + + /** + * Function for creating the scoreboard + * @param player The player + * @param life The life of player + */ + public static void init(Player player, double life) { + Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + + Cache cache = Main.cache.get(player.getUniqueId()); + + Objective objective = scoreboard.registerNewObjective("revivemc", "dummy"); + objective.setDisplayName(Main.lang_yaml.title_scoreboard); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + + Score line_1 = objective.getScore(Main.lang_yaml.name_scoreboard + player.getDisplayName()); + line_1.setScore(0); + + Score line_2 = objective.getScore(Main.lang_yaml.kills_scoreboard + cache.getKills()); + line_2.setScore(1); + + Score line_3 = objective.getScore(Main.lang_yaml.heart_scoreboard + life); + line_3.setScore(2); + + Score line_4 = objective.getScore(Main.lang_yaml.deaths_scoreboard + cache.getDeaths()); + line_4.setScore(3); + + player.setScoreboard(scoreboard); + } + +} diff --git a/src/main/java/fr/revivemc/yaml/ConfigYaml.java b/src/main/java/fr/revivemc/yaml/ConfigYaml.java new file mode 100644 index 0000000..8182887 --- /dev/null +++ b/src/main/java/fr/revivemc/yaml/ConfigYaml.java @@ -0,0 +1,48 @@ +package fr.revivemc.yaml; + +import fr.revivemc.Main; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; + +public class ConfigYaml { + + /** + * Variable for config and subfolder + */ + private YamlConfiguration config; + public String lang_file_name; + + /** + * Create the file and fill it with the basic information if it does not exist + */ + private void loadYaml() { + File data_folder = Main.getPlugin(Main.class).getDataFolder(); + + File config_file = new File(data_folder, "config.yml"); + config = YamlConfiguration.loadConfiguration(config_file); + + if (!config_file.exists()) { + try { + config_file.createNewFile(); + config.set("lang", "en_us.yml"); + config.save(config_file); + + System.out.println("config.yml has been created"); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + } + + /** + * Initialize the yaml part + */ + public void init() { + loadYaml(); + + lang_file_name = config.getString("lang"); + } + +} diff --git a/src/main/java/fr/revivemc/yaml/LangYaml.java b/src/main/java/fr/revivemc/yaml/LangYaml.java new file mode 100644 index 0000000..11e5ae6 --- /dev/null +++ b/src/main/java/fr/revivemc/yaml/LangYaml.java @@ -0,0 +1,77 @@ +package fr.revivemc.yaml; + +import fr.revivemc.Main; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; + +public class LangYaml { + + /** + * Variable for config and values for lang + */ + private YamlConfiguration config; + public String title_scoreboard; + public String kills_scoreboard; + public String deaths_scoreboard; + public String heart_scoreboard; + public String name_scoreboard; + + /** + * Function that allows you to create the folder if it does not have the default values + * @param config_file File to create + * @param lang_folder Folder of lang + */ + private void createFile(File config_file, File lang_folder) { + try { + config_file = new File(lang_folder, "en_us.yml"); + + config_file.createNewFile(); + config.set("title_scoreboard", "ReviveMC"); + config.set("kills_scoreboard", "Kills: "); + config.set("deaths_scoreboard", "Deaths: "); + config.set("heart_scoreboard", "Hearts: "); + config.set("name_scoreboard", "Name: "); + config.save(config_file); + + System.out.println("en_us.yml has been created"); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + + /** + * File and fill it with the basic information if it does not exist + */ + private void loadYaml() { + File data_folder = Main.getPlugin(Main.class).getDataFolder(); + File lang_folder = new File(data_folder, "lang"); + + if (!lang_folder.exists()) + lang_folder.mkdir(); + + File config_file = new File(lang_folder, Main.config_yaml.lang_file_name); + config = YamlConfiguration.loadConfiguration(config_file); + + if (!config_file.exists()) + createFile(config_file, lang_folder); + + title_scoreboard = config.getString("title_scoreboard"); + kills_scoreboard = config.getString("kills_scoreboard"); + deaths_scoreboard = config.getString("deaths_scoreboard"); + name_scoreboard = config.getString("name_scoreboard"); + heart_scoreboard = config.getString("heart_scoreboard"); + if (title_scoreboard == null || kills_scoreboard == null || deaths_scoreboard == null + || name_scoreboard == null || heart_scoreboard == null) + createFile(config_file, lang_folder); + } + + /** + * Initialize the yaml part + */ + public void init() { + loadYaml(); + } + +}