diff --git a/ic_plugin_coordinates/.mvn/jvm.config b/ic_plugin_coordinates/.mvn/jvm.config new file mode 100644 index 0000000..e69de29 diff --git a/ic_plugin_coordinates/.mvn/maven.config b/ic_plugin_coordinates/.mvn/maven.config new file mode 100644 index 0000000..e69de29 diff --git a/ic_plugin_coordinates/pom.xml b/ic_plugin_coordinates/pom.xml new file mode 100644 index 0000000..50b70a0 --- /dev/null +++ b/ic_plugin_coordinates/pom.xml @@ -0,0 +1,127 @@ + + + 4.0.0 + + nl.interestingcorner.coordinates + ic_plugin_coordinates + 1.0-SNAPSHOT + + ic_plugin_coordinates + + https://interesting-corner.nl + + + UTF-8 + 17 + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.junit + junit-bom + 5.11.0 + pom + import + + + + + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.junit.jupiter + junit-jupiter-params + test + + + com.google.errorprone + error_prone_annotations + 2.28.0 + provided + + + org.spigotmc + spigot-api + 1.21.8-R0.1-SNAPSHOT + provided + + + org.xerial + sqlite-jdbc + 3.50.3.0 + + + + + ${project.basedir}/src/main/java + + + ${project.basedir}/src/main/resources + + plugin.yml + + + + + + + + maven-clean-plugin + 3.4.0 + + + + maven-resources-plugin + 3.3.1 + + + maven-compiler-plugin + 3.13.0 + + + maven-surefire-plugin + 3.3.0 + + + maven-jar-plugin + 3.4.2 + + + ${db.username} + ${db.password} + + + + + maven-install-plugin + 3.1.2 + + + maven-deploy-plugin + 3.1.2 + + + + maven-site-plugin + 3.12.1 + + + maven-project-info-reports-plugin + 3.6.1 + + + + + diff --git a/ic_plugin_coordinates/settings.xml b/ic_plugin_coordinates/settings.xml new file mode 100644 index 0000000..1e175f7 --- /dev/null +++ b/ic_plugin_coordinates/settings.xml @@ -0,0 +1,14 @@ + + + + default + + spigot + Z7nhqy+spigot-minecraft + ic_minecraft + localhost + + + + \ No newline at end of file diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/App.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/App.java new file mode 100644 index 0000000..eb159e3 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/App.java @@ -0,0 +1,50 @@ +package nl.interestingcorner.coordinates; + +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.java.JavaPlugin; + +import nl.interestingcorner.coordinates.commands.CoordinatesCommand; +import nl.interestingcorner.coordinates.db.DatabaseManager; +import nl.interestingcorner.coordinates.gui.CoordinatesGUIListener; + +public class App extends JavaPlugin { + + @Override + public void onEnable() { + getLogger().info("Eyooo we boutta get lit!"); + + if (!DatabaseManager.INSTANCE.initialize(this)) { + getLogger().severe("Could not initialize database. Exiting!"); + setEnabled(false); + return; + } + getLogger().info("Successfully initialized database"); + + getServer().getPluginManager().registerEvents(new CoordinatesGUIListener(), this); + registerCommands(); + + } + + @Override + public void onDisable() { + getLogger().info("Eyooo we outta here!"); + + if (!DatabaseManager.INSTANCE.close()) { + getLogger().severe("Error while trying to close db connection"); + } + } + + private void registerCommands() { + registerSimgleCommand("ic-coords", new CoordinatesCommand()); + } + + private void registerSimgleCommand(String name, CommandExecutor executor) + { + PluginCommand pc = this.getCommand(name); + if (pc != null) + { + pc.setExecutor(executor); + } + } +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/AddCoordinateCommandHandler.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/AddCoordinateCommandHandler.java new file mode 100644 index 0000000..7590177 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/AddCoordinateCommandHandler.java @@ -0,0 +1,160 @@ +package nl.interestingcorner.coordinates.commands; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ComponentStyle; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.TranslatableComponent; +import nl.interestingcorner.coordinates.db.Coordinate; +import nl.interestingcorner.coordinates.db.DatabaseManager; +import nl.interestingcorner.coordinates.db.MinecraftColor; + +public class AddCoordinateCommandHandler implements CoordinatesCommandHandler { + + /** + * Minimum arguments needed for adding a command: name, description, color + */ + private final int MIN_ARGS = 4; + + private CommandSender sender; + + @Override + public boolean handleCommand(CommandSender sender, String[] args) { + if (args.length < MIN_ARGS) { + return false; + } + + this.sender = sender; + + List argsWithoutFirstCommand = removeFirstArg(args); + if (argsWithoutFirstCommand.isEmpty()) { + return false; + } + + List parsedArgs = parseArgs(argsWithoutFirstCommand.toArray(String[]::new)); + if (parsedArgs.isEmpty()) { + return false; + } + + sender.sendMessage("Args after parsing:"); + sender.sendMessage("0:" + parsedArgs.get(0)); + sender.sendMessage("1:" + parsedArgs.get(1)); + sender.sendMessage("2:" + parsedArgs.get(2)); + + String name = parsedArgs.get(0); + String description = parsedArgs.get(1); + String color = parsedArgs.get(2); + + if (!MinecraftColor.isValidColor(color)) { + sendInvalidColorMessage(color); + return false; + } + + if (sender instanceof Player player) { + Location playerLocation = player.getLocation(); + if (playerLocation == null) { + return false; + } + + World playerWorld = playerLocation.getWorld(); + if (playerWorld == null) { + return false; + } + + //TODO check if item doesnt already exist, coordinate with same values, create isEquals method for coordinate + return DatabaseManager.INSTANCE + .addCoordinate(name, // name + description, // description + new Coordinate.Position(playerLocation.getBlockX(), playerLocation.getBlockY(), + playerLocation.getBlockZ()), // position + playerWorld.getEnvironment().equals(World.Environment.NETHER), // nether + playerWorld.getName(), // world + MinecraftColor.fromString(color) // color + ); + } + + return true; + } + + private List removeFirstArg(String[] args) { + List onlyArgs = new ArrayList<>(); + + sender.sendMessage("removeFirstArg: size of args is " + String.valueOf(args.length)); + for (int i = 1; i < args.length; i++) { + onlyArgs.add(args[i]); + } + + sender.sendMessage("removeFirstArg: size of onlyArgs is " + String.valueOf(onlyArgs.size())); + return onlyArgs; + } + + private List parseArgs(String[] args) { + List res = new ArrayList<>(); + StringBuilder currentArg = new StringBuilder(); + boolean inQuotes = false; + + for (String arg : args) { + if (inQuotes) { + if (arg.endsWith("\"")) { + // end of quoted entry + // add final arg to result + String replaced = arg.replace("\"", ""); + currentArg.append(" ").append(replaced); + res.add(currentArg.toString()); + + // clear current arg + currentArg.setLength(0); + inQuotes = false; + } else { + currentArg.append(" ").append(arg); + } + } else { + if (arg.startsWith("\"")) { + String replaced = arg.replace("\"", ""); + + if (arg.endsWith("\"")) { + // if the current arg starts and ends with a ", just add the arg to the result + res.add(replaced); + } else { + // if the current arg doesn't end with a ", it is quoted and we need to handle + // the remainder + inQuotes = true; + currentArg.append(replaced); + } + } else { + res.add(arg); + } + } + } + + return res; + } + + private void sendInvalidColorMessage(String color) + { + TextComponent finalMessage = new TextComponent(); + TextComponent colorMessage = new TextComponent("Color "); + colorMessage.setColor(ChatColor.RED); + finalMessage.addExtra(colorMessage); + + TextComponent enteredColor = new TextComponent(color); + enteredColor.setColor(ChatColor.AQUA); + finalMessage.addExtra(enteredColor); + + TextComponent endOfMessage = new TextComponent(" is not a valid color! Please use a regular minecraft color"); + endOfMessage.setColor(ChatColor.RED); + finalMessage.addExtra(endOfMessage); + sender.spigot().sendMessage(finalMessage); + } + +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/CoordinatesCommand.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/CoordinatesCommand.java new file mode 100644 index 0000000..dd17308 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/CoordinatesCommand.java @@ -0,0 +1,30 @@ +package nl.interestingcorner.coordinates.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CoordinatesCommand implements CommandExecutor{ + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + StringBuilder sb = new StringBuilder("Got command " + command.getName() + " label " + label + " and args "); + for (String string : args) { + sb.append(" "); + sb.append(string); + sb.append(" "); + } + + sender.sendMessage("Args length: " + String.valueOf(args.length)); + sender.sendMessage(sb.toString()); + + // strategy design pattern + return switch (args[0]) { + case "get" -> new GetCoordinatesCommandHandler().handleCommand(sender, args); + case "add" -> new AddCoordinateCommandHandler().handleCommand(sender, args); + default -> false; + }; + } + + +} \ No newline at end of file diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/CoordinatesCommandHandler.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/CoordinatesCommandHandler.java new file mode 100644 index 0000000..8e21f1d --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/CoordinatesCommandHandler.java @@ -0,0 +1,7 @@ +package nl.interestingcorner.coordinates.commands; + +import org.bukkit.command.CommandSender; + +public interface CoordinatesCommandHandler { + boolean handleCommand(CommandSender sender, String[] args); +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/GetCoordinatesCommandHandler.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/GetCoordinatesCommandHandler.java new file mode 100644 index 0000000..607cab2 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/commands/GetCoordinatesCommandHandler.java @@ -0,0 +1,46 @@ +package nl.interestingcorner.coordinates.commands; + +import java.util.List; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import nl.interestingcorner.coordinates.db.Coordinate; +import nl.interestingcorner.coordinates.db.DatabaseManager; +import nl.interestingcorner.coordinates.gui.CoordinatesGUI; + +public class GetCoordinatesCommandHandler implements CoordinatesCommandHandler { + + @Override + public boolean handleCommand(CommandSender sender, String[] args) { + if (sender instanceof Player player) { + List coords; + if (args.length < 2) { + coords = DatabaseManager.INSTANCE.getAllCoordinates(); + } else if (args[1].equalsIgnoreCase("world")) { + String world = player.getWorld().getName(); + coords = DatabaseManager.INSTANCE.getAllCoordinates(world); + } else { + sender.sendMessage("Invalid argument: " + args[1]); + return false; + } + + if (coords.isEmpty()) { + player.sendMessage("No coordinates found! Add some with the §3/ic-coords §5add §fcommand."); + return true; + } + + StringBuilder res = new StringBuilder("Coordinates: "); + + for (Coordinate coordinate : coords) { + res.append(coordinate.toString()); + } + + player.sendMessage(res.toString()); + + CoordinatesGUI.open(player, coords); + } + return true; + } + +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/Coordinate.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/Coordinate.java new file mode 100644 index 0000000..fb72c83 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/Coordinate.java @@ -0,0 +1,109 @@ +package nl.interestingcorner.coordinates.db; + +/** + * +-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+-----+---------+----------------+ + * | Field | Type | Null | Key | Default | Extra | + * +-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+-----+---------+----------------+ + * | id | int | NO | PRI | NULL | auto_increment | + * | name | varchar(255) | NO | | NULL | | + * | x | int | NO | | NULL | | + * | y | int | NO | | NULL | | + * | z | int | NO | | NULL | | + * | description | varchar(255) | NO | | NULL | | + * | color | + * enum('dark_red','red','black','blue','aqua','dark_aqua','green','gold','dark_purple','light_purple','yellow','dark_green','gray','dark_gray','white','dark_blue') + * | YES | | white | | + * | nether | tinyint(1) | YES | | 0 | | + * +-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+-----+---------+----------------+ + */ + + +/** + * Class to represent a coordinate to teleport to + */ +public class Coordinate { + /** + * auto-generated ID + */ + public int id; + + /** + * name of the coordinate + */ + public String name; + + /** + * description of the coordinate + */ + public String description; + + /** + * position in x,y,z + */ + public Position position; + + /** + * If the coordinate is in the nether + */ + public boolean nether; + + /** + * The color to display the coordinate name in + */ + public MinecraftColor color; + + /** + * the world for this coordinate. This corresponds to the name of the world in + * Multiverse + */ + public String world; + + public Coordinate(int id, String name, String description, Position position, boolean nether, String world) { + this.id = id; + this.name = name; + this.description = description; + this.position = position; + this.nether = nether; + this.world = world; + this.color = MinecraftColor.WHITE; + } + + public Coordinate(int id, String name, String description, Position position, boolean nether, String world, + MinecraftColor color) { + this(id, name, description, position, nether, world); + this.color = color; + } + + public record Position(int x, int y, int z) { + } + + public static String createTableStatement = """ + CREATE TABLE IF NOT EXISTS coordinates ( + id INTEGER PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description VARCHAR(255), + x INT NOT NULL, + y INT NOT NULL, + z INT NOT NULL, + nether BOOLEAN NOT NULL DEFAULT FALSE, + color VARCHAR(255), + world VARCHAR(255) DEFAULT "white" + ); + """; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("{ "); + sb.append("id: ").append(id) + .append(", name: '").append(name).append('\'') + .append(", description: '").append(description).append('\'') + .append(", position: { x: ").append(position.x()) + .append(", y: ").append(position.y()) + .append(", z: ").append(position.z()).append(" }") + .append(", nether: ").append(nether) + .append(", color: ").append(color != null ? color.toString() : "null") + .append(", world: '").append(world).append('\'') + .append(" }"); + return sb.toString(); + } +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/DatabaseManager.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/DatabaseManager.java new file mode 100644 index 0000000..d4784ce --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/DatabaseManager.java @@ -0,0 +1,216 @@ +package nl.interestingcorner.coordinates.db; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.bukkit.plugin.java.JavaPlugin; + +public enum DatabaseManager { + + INSTANCE; + + private Connection connection; + private JavaPlugin app; + + /** + * Initializes the database. Creates the file and sets up the db structure. + * + * @param app the app to use for logging + * @return true if the database was initialized successfully. False if not. + */ + public boolean initialize(JavaPlugin app) { + this.app = app; + + if (!setupDatabase()) { + return false; + } + + if (!initializeTables()) { + return false; + } + + return true; + } + + /** + * Closes the connectino to the database + * + * @return true if the connection closed succesfully, false if not. + */ + public boolean close() { + try { + if (this.connection != null && !this.connection.isClosed()) { + this.connection.close(); + } + } catch (SQLException ex) { + this.app.getLogger().log(Level.SEVERE, "Error while closing the databse connection: {0}", ex.getMessage()); + return false; + } + + return true; + } + + /** + * Gets all coordinates from the database + * + * @return a list with all coordinates from the database. Empty if an error + * occurred. + */ + public List getAllCoordinates() { + List result = new ArrayList<>(); + try { + PreparedStatement getAllCoordinatesStatement = this.connection + .prepareStatement("SELECT * FROM coordinates"); + + result = convertResultsToCoordinates(getAllCoordinatesStatement.executeQuery()); + + } catch (SQLException e) { + this.app.getLogger().log(Level.SEVERE, "Could not get coordinates! {0}", e.getMessage()); + } + return result; + } + + public List getAllCoordinates(String world) { + List result = new ArrayList<>(); + try { + PreparedStatement getAllCoordinatesStatement = this.connection + .prepareStatement("SELECT * FROM coordinates WHERE world = ?"); + getAllCoordinatesStatement.setString(1, world); + + result = convertResultsToCoordinates(getAllCoordinatesStatement.executeQuery()); + + } catch (SQLException e) { + this.app.getLogger().log(Level.SEVERE, "Could not get coordinates for world {0}! {1}", + new Object[] { world, e.getMessage() }); + } + return result; + } + + public List convertResultsToCoordinates(ResultSet results) throws SQLException { + List coordinates = new ArrayList<>(); + while (results.next()) { + + MinecraftColor color = MinecraftColor.fromString(results.getString("color")); + if (color == null) { + color = MinecraftColor.WHITE; + } + + Coordinate c = new Coordinate( + results.getInt("id"), + results.getString("name"), + results.getString("description"), + new Coordinate.Position( + results.getInt("x"), + results.getInt("y"), + results.getInt("z")), + results.getBoolean("nether"), + results.getString("world"), + color); + + coordinates.add(c); + } + + return coordinates; + } + + /** + * Adds a new coordinate to the database with the given parameters. + * + * @param name the name of the coordinate + * @param description a short description of the coordinate + * @param position the position of the coordinate where the player will + * spwan when they teleport to the coordinate + * @param nether if the coordinate is in the nether + * @param world the Multiverse world the coordinate belongs to + * @param color the color to display for the coordinate name + * @return true if the command was added successfully, false otherwise + */ + public boolean addCoordinate(String name, String description, Coordinate.Position position, boolean nether, + String world, MinecraftColor color) { + String sql = "INSERT INTO coordinates (name, description, x, y, z, nether, color, world) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + try { + PreparedStatement addCoordinateStatement = this.connection.prepareStatement(sql); + addCoordinateStatement.setString(1, name); + addCoordinateStatement.setString(2, description); + addCoordinateStatement.setInt(3, position.x()); + addCoordinateStatement.setInt(4, position.y()); + addCoordinateStatement.setInt(5, position.z()); + addCoordinateStatement.setBoolean(6, nether); + addCoordinateStatement.setString(7, color.name()); + addCoordinateStatement.setString(8, world); + + addCoordinateStatement.executeUpdate(); + } catch (SQLException e) { + this.app.getLogger().log(Level.SEVERE, "Error adding coordinate to database: {0}", e.getMessage()); + return false; + } + return true; + } + + /** + * Sets up the connectino to the database. Creates a new .db file if it + * doesn't exist yet. + * + * @return true if the connection was set up successfully. False if not. + */ + private boolean setupDatabase() { + if (!this.app.getDataFolder().exists()) { + if (!this.app.getDataFolder().mkdirs()) { + app.getLogger().severe("Could not create data folder"); + return false; + } + } + + File dbFile = new File(app.getDataFolder(), "database.db"); + String url = "jdbc:sqlite:" + dbFile.getAbsolutePath(); + + try { + this.connection = DriverManager.getConnection(url); + } catch (SQLException e) { + this.app.getLogger().log(Level.SEVERE, "Could not connect to database file {0}: {1}", + new Object[] { dbFile, e.getMessage() }); + } + + this.app.getLogger().log(Level.INFO, "Connected to SQLite database: {0}", dbFile.getName()); + + return true; + } + + /** + * initializes the tables for the database. + * + * @return true if the tables were initialized successfully. False if not. + */ + private boolean initializeTables() { + try { + PreparedStatement createTableStatement = this.connection.prepareStatement(Coordinate.createTableStatement); + createTableStatement.executeUpdate(); + this.app.getLogger().fine("Executed create table statement"); + + PreparedStatement getTablesStatement = this.connection.prepareStatement( + "SELECT name FROM sqlite_master WHERE type='table'"); + ResultSet results = getTablesStatement.executeQuery(); + + while (results.next()) { + this.app.getLogger().log(Level.INFO, "Found table: {0}", results.getString("name")); + } + } catch (SQLException e) { + this.app.getLogger().log(Level.SEVERE, "Could not create table: {0}", e.getMessage()); + return false; + } + return true; + } + +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/MinecraftColor.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/MinecraftColor.java new file mode 100644 index 0000000..11fbd1f --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/db/MinecraftColor.java @@ -0,0 +1,135 @@ +package nl.interestingcorner.coordinates.db; + +import java.util.HashMap; + +import org.bukkit.Material; + +public enum MinecraftColor { + DARK_RED("dark_red"), + RED("red"), + BLACK("black"), + BLUE("blue"), + AQUA("aqua"), + DARK_AQUA("dark_aqua"), + GREEN("green"), + GOLD("gold"), + DARK_PURPLE("dark_purple"), + LIGHT_PURPLE("light_purple"), + YELLOW("yellow"), + DARK_GREEN("dark_green"), + GRAY("gray"), + DARK_GRAY("dark_gray"), + WHITE("white"), + DARK_BLUE("dark_blue"); + + private final String name; + + private static final HashMap materialsMap = new HashMap<>() {{ + put(DARK_RED, Material.RED_WOOL); + put(RED, Material.RED_WOOL); + put(BLACK, Material.BLACK_WOOL); + put(BLUE, Material.BLUE_WOOL); + put(AQUA, Material.LIGHT_BLUE_WOOL); + put(DARK_AQUA, Material.CYAN_WOOL); + put(GREEN, Material.GREEN_WOOL); + put(GOLD, Material.YELLOW_WOOL); + put(DARK_PURPLE, Material.PURPLE_WOOL); + put(LIGHT_PURPLE, Material.MAGENTA_WOOL); + put(YELLOW, Material.YELLOW_WOOL); + put(DARK_GREEN, Material.LIME_WOOL); + put(GRAY, Material.LIGHT_GRAY_WOOL); + put(DARK_GRAY, Material.GRAY_WOOL); + put(WHITE, Material.WHITE_WOOL); + put(DARK_BLUE, Material.BLUE_WOOL); + }}; + + private static final HashMap colorCodesMap = new HashMap<>() {{ + put(DARK_RED, "§4"); + put(RED, "§c"); + put(BLACK, "§0"); + put(BLUE, "§9"); + put(AQUA, "§b"); + put(DARK_AQUA, "§3"); + put(GREEN, "§a"); + put(GOLD, "§6"); + put(DARK_PURPLE, "§5"); + put(LIGHT_PURPLE, "§d"); + put(YELLOW, "§e"); + put(DARK_GREEN, "§2"); + put(GRAY, "§7"); + put(DARK_GRAY, "§8"); + put(WHITE, "§f"); + put(DARK_BLUE, "§1"); + }}; + + MinecraftColor(String name) { + this.name = name; + } + + public boolean equalsName(String otherName) { + return name.equalsIgnoreCase(otherName); + } + + @Override + public String toString() { + return this.name; + } + + /** + * Finds a MinecraftColor from a string value + * + * @param name the name to find the MinecraftColor from + * @return the MinecraftColor if found, null if not found. + */ + public static MinecraftColor fromString(String name) { + if (name == null) { + return WHITE; + } + + for (MinecraftColor color : MinecraftColor.values()) { + if (color.equalsName(name)) { + return color; + } + } + return WHITE; + } + + /** + * Checks if a given name is a valid color value. + * @param name the name to check + * @return true if it's a valid color value, false otherwise + */ + public static boolean isValidColor(String name) + { + if (name == null) + { + return false; + } + + for (MinecraftColor color : values()) { + if (color.equalsName(name)) { + return true; + } + } + + return false; + } + + /** + * Converts this MinecraftColor to a corresponding Material. + * + * @return the Material corresponding to this MinecraftColor + */ + public Material toMaterial() { + return materialsMap.get(this); + } + + /** + * Converts this MinecraftColor to a corresponding Minecraft color code. + * @return + */ + public String toColorCode() { + return colorCodesMap.get(this); + } +} + diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/gui/CoordinatesGUI.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/gui/CoordinatesGUI.java new file mode 100644 index 0000000..626afc5 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/gui/CoordinatesGUI.java @@ -0,0 +1,68 @@ +package nl.interestingcorner.coordinates.gui; + +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import nl.interestingcorner.coordinates.db.Coordinate; +import nl.interestingcorner.coordinates.db.MinecraftColor; + +public class CoordinatesGUI { + public static void open(Player player, List coordinates) { + + int coordinatesAmount = coordinates.size(); + int size; + if (coordinatesAmount <= 9) { + size = 9; + } else { + // TODO handle if size is more than 54 - 9, add pagination + /** + * if more than 45, add pages. Split by 45 items per page. + * use bottom row leftmost and rightmost item for navigation. + * use paper item for page number display in middle. + * use lore of navigation items clicked to handle showing next/previous page. + * use player.getOpeninventory() to get current inventory and update or close it. + */ + + // round up to nearest multiple of 9 + size = ((coordinatesAmount / 9) + 1) * 9; + player.sendMessage("Size: " + size); + } + + // Create an inventory with 9 slots and a title + Inventory gui = Bukkit.createInventory(null, size, "Coordinates Menu"); + + for (Coordinate coordinate : coordinates) { + ItemStack item = createCoordinateItem(coordinate); + gui.addItem(item); + } + + // Open the GUI for the player + player.openInventory(gui); + } + + private static ItemStack createCoordinateItem(Coordinate coordinate) { + ItemStack itemStack = new ItemStack(coordinate.color.toMaterial()); + ItemMeta meta = itemStack.getItemMeta(); + if (meta == null) { + return itemStack; + } + meta.setDisplayName(coordinate.color.toColorCode() + coordinate.name); + meta.setLore(List.of( + MinecraftColor.WHITE.toColorCode() + coordinate.description, + coordinate.nether ? MinecraftColor.RED.toColorCode() + "Nether Coordinate" : "Overworld Coordinate", + "X: " + coordinate.position.x(), + "Y: " + coordinate.position.y(), + "Z: " + coordinate.position.z(), + "World: " + coordinate.world + )); + itemStack.setItemMeta(meta); + + return itemStack; + } +} diff --git a/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/gui/CoordinatesGUIListener.java b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/gui/CoordinatesGUIListener.java new file mode 100644 index 0000000..ef040b6 --- /dev/null +++ b/ic_plugin_coordinates/src/main/java/nl/interestingcorner/coordinates/gui/CoordinatesGUIListener.java @@ -0,0 +1,33 @@ +package nl.interestingcorner.coordinates.gui; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.entity.Player; +import org.bukkit.ChatColor; + +public class CoordinatesGUIListener implements Listener{ + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + + // Check if this is our custom GUI + if (event.getView().getTitle().equals("Coordinates Menu")) { + event.setCancelled(true); // Prevent taking the item + + if (event.getCurrentItem() == null) return; + + Player player = (Player) event.getWhoClicked(); + + switch (event.getSlot()) { + case 0 -> { + player.sendMessage(ChatColor.GREEN + "You clicked Add Coordinate!"); + player.closeInventory(); + // Here you could open another GUI or run a command + } + // Add other cases for other slots if needed + } + } + } + +} diff --git a/ic_plugin_coordinates/src/main/resources/plugin.yml b/ic_plugin_coordinates/src/main/resources/plugin.yml new file mode 100644 index 0000000..a6cb5f3 --- /dev/null +++ b/ic_plugin_coordinates/src/main/resources/plugin.yml @@ -0,0 +1,9 @@ +main: nl.interestingcorner.coordinates.App +name: IC-coords +version: 0.1 +api-version: 1.21 + +commands: + ic-coords: + description: Main command for the coordinates + usage: /ic-coords get | add \ No newline at end of file diff --git a/ic_plugin_coordinates/src/test/java/nl/interestingcorner/AppTest.java b/ic_plugin_coordinates/src/test/java/nl/interestingcorner/AppTest.java new file mode 100644 index 0000000..6d3028e --- /dev/null +++ b/ic_plugin_coordinates/src/test/java/nl/interestingcorner/AppTest.java @@ -0,0 +1,19 @@ +package nl.interestingcorner; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +public class AppTest { + + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() { + assertTrue(true); + } +}