diff --git a/src/main/java/teachingtutorials/TeachingTutorials.java b/src/main/java/teachingtutorials/TeachingTutorials.java index dcbe5aa..432e462 100644 --- a/src/main/java/teachingtutorials/TeachingTutorials.java +++ b/src/main/java/teachingtutorials/TeachingTutorials.java @@ -17,6 +17,7 @@ import teachingtutorials.newlocation.NewLocation; import teachingtutorials.tutorials.*; import teachingtutorials.utils.DBConnection; +import teachingtutorials.utils.Display; import teachingtutorials.utils.User; import teachingtutorials.utils.VirtualBlock; @@ -357,22 +358,15 @@ else if(szLines[iLine].startsWith("(")) return; } szFields = szLines[iLine].split(","); - //Field 1 is step name, field 2 is display type, field 3 is the instruction - if (szFields.length < 3) + //Field 1 is step name, field 2 is display type + if (szFields.length < 2) { Bukkit.getConsoleSender().sendMessage(ChatColor.RED +"Tutorial config is not configured correctly, line: "+(iLine+1)); return; } szType = "Step"; - //Compiles instructions if commas were part of the instruction and split - String szInstructions = szFields[2]; - for (int k = 3 ; k < szFields.length ; k++) - { - szInstructions = szInstructions +"," +szFields[k]; - } - - Step step = new Step(szFields[0].replace("(",""), szFields[1], szInstructions); + Step step = new Step(szFields[0].replace("(",""), szFields[1]); lastStage.steps.add(step); lastStep = step; } @@ -569,10 +563,9 @@ public boolean addNewTutorialToDB(Tutorial tutorial) Step step = steps.get(j); try { - String szStepInstructions = step.getInstructions().replace("\'", "\'\'"); - String szInstructionType = step.getInstructionDisplayType(); + Display.DisplayType instructionDisplayType = step.getInstructionDisplayType(); - sql = "INSERT INTO Steps (StepName, StageID, StepInStage, StepInstructions, InstructionDisplay) VALUES ('"+step.getName()+"', "+iStageID+", "+(j+1)+", '" +szStepInstructions +"' ,'" +szInstructionType +"')"; + sql = "INSERT INTO Steps (StepName, StageID, StepInStage, InstructionDisplay) VALUES ('"+step.getName()+"', "+iStageID+", "+(j+1)+",'" +instructionDisplayType +"')"; Bukkit.getConsoleSender().sendMessage(sql); SQL.executeUpdate(sql); @@ -671,10 +664,6 @@ public Connection getConnection() private boolean createTables() { - //Is assumed true and if any of the tables fail to create will change to false - boolean bSuccess = true; -// int iCount = -1; - sql = ""; FileReader fileReader = null; @@ -712,16 +701,6 @@ private boolean createTables() //Executes the update and returns how many rows were changed SQL.executeUpdate(statements[i]); - -// //If only 1 record was changed, success is set to true - FCKING IDIOT -// if (iCount == 1) -// { -// } -// else -// { -// Bukkit.getConsoleSender().sendMessage(ChatColor.RED +"[TeachingTutorials] - Failed to execute table, iCount = "+iCount +"\n"); -// bSuccess = false; -// } Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] - Executed command\n"); } } @@ -758,7 +737,7 @@ private boolean createTables() } dbConnection.disconnect(); } - return (bSuccess); + return true; } private String readAll(BufferedReader br) diff --git a/src/main/java/teachingtutorials/TutorialPlaythrough.java b/src/main/java/teachingtutorials/TutorialPlaythrough.java index 32ee610..bf3ee01 100644 --- a/src/main/java/teachingtutorials/TutorialPlaythrough.java +++ b/src/main/java/teachingtutorials/TutorialPlaythrough.java @@ -46,6 +46,12 @@ public User getCreatorOrStudent() return creatorOrStudent; } + public void setFallListenerSafeLocation(org.bukkit.Location location) + { + //Raises the safe location by 1 block to ensure players do not tp inside blocks as used to happen sometimes + fallListener.setSafeLocation(location.add(0, 1, 0)); + } + // Moves the tutorial on to the next stage // Accessed after the end of each stage (Called from Stage.endStage() asynchronously) // or at the start of the playthrough diff --git a/src/main/java/teachingtutorials/compulsory/Compulsory.java b/src/main/java/teachingtutorials/compulsory/Compulsory.java index 0c7e78d..1530cb7 100644 --- a/src/main/java/teachingtutorials/compulsory/Compulsory.java +++ b/src/main/java/teachingtutorials/compulsory/Compulsory.java @@ -12,8 +12,8 @@ public Compulsory(TeachingTutorials plugin, User user) super(user, plugin, true); } - public void startLesson() + public boolean startLesson() { - super.startLesson(); + return super.startLesson(); } } diff --git a/src/main/java/teachingtutorials/fundamentalTasks/Chat.java b/src/main/java/teachingtutorials/fundamentalTasks/Chat.java index aa5e981..ffaf2a6 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/Chat.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/Chat.java @@ -47,7 +47,7 @@ public Chat(TeachingTutorials plugin, Player player, Group parentGroup, int iTas this.szDetails = szDetails; //Listen out for difficulty - There will only be one difficulty listener per chat to avoid bugs - difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTask.chat); + difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTaskType.chat); difficultyListener.register(); } diff --git a/src/main/java/teachingtutorials/fundamentalTasks/Command.java b/src/main/java/teachingtutorials/fundamentalTasks/Command.java index 08c6fce..2c984c6 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/Command.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/Command.java @@ -103,7 +103,7 @@ public Command(TeachingTutorials plugin, Player player, Group parentGroup, int i this.commandType = teachingtutorials.fundamentalTasks.commandType.valueOf(szDetails); //Listen out for difficulty - There will only be one difficulty listener per command to avoid bugs - difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTask.command); + difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTaskType.command); difficultyListener.register(); tasksInGroup = tasks; diff --git a/src/main/java/teachingtutorials/fundamentalTasks/FundamentalTask.java b/src/main/java/teachingtutorials/fundamentalTasks/FundamentalTaskType.java similarity index 73% rename from src/main/java/teachingtutorials/fundamentalTasks/FundamentalTask.java rename to src/main/java/teachingtutorials/fundamentalTasks/FundamentalTaskType.java index 6483039..4fe9bf7 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/FundamentalTask.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/FundamentalTaskType.java @@ -1,6 +1,6 @@ package teachingtutorials.fundamentalTasks; -public enum FundamentalTask +public enum FundamentalTaskType { tpll, selection, command, place, chat } diff --git a/src/main/java/teachingtutorials/fundamentalTasks/GeometricUtils.java b/src/main/java/teachingtutorials/fundamentalTasks/GeometricUtils.java index b6dcfb5..946fafa 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/GeometricUtils.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/GeometricUtils.java @@ -58,8 +58,6 @@ public static double[] convertToMCCoordinates(double dLatitude, double dLongitud { double[] xz = null; - final GeographicProjection projection = EarthGeneratorSettings.parse(EarthGeneratorSettings.BTE_DEFAULT_SETTINGS).projection(); - try { xz = projection.fromGeo(dLongitude, dLatitude); @@ -71,6 +69,21 @@ public static double[] convertToMCCoordinates(double dLatitude, double dLongitud return xz; } + public static double[] convertToGeometricCoordinates(double X, double Z) + { + double[] longLat = null; + + try + { + longLat = projection.toGeo(X, Z); + } + catch (OutOfProjectionBoundsException e) + { + //Player has selected an area outside of the projection + } + return longLat; + } + public static boolean tpllPlayer(World world, double latitude, double longitude, Player player) { try diff --git a/src/main/java/teachingtutorials/fundamentalTasks/Place.java b/src/main/java/teachingtutorials/fundamentalTasks/Place.java index b040338..c755f3f 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/Place.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/Place.java @@ -67,7 +67,7 @@ public Place(TeachingTutorials plugin, Player player, Group parentGroup, int iTa this.szDetails = szDetails; //Listen out for difficulty - There will only be one difficulty listener per place task to avoid bugs - difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTask.tpll); + difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTaskType.tpll); difficultyListener.register(); } diff --git a/src/main/java/teachingtutorials/fundamentalTasks/Selection.java b/src/main/java/teachingtutorials/fundamentalTasks/Selection.java index 45845e3..cb03a90 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/Selection.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/Selection.java @@ -86,7 +86,7 @@ public Selection(TeachingTutorials plugin, Player player, Group parentGroup, int this.bSelection2Made = false; //Listen out for difficulty - There will only be one difficulty listener per selection to avoid bugs - difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTask.selection); + difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTaskType.selection); difficultyListener.register(); } diff --git a/src/main/java/teachingtutorials/fundamentalTasks/TpllListener.java b/src/main/java/teachingtutorials/fundamentalTasks/TpllListener.java index e364661..d21dd23 100644 --- a/src/main/java/teachingtutorials/fundamentalTasks/TpllListener.java +++ b/src/main/java/teachingtutorials/fundamentalTasks/TpllListener.java @@ -1,8 +1,5 @@ package teachingtutorials.fundamentalTasks; -import net.buildtheearth.terraminusminus.generator.EarthGeneratorSettings; -import net.buildtheearth.terraminusminus.projection.GeographicProjection; -import net.buildtheearth.terraminusminus.projection.OutOfProjectionBoundsException; import net.buildtheearth.terraminusminus.util.geo.CoordinateParseUtils; import net.buildtheearth.terraminusminus.util.geo.LatLng; import org.bukkit.*; @@ -15,7 +12,6 @@ import teachingtutorials.TeachingTutorials; import teachingtutorials.newlocation.DifficultyListener; import teachingtutorials.tutorials.Group; -import teachingtutorials.tutorials.Location; import teachingtutorials.tutorials.LocationTask; import teachingtutorials.utils.Display; @@ -82,7 +78,7 @@ public TpllListener(TeachingTutorials plugin, Player player, Group parentGroup, this.szDetails = szDetails; //Listen out for difficulty - There will only be one difficulty listener per tpll command to avoid bugs - difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTask.tpll); + difficultyListener = new DifficultyListener(this.plugin, this.player, this, FundamentalTaskType.tpll); difficultyListener.register(); } diff --git a/src/main/java/teachingtutorials/guis/CreatorTutorialsMenu.java b/src/main/java/teachingtutorials/guis/CreatorTutorialsMenu.java index d584e0c..d44823a 100644 --- a/src/main/java/teachingtutorials/guis/CreatorTutorialsMenu.java +++ b/src/main/java/teachingtutorials/guis/CreatorTutorialsMenu.java @@ -177,9 +177,7 @@ private void leftClicked(User u, int iSlot) { if (tutorials[iSlot].toggleInUse()) { - delete(); this.refresh(); - u.mainGui.open(u); } else { diff --git a/src/main/java/teachingtutorials/guis/Gui.java b/src/main/java/teachingtutorials/guis/Gui.java index 2458460..6c6e1bc 100644 --- a/src/main/java/teachingtutorials/guis/Gui.java +++ b/src/main/java/teachingtutorials/guis/Gui.java @@ -85,12 +85,7 @@ public void open(User u) { public void delete() { for (Player p : Bukkit.getOnlinePlayers()) { - UUID u = openInventories.get(p.getUniqueId()); - if (u != null) { - if (u.equals(getUuid())) { - p.closeInventory(); - } - } + openInventories.remove(p.getUniqueId(), getUuid()); } inventoriesByUUID.remove(getUuid()); } diff --git a/src/main/java/teachingtutorials/guis/LibraryMenu.java b/src/main/java/teachingtutorials/guis/LibraryMenu.java index c5c9dd7..ac209c1 100644 --- a/src/main/java/teachingtutorials/guis/LibraryMenu.java +++ b/src/main/java/teachingtutorials/guis/LibraryMenu.java @@ -145,13 +145,13 @@ public void rightClick(User u) { @Override public void leftClick(User u) { - delete(); - //Creates a NewLocation object Lesson newLesson = new Lesson(user, plugin, tutorials[iSlot]); //Launches them into the new location adding process - newLesson.startLesson(); + if (newLesson.startLesson()) + delete(); + user.mainGui = null; } }); } diff --git a/src/main/java/teachingtutorials/guis/MainMenu.java b/src/main/java/teachingtutorials/guis/MainMenu.java index b1c0a02..a555197 100644 --- a/src/main/java/teachingtutorials/guis/MainMenu.java +++ b/src/main/java/teachingtutorials/guis/MainMenu.java @@ -68,10 +68,9 @@ public void rightClick(User u) @Override public void leftClick(User u) { - //Deletes this gui - delete(); - - performEvent(EventType.COMPULSORY, u, plugin); + if (performEvent(EventType.COMPULSORY, u, plugin)) + //Deletes this gui + delete(); } }); @@ -83,10 +82,9 @@ public void rightClick(User u) { } @Override public void leftClick(User u) { - //Deletes this gui - delete(); - - performEvent(EventType.LIBRARY, u, plugin); + if (performEvent(EventType.LIBRARY, u, plugin)) + //Deletes this gui + delete(); } }); @@ -100,10 +98,9 @@ public void rightClick(User u) @Override public void leftClick(User u) { - //Deletes this gui - delete(); - - performEvent(EventType.CONTINUE, u, plugin); + if (performEvent(EventType.CONTINUE, u, plugin)) + //Deletes this gui + delete(); } }); } @@ -129,10 +126,9 @@ public void rightClick(User u) { } @Override public void leftClick(User u) { - //Deletes this gui - delete(); - - performEvent(EventType.COMPULSORY, u, plugin); + if (performEvent(EventType.COMPULSORY, u, plugin)) + //Deletes this gui + delete(); } }); } @@ -149,10 +145,9 @@ public void rightClick(User u) @Override public void leftClick(User u) { - //Deletes this gui - delete(); - - performEvent(EventType.CONTINUE, u, plugin); + if (performEvent(EventType.CONTINUE, u, plugin)) + //Deletes this gui + delete(); } }); @@ -164,10 +159,9 @@ public void rightClick(User u) { } @Override public void leftClick(User u) { - //Deletes this gui - delete(); - - performEvent(EventType.LIBRARY, u, plugin); + if (performEvent(EventType.LIBRARY, u, plugin)) + //Deletes this gui + delete(); } }); } @@ -184,36 +178,42 @@ public void rightClick(User u) { } @Override public void leftClick(User u) { - //Deletes this gui - delete(); - performEvent(EventType.ADMIN_MENU, u, plugin); + if (performEvent(EventType.ADMIN_MENU, u, plugin)) + //Deletes this gui + delete(); } }); } } - public static void performEvent(EventType event, User user, TeachingTutorials plugin) + public static boolean performEvent(EventType event, User user, TeachingTutorials plugin) { switch (event) { case COMPULSORY -> { //Starts the compulsory tutorial Compulsory compulsory = new Compulsory(plugin, user); - compulsory.startLesson(); + return compulsory.startLesson(); } case CONTINUE -> { //Creates a lesson with the user Lesson lesson = new Lesson(user, plugin, false); - lesson.startLesson(); + return lesson.startLesson(); } case ADMIN_MENU -> { user.mainGui = new AdminMenu(plugin, user); user.mainGui.open(user); + return true; } case LIBRARY -> { user.mainGui = new LibraryMenu(plugin, user, Tutorial.getInUseTutorialsWithLocations()); user.mainGui.open(user); + return true; + } + default -> + { + return false; } } } @@ -226,4 +226,11 @@ public void refresh() this.open(user); } + + @Override + public void delete() + { + super.delete(); + user.mainGui = null; + } } diff --git a/src/main/java/teachingtutorials/guis/locationcreatemenus/StepEditorMenu.java b/src/main/java/teachingtutorials/guis/locationcreatemenus/StepEditorMenu.java new file mode 100644 index 0000000..e644c85 --- /dev/null +++ b/src/main/java/teachingtutorials/guis/locationcreatemenus/StepEditorMenu.java @@ -0,0 +1,185 @@ +package teachingtutorials.guis.locationcreatemenus; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import teachingtutorials.TeachingTutorials; +import teachingtutorials.guis.Gui; +import teachingtutorials.listeners.TextEditorBookListener; +import teachingtutorials.tutorials.LocationStep; +import teachingtutorials.tutorials.Step; +import teachingtutorials.utils.Display; +import teachingtutorials.utils.User; +import teachingtutorials.utils.Utils; + +/** + * A menu accessible to a creator when creating a new location, used to set the step instructions, + * the step start location and the hologram location of whatever step the creator is currently at + */ +public class StepEditorMenu extends Gui +{ + private static final int iInvSize = 3 * 9; + private final TeachingTutorials plugin; + private final User user; + private final Step step; + private final LocationStep locationStep; + + private TextEditorBookListener bookListener; + + private ItemStack book; + + public StepEditorMenu(TeachingTutorials plugin, User user, Step step, LocationStep locationStep) + { + super(iInvSize, getName(step.getName())); + this.plugin = plugin; + this.user = user; + this.step = step; + this.locationStep = locationStep; + + this.book = new ItemStack(Material.WRITABLE_BOOK, 1); + BookMeta bookMeta = (BookMeta) book.getItemMeta(); + bookMeta.setTitle(step.getName()); + this.book.setItemMeta(bookMeta); + + setItems(); + } + + public void setItems() + { + ItemStack setStartLocation = Utils.createItem(Material.COMPASS, 1, + Component.text("Set the step's start location", NamedTextColor.GREEN), + Component.text("Set the start location to your current position and direction", NamedTextColor.DARK_GREEN)); + + ItemStack teleportToStart = Utils.createItem(Material.VILLAGER_SPAWN_EGG, 1, + Component.text("Teleport back to the start location", NamedTextColor.GREEN)); + + boolean bIsHologramNeeded = step.getInstructionDisplayType().equals(Display.DisplayType.hologram); + if (bIsHologramNeeded) + { + //Set start location coordinates to current location + setItem(11, setStartLocation, new guiAction() { + @Override + public void rightClick(User u) { + leftClick(u); + } + + @Override + public void leftClick(User u) { + setStartLocation(u.player.getLocation()); + } + }); + + //Set instructions + ItemStack instructions = Utils.createItem(Material.WRITABLE_BOOK, 1, + Component.text("Set the instructions", NamedTextColor.GREEN)); + + setItem(13, instructions, new guiAction() { + @Override + public void rightClick(User u) { + leftClick(u); + } + + @Override + public void leftClick(User u) { + //The book must have the step name as the title + Utils.giveItem(u.player, book, "Instructions editor book"); + Display display = new Display(u.player, Component.text("Use the instructions editor book to set the instructions", NamedTextColor.GREEN)); + display.Message(); + + //Closes the current inventory + u.player.closeInventory(InventoryCloseEvent.Reason.PLUGIN); + + //Sets up the book listener and registers it + bookListener = new TextEditorBookListener(plugin, u, locationStep, StepEditorMenu.this, step.getInstructionDisplayType(), step.getName(), book); + bookListener.register(); + + //step.tryNextStep() is called via instructionsEdited() from TextEditorBookListener once the book close event occurs + } + }); + + //Set hologram coordinates to player's current location + ItemStack hologramLocation = Utils.createItem(Material.FILLED_MAP, 1, + Component.text("Set the instructions hologram location", NamedTextColor.GREEN), + Component.text("Set the instructions hologram to your current position", NamedTextColor.DARK_GREEN)); + + setItem(15, hologramLocation, new guiAction() { + @Override + public void rightClick(User u) { + leftClick(u); + } + + @Override + public void leftClick(User u) { + locationStep.setHologramLocationToThatOfPlayer(u.player, step.getName()); + step.tryNextStep(); + } + }); + } + else + { + setItem(13, setStartLocation, new guiAction() { + @Override + public void rightClick(User u) { + leftClick(u); + } + + @Override + public void leftClick(User u) { + setStartLocation(u.player.getLocation()); + } + }); + } + + //Teleport to start + setItem(0, teleportToStart, new guiAction() { + @Override + public void rightClick(User u) { + leftClick(u); + } + + @Override + public void leftClick(User u) { + locationStep.teleportPlayerToStartOfStep(u.player, step.parentStage.tutorialPlaythrough.getLocation().getWorld(), plugin); + } + }); + } + + private void setStartLocation(Location playersLocation) + { + locationStep.setStartLocation(playersLocation); + step.parentStage.tutorialPlaythrough.setFallListenerSafeLocation(playersLocation); + step.tryNextStep(); + } + + public static Component getName(String szStepName) + { + Component inventoryName = Component.text("Step - " +szStepName, Style.style(TextDecoration.BOLD, NamedTextColor.DARK_AQUA)); + return inventoryName; + } + + /** + * Clears items from the GUI, recreates the items and then opens the menu + */ + @Override + public void refresh() + { + this.clearGui(); + this.setItems(); + + this.open(user); + } + + /** + * Triggers the step to test whether it can move forwards with the stage + */ + public void instructionsEdited() + { + step.tryNextStep(); + } +} diff --git a/src/main/java/teachingtutorials/listeners/Falling.java b/src/main/java/teachingtutorials/listeners/Falling.java index 7438f8e..6465f12 100644 --- a/src/main/java/teachingtutorials/listeners/Falling.java +++ b/src/main/java/teachingtutorials/listeners/Falling.java @@ -23,6 +23,17 @@ public Falling (Player player, Location safeLocation, TeachingTutorials plugin) this.plugin = plugin; } + public Falling (Player player, TeachingTutorials plugin) + { + this.player = player; + this.plugin = plugin; + } + + public void setSafeLocation(Location location) + { + this.safeLocation = location; + } + @EventHandler public void onClick(PlayerMoveEvent event) { diff --git a/src/main/java/teachingtutorials/listeners/GlobalPlayerCommandProcess.java b/src/main/java/teachingtutorials/listeners/GlobalPlayerCommandProcess.java index 06e01f0..38f7953 100644 --- a/src/main/java/teachingtutorials/listeners/GlobalPlayerCommandProcess.java +++ b/src/main/java/teachingtutorials/listeners/GlobalPlayerCommandProcess.java @@ -1,7 +1,6 @@ package teachingtutorials.listeners; import net.buildtheearth.terraminusminus.generator.EarthGeneratorSettings; -import net.buildtheearth.terraminusminus.projection.GeographicProjection; import net.buildtheearth.terraminusminus.projection.OutOfProjectionBoundsException; import net.buildtheearth.terraminusminus.util.geo.CoordinateParseUtils; import net.buildtheearth.terraminusminus.util.geo.LatLng; @@ -44,6 +43,9 @@ public GlobalPlayerCommandProcess(TeachingTutorials plugin) @EventHandler(priority = EventPriority.LOW) public void commandEvent(PlayerCommandPreprocessEvent event) { + if (event.isCancelled()) + return; + //Extracts the player to a local variable Player player = event.getPlayer(); @@ -116,11 +118,20 @@ else if (command.startsWith("/tutorials") || command.startsWith("/learn")) User user = User.identifyUser(plugin, player); if (user != null) { + //Check if the mainGui is not null. if (user.mainGui != null) - user.mainGui.delete(); - - user.mainGui = new MainMenu(plugin, user); - user.mainGui.open(user); + //If not then open it after refreshing its contents. + user.mainGui.refresh(); + + //If no gui exists open the learning menu + else + { + //Creates a new main menu + user.mainGui = new MainMenu(plugin, user); + + //Opens the gui + user.mainGui.open(user); + } } } } diff --git a/src/main/java/teachingtutorials/listeners/PlayerInteract.java b/src/main/java/teachingtutorials/listeners/PlayerInteract.java index 9b133b7..eae78f9 100644 --- a/src/main/java/teachingtutorials/listeners/PlayerInteract.java +++ b/src/main/java/teachingtutorials/listeners/PlayerInteract.java @@ -42,15 +42,21 @@ public void interactEvent(PlayerInteractEvent e) if (player.getInventory().getItemInMainHand().equals(TeachingTutorials.menu)) { e.setCancelled(true); - //Check if the mainGui is not null. - //If not then open it after refreshing its contents. - //If no gui exists open the navigator. + //Check if the mainGui is not null. if (user.mainGui != null) + //If not then open it after refreshing its contents. user.mainGui.refresh(); + + //If no gui exists open the learning menu else + { + //Creates a new main menu user.mainGui = new MainMenu(plugin, user); - user.mainGui.open(user); + + //Opens the gui + user.mainGui.open(user); + } } } } diff --git a/src/main/java/teachingtutorials/listeners/TextEditorBookListener.java b/src/main/java/teachingtutorials/listeners/TextEditorBookListener.java new file mode 100644 index 0000000..0b0a764 --- /dev/null +++ b/src/main/java/teachingtutorials/listeners/TextEditorBookListener.java @@ -0,0 +1,95 @@ +package teachingtutorials.listeners; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerEditBookEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import teachingtutorials.TeachingTutorials; +import teachingtutorials.guis.locationcreatemenus.StepEditorMenu; +import teachingtutorials.tutorials.LocationStep; +import teachingtutorials.utils.Display; +import teachingtutorials.utils.User; + +import java.util.List; + +public class TextEditorBookListener implements Listener +{ + private TeachingTutorials plugin; + private User user; + private LocationStep locationStep; + private StepEditorMenu stepEditorMenu; + private Display.DisplayType displayType; + private String szStepName; + private ItemStack book; + + public TextEditorBookListener(TeachingTutorials plugin, User user, LocationStep locationStep, StepEditorMenu stepEditorMenu, Display.DisplayType displayType, String szStepName, ItemStack book) + { + this.plugin = plugin; + this.user = user; + this.locationStep = locationStep; + this.stepEditorMenu = stepEditorMenu; + this.displayType = displayType; + this.szStepName = szStepName; + this.book = book; + } + + public void register() + { + Bukkit.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void BookCloseEvent(PlayerEditBookEvent e) + { + //Check the player + if (!e.getPlayer().equals(user.player)) + return; + + //We can't actually also check the book because the event doesn't give that + //We can only check the title + if (!e.getNewBookMeta().getTitle().equalsIgnoreCase(szStepName)) + return; + + //Extracts the new content from the book + String szNewContent = ""; + List pages = e.getNewBookMeta().pages(); + for (Component page: pages) + { + szNewContent = szNewContent + ((TextComponent) page).content() + " "; + + } + //Removes the end space, the space after the last page is added in the loop but then needs to be removed + szNewContent = szNewContent.substring(0, szNewContent.length() - 1); + + //Edits the step instructions + locationStep.setInstruction(szNewContent, displayType, user.player, szStepName); + + //Saves the instructions in the book + BookMeta bookMeta = (BookMeta) book.getItemMeta(); + bookMeta.pages(e.getNewBookMeta().pages()); + this.book.setItemMeta(bookMeta); + + //Reopen the feature menu + user.mainGui = stepEditorMenu; + user.mainGui.refresh(); + + //Unregisters this listener + unregister(); + + //Removes the book + user.player.getInventory().getItemInMainHand().setAmount(0); + + //Informs the menu that some instructions were edited + stepEditorMenu.instructionsEdited(); + } + + private void unregister() + { + HandlerList.unregisterAll(this); + } +} diff --git a/src/main/java/teachingtutorials/newlocation/DifficultyListener.java b/src/main/java/teachingtutorials/newlocation/DifficultyListener.java index bfb9397..b62588e 100644 --- a/src/main/java/teachingtutorials/newlocation/DifficultyListener.java +++ b/src/main/java/teachingtutorials/newlocation/DifficultyListener.java @@ -9,7 +9,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import teachingtutorials.TeachingTutorials; -import teachingtutorials.fundamentalTasks.FundamentalTask; +import teachingtutorials.fundamentalTasks.FundamentalTaskType; import teachingtutorials.fundamentalTasks.Task; import teachingtutorials.tutorials.LocationTask; import teachingtutorials.utils.Display; @@ -21,10 +21,10 @@ public class DifficultyListener implements Listener Player player; LocationTask locationTask; Task task; - FundamentalTask taskType; + FundamentalTaskType taskType; boolean bReadyForDifficulty; - public DifficultyListener(TeachingTutorials plugin, Player player, Task task, FundamentalTask taskType) + public DifficultyListener(TeachingTutorials plugin, Player player, Task task, FundamentalTaskType taskType) { this.plugin = plugin; this.player = player; diff --git a/src/main/java/teachingtutorials/newlocation/NewLocation.java b/src/main/java/teachingtutorials/newlocation/NewLocation.java index fb31c2d..e2920e2 100644 --- a/src/main/java/teachingtutorials/newlocation/NewLocation.java +++ b/src/main/java/teachingtutorials/newlocation/NewLocation.java @@ -12,11 +12,11 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.event.player.PlayerTeleportEvent; import teachingtutorials.TeachingTutorials; import teachingtutorials.TutorialPlaythrough; import teachingtutorials.fundamentalTasks.GeometricUtils; +import teachingtutorials.guis.MainMenu; import teachingtutorials.listeners.Falling; import teachingtutorials.newlocation.elevation.ElevationManager; import teachingtutorials.tutorials.Location; @@ -25,7 +25,6 @@ import teachingtutorials.utils.Display; import teachingtutorials.utils.Mode; import teachingtutorials.utils.User; -import teachingtutorials.utils.VirtualBlock; import teachingtutorials.utils.plugins.Multiverse; import teachingtutorials.utils.plugins.WorldGuard; @@ -202,13 +201,13 @@ public void AreaSelectionMade() } //Called from the StartLocationListener once the start location has been dictated - public void lessonStart(LatLng latLong) + public void lessonStart(LatLng startTP) { //Updates the stage this.stage = NewLocationProcess.creatingLocationForDB; //Creates a new location object - this.location = new Location(latLong, this.getTutorialID()); + this.location = new Location(this.getTutorialID(), true); //Adds the location to the database if (location.insertNewLocation()) @@ -280,7 +279,7 @@ public void lessonStart(LatLng latLong) @Override public void run() { try { - generateArea(world); + generateArea(world, startTP); } catch (OutOfProjectionBoundsException e) { @@ -295,10 +294,10 @@ public void run() { }); } - private void teleportCreatorAndStartLesson(World world) + private void teleportCreatorAndStartLesson(World world, LatLng startTP) { //Finds the start location - org.bukkit.Location tpLocation = GeometricUtils.convertToBukkitLocation(world, location.getStartCoordinates().getLat(), location.getStartCoordinates().getLng()); + org.bukkit.Location tpLocation = GeometricUtils.convertToBukkitLocation(world, startTP.getLat(), startTP.getLng()); //Registers the fall listener fallListener = new Falling(creatorOrStudent.player, tpLocation, plugin); @@ -352,6 +351,7 @@ public void terminateEarly() case inputtingAnswers: //Performs common playthrough termination processes super.commonEndPlaythrough(); + creatorOrStudent.mainGui = new MainMenu(plugin, creatorOrStudent); //Delete the location in the DB if(Location.deleteLocationByID(location.getLocationID())) @@ -387,7 +387,7 @@ protected void endPlaythrough() super.commonEndPlaythrough(); } - private void generateArea(World world) throws OutOfProjectionBoundsException + private void generateArea(World world, LatLng startTP) throws OutOfProjectionBoundsException { //UK121Generation(world); TerraMinusMinusGeneration(world); @@ -398,7 +398,7 @@ private void generateArea(World world) throws OutOfProjectionBoundsException Bukkit.getScheduler().runTask(plugin, new Runnable() { @Override public void run() { - teleportCreatorAndStartLesson(world); + teleportCreatorAndStartLesson(world, startTP); } }); } diff --git a/src/main/java/teachingtutorials/tutorials/Lesson.java b/src/main/java/teachingtutorials/tutorials/Lesson.java index 9926587..db4d371 100644 --- a/src/main/java/teachingtutorials/tutorials/Lesson.java +++ b/src/main/java/teachingtutorials/tutorials/Lesson.java @@ -73,7 +73,7 @@ public Lesson(User player, TeachingTutorials plugin, Tutorial tutorial) } //Used for kicking the lesson off, determines whether it needs to create a new lesson or resume a previous lesson - public void startLesson() + public boolean startLesson() { //Checks to see whether a user is actually free to start a new lesson //(Not already doing a tutorial, creating a tutorial, creating a location etc.) @@ -81,6 +81,7 @@ public void startLesson() { Display display = new Display(creatorOrStudent.player, ChatColor.DARK_AQUA +"Complete your current tutorial first"); display.Message(); + return false; } //Student is ready to go into a lesson and the tutorial must now be determined @@ -92,22 +93,20 @@ public void startLesson() //Attempts to resume the lesson if the student has a lesson that they need to complete if (resumeLesson()) { //If the lesson resumed successfully - //Registers the fall listener - fallListener = new Falling(creatorOrStudent.player, location.calculateBukkitStartLocation(), plugin); - fallListener.register(); - creatorOrStudent.currentMode = Mode.Doing_Tutorial; //Updates the user's current mode creatorOrStudent.bInLesson = true; //Updates the user's "In Lesson" status in RAM creatorOrStudent.setInLesson(1); //Updates the DB //Adds this lesson to the list of lessons ongoing on the server this.plugin.lessons.add(this); + return true; } else { //If the lesson failed to resume Display display = new Display(creatorOrStudent.player, ChatColor.RED +"Could not resume lesson, speak to staff"); display.Message(); Bukkit.getConsoleSender().sendMessage(ChatColor.RED +"Could not resume lesson for player: "+creatorOrStudent.player.getName()); + return false; } } @@ -122,10 +121,6 @@ public void startLesson() addLessonToDB(); //There is currently no check to determine whether the DB creation worked - //Registers the fall listener - fallListener = new Falling(creatorOrStudent.player, location.calculateBukkitStartLocation(), plugin); - fallListener.register(); - //Updates the user's mode, "In Lesson" status in RAM, and "In Lesson" status in the DB creatorOrStudent.currentMode = Mode.Doing_Tutorial; creatorOrStudent.bInLesson = true; @@ -133,12 +128,16 @@ public void startLesson() //Adds this lesson to the list of lessons ongoing on the server this.plugin.lessons.add(this); + + return true; } else { //If the lesson failed to be created Display display = new Display(creatorOrStudent.player, ChatColor.RED +"Could not create lesson, speak to staff"); display.Message(); Bukkit.getConsoleSender().sendMessage(ChatColor.RED +"Could not create lesson for player: "+creatorOrStudent.player.getName()); + + return false; } } } @@ -160,16 +159,6 @@ private boolean resumeLesson() +", Tutorial ID = " +this.tutorial.getTutorialID() +" and LocationID = "+this.location.getLocationID()); - //Teleports the player to the location's world - org.bukkit.Location tpLocation = location.calculateBukkitStartLocation(); - if (tpLocation == null) - { - creatorOrStudent.player.sendMessage(ChatColor.RED +"Could not teleport you to the start location"); - return false; - } - else - creatorOrStudent.player.teleport(tpLocation); - //Redisplays all virtual blocks for (int i = 0 ; i < iStageIndex ; i++) { @@ -182,6 +171,10 @@ private boolean resumeLesson() //Takes the stage position back for it to then be set forward again at the start of nextStage() iStageIndex = iStageIndex - 1; + //Registers the fall listener + fallListener = new Falling(creatorOrStudent.player, plugin); + fallListener.register(); + //Continues the current stage nextStage(iStepToStart); @@ -240,19 +233,13 @@ else if (bTutorialDetailsAlreadyEntered) +", Tutorial ID = " +this.tutorial.getTutorialID() +" and LocationID = "+this.location.getLocationID()); - //Teleports the student to the start location of the location - org.bukkit.Location tpLocation = location.calculateBukkitStartLocation(); - if (tpLocation == null) - { - creatorOrStudent.player.sendMessage(ChatColor.RED +"Could not teleport you to the start location"); - return false; - } - else - creatorOrStudent.player.teleport(tpLocation); - //Set the current stage to the first stage this.iStageIndex = 0; + //Registers the fall listener + fallListener = new Falling(creatorOrStudent.player, plugin); + fallListener.register(); + //Signals for the next stage (the first stage) to begin nextStage(1); } diff --git a/src/main/java/teachingtutorials/tutorials/Location.java b/src/main/java/teachingtutorials/tutorials/Location.java index e18e983..dd3a05e 100644 --- a/src/main/java/teachingtutorials/tutorials/Location.java +++ b/src/main/java/teachingtutorials/tutorials/Location.java @@ -1,8 +1,5 @@ package teachingtutorials.tutorials; -import net.buildtheearth.terraminusminus.generator.EarthGeneratorSettings; -import net.buildtheearth.terraminusminus.projection.GeographicProjection; -import net.buildtheearth.terraminusminus.util.geo.LatLng; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.World; @@ -15,7 +12,6 @@ public class Location { private int iLocationID; - private LatLng startCoordinates; private int iTutorialID; private float fDifficulty; private World world; @@ -25,9 +21,8 @@ public class Location //-------------------------------------------------- //Used for creating a new location - public Location(LatLng latlong, int iTutorialID) + public Location(int iTutorialID, boolean bNew) { - this.startCoordinates = latlong; this.iTutorialID = iTutorialID; } @@ -56,6 +51,8 @@ public int getLocationID() public World getWorld() { + if (world == null) + world = Bukkit.getWorld(iLocationID+""); return world; } @@ -64,11 +61,6 @@ public int getTutorialID() return iTutorialID; } - public LatLng getStartCoordinates() - { - return startCoordinates; - } - //--------------------------------------------------- //----------------------Setters---------------------- //--------------------------------------------------- @@ -78,33 +70,6 @@ public void setWorld(World world) this.world = world; } - //--------------------------------------------------- - //-----------------------Utils----------------------- - //--------------------------------------------------- - - public org.bukkit.Location calculateBukkitStartLocation() - { - double[] xz; - final GeographicProjection projection = EarthGeneratorSettings.parse(EarthGeneratorSettings.BTE_DEFAULT_SETTINGS).projection(); - - //Converts the longitude and latitude start coordinates of the location to minecraft coordinates - try - { - xz = projection.fromGeo(this.getStartCoordinates().getLng(), this.getStartCoordinates().getLat()); - //Declares location object - org.bukkit.Location tpLocation; - - tpLocation = new org.bukkit.Location(world, xz[0], world.getHighestBlockYAt((int) xz[0], (int) xz[1]) + 1, xz[1]); - return tpLocation; - } - catch (Exception e) - { - e.printStackTrace(); - Bukkit.getConsoleSender().sendMessage(ChatColor.RED +"Unable to convert lat,long coordinates of start location to minecraft coordinates"); - return null; - } - } - //--------------------------------------------------- //--------------------SQL Fetches-------------------- //--------------------------------------------------- @@ -130,12 +95,7 @@ private void fetchDetailsByLocationID() //Stores the information this.fDifficulty = resultSet.getFloat("Difficulty");; - double dLatitude = resultSet.getDouble("Latitude"); - double dLongitude = resultSet.getDouble("Longitude"); this.iTutorialID = resultSet.getInt("TutorialID"); - - //Puts the start coordinates into the LatLng object - this.startCoordinates = new LatLng(dLatitude, dLongitude); } catch (Exception e) { @@ -199,7 +159,7 @@ public boolean insertNewLocation() try { SQL = TeachingTutorials.getInstance().getConnection().createStatement(); - sql = "INSERT INTO Locations (TutorialID, Latitude, Longitude) VALUES (" +iTutorialID +", " +startCoordinates.getLat() +", " +startCoordinates.getLng() +")"; + sql = "INSERT INTO Locations (TutorialID) VALUES (" +iTutorialID+")"; Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +sql); iCount = SQL.executeUpdate(sql); @@ -247,6 +207,12 @@ public static boolean deleteLocationByID(int iLocationID) iCount = SQL.executeUpdate(sql); Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] " +iCount +" LocationTasks were deleted"); + //Removes the location specific step details + sql = "Delete FROM LocationSteps WHERE LocationID = " +iLocationID; + Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] " +sql); + iCount = SQL.executeUpdate(sql); + Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] " +iCount +" LocationSteps were deleted"); + //Removes the location sql = "Delete FROM Locations WHERE LocationID = " +iLocationID; Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] " +sql); diff --git a/src/main/java/teachingtutorials/tutorials/LocationStep.java b/src/main/java/teachingtutorials/tutorials/LocationStep.java new file mode 100644 index 0000000..ab64f94 --- /dev/null +++ b/src/main/java/teachingtutorials/tutorials/LocationStep.java @@ -0,0 +1,323 @@ +package teachingtutorials.tutorials; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import teachingtutorials.TeachingTutorials; +import teachingtutorials.fundamentalTasks.GeometricUtils; +import teachingtutorials.utils.Display; +import teachingtutorials.utils.Hologram; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * Holds step data specific to a location and contains some procedures related to utilising this data + */ +public class LocationStep// extend step? +{ + //Data stored in the LocationSteps table in the DB + private int iLocationID; + private int iStepID; + + private double dStartLatitude; + private double dStartLongitude; + private float fStartYaw; + private float fStartPitch; + + private String szInstructions; + private double dHologramLocationX; + private double dHologramLocationY; + private double dHologramLocationZ; + private Hologram instructions; + + private boolean bLocationSet; + private boolean bInstructionsSet; + private boolean bHologramLocationSet; + + public LocationStep(int iLocationID, int iStepID, boolean bHologramNeeded) + { + this.iLocationID = iLocationID; + this.iStepID = iStepID; + this.szInstructions = ""; + + bLocationSet = false; + bInstructionsSet = false; + bHologramLocationSet = !bHologramNeeded; + + if (bHologramLocationSet) + Bukkit.getConsoleSender().sendMessage("Hologram location is set because no hologram is needed"); + //If hologram needed then we set this to false as the location is not set yet + //If a hologram is not needed then we set this to true, indicating that this does not need to be done + } + + public boolean isOtherInformationSet() + { + if (bLocationSet) + Bukkit.getConsoleSender().sendMessage("Location is set"); + if (bInstructionsSet) + Bukkit.getConsoleSender().sendMessage("Instruction is set"); + if (bHologramLocationSet) + Bukkit.getConsoleSender().sendMessage("Hologram location is set"); + + boolean bAllExtraInformationIsSet = (bLocationSet && bInstructionsSet) && bHologramLocationSet; + if (bAllExtraInformationIsSet) + Bukkit.getConsoleSender().sendMessage("All extra information is set"); + + return bAllExtraInformationIsSet; + } + + //------------------------------------------------ + //--------------------Database-------------------- + //------------------------------------------------ + + /** + * //Accesses the DB and fetches the information about the step location + * @param iStepID The step ID of the step + * @param iLocationID The location that is being played + * @return + */ + public static LocationStep getFromStepAndLocation(int iStepID, int iLocationID, boolean bHologramNeeded) + { + LocationStep locationStep = new LocationStep(iLocationID, iStepID, bHologramNeeded); + + String sql; + Statement SQL = null; + ResultSet resultSet = null; + + try + { + //Compiles the command to fetch the location step + sql = "Select * FROM LocationSteps WHERE Step = "+iStepID +" AND Location = " +iLocationID; + SQL = TeachingTutorials.getInstance().getConnection().createStatement(); + + //Executes the query + resultSet = SQL.executeQuery(sql); + if (resultSet.next()) + { + //Extracts and stores the data + locationStep.dStartLatitude = resultSet.getDouble("Latitude"); + locationStep.dStartLongitude = resultSet.getDouble("Longitude"); + locationStep.fStartYaw = resultSet.getFloat("StartYaw"); + locationStep.fStartPitch = resultSet.getFloat("StartPitch"); + locationStep.szInstructions = resultSet.getString("Instructions"); + locationStep.dHologramLocationX = resultSet.getDouble("InstructionsX"); + locationStep.dHologramLocationY = resultSet.getDouble("InstructionsY"); + locationStep.dHologramLocationZ = resultSet.getDouble("InstructionsZ"); + } + } + catch(SQLException se) + { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[TeachingTutorials] - SQL - SQL Error fetching Steps by StageID"); + se.printStackTrace(); + } + catch (Exception e) + { + e.printStackTrace(); + } + return locationStep; + } + + /** + * Adds the location step to the DB + */ + public boolean storeDetailsInDB() + { + String sql; + Statement SQL = null; + ResultSet resultSet = null; + + int iCount; + + try + { + SQL = TeachingTutorials.getInstance().getConnection().createStatement(); + sql = "INSERT INTO LocationSteps (Location, Step, Latitude, Longitude, StartYaw, StartPitch, Instructions, InstructionsX, InstructionsY, InstructionsZ) VALUES (" + + iLocationID +", " + + iStepID +", " + + dStartLatitude +", " + + dStartLongitude +", " + + fStartYaw +", " + + fStartPitch +", '" + + szInstructions +"', " + + dHologramLocationX +", " + + dHologramLocationY +", " + + dHologramLocationZ + +")"; + Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +sql); + iCount = SQL.executeUpdate(sql); + + if (iCount != 1) + { + return false; + } + return true; + } + catch (SQLException se) + { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[TeachingTutorials] - SQL - SQL Error adding new location step"); + se.printStackTrace(); + return false; + } + catch (Exception e) + { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[TeachingTutorials] - SQL - Other error adding new location step"); + e.printStackTrace(); + return false; + } + } + + //----------------------------------------------- + //---------------------Utils--------------------- + //----------------------------------------------- + + /** + * Teleports the player to the start of the step + * @param player The player to teleport + * @param world The world for the relevant location + * @return The start location of the step + */ + public Location teleportPlayerToStartOfStep(Player player, World world, TeachingTutorials plugin) + { + Location location = getStartLocation(world); + if (location != null) + { + //Teleports the player + Location finalLocation = location; + Bukkit.getScheduler().runTask(plugin, () -> player.teleport(finalLocation)); + } + else + { + location = player.getLocation(); + player.sendMessage(ChatColor.RED +"No start location for this step has been set yet"); + } + + return location; + } + + /** + * Sets the step start location + * @param location The location of the intended step start location + */ + public void setStartLocation(Location location) + { + double[] longLat = GeometricUtils.convertToGeometricCoordinates(location.getX(), location.getZ()); + + if (longLat != null) + { + this.dStartLongitude = longLat[0]; + this.dStartLatitude = longLat[1]; + + this.fStartPitch = location.getPitch(); + this.fStartYaw = location.getYaw(); + + bLocationSet = true; + } + else + { + + } + } + + /** + * + * @return The start location for the step as a bukkit object + */ + private Location getStartLocation(World world) + { + Location location = GeometricUtils.convertToBukkitLocation(world, dStartLatitude, dStartLongitude); + + if (location != null) + { + location.setY(location.getY() + 1); + location.setYaw(fStartYaw); + location.setPitch(fStartPitch); + } + return location; + } + + /** + * Displays the instructions to the player + * @param displayType The way the instruction should be displayed + * @param player The player to which the instruction should be displayed + */ + public void displayInstructions(Display.DisplayType displayType, Player player, String szStepName, World world) + { + Display display; + + switch (displayType) + { + case hologram: + display = new Display(player, this.szInstructions); + instructions = display.Hologram(ChatColor.AQUA +"" +ChatColor.UNDERLINE +ChatColor.BOLD +szStepName, getHologramLocation(world)); + break; + default: + display = new Display(player, this.szInstructions); + display.Message(); + break; + } + } + + /** + * Removes the hologram from view if it is displayed + */ + public void removeInstructionsHologram() + { + if (instructions != null) + instructions.removeHologram(); + } + + /** + * Sets the location of the instructions hologram and displays the instructions to the creator + * @param player The player to which the location must be set to + * @param szStepName The name of the step, so that the instructions can then be displayed + */ + public void setHologramLocationToThatOfPlayer(Player player, String szStepName) + { + //Sets the location + Location playerLocation = player.getLocation(); + this.dHologramLocationX = playerLocation.getX(); + this.dHologramLocationY = playerLocation.getY(); + this.dHologramLocationZ = playerLocation.getZ(); + + //Displays the instructions + removeInstructionsHologram(); + displayInstructions(Display.DisplayType.hologram, player, szStepName, player.getWorld()); + + this.bHologramLocationSet = true; + } + + /** + * + * @return The instructions' hologram location for the step as a bukkit object + */ + private Location getHologramLocation(World world) + { + Location hologramLocation = new Location(world, dHologramLocationX, dHologramLocationY, dHologramLocationZ); + return hologramLocation; + } + + /** + * Sets the instructions of the step and displays the instructions + * @param szInstructions The desired instructions + * @param displayType The display type, so the instructions can be displayed + * @param player The player, so the instructions can be displayed + * @param szStepName The player, so the instructions can be displayed + */ + public void setInstruction(String szInstructions, Display.DisplayType displayType, Player player, String szStepName) + { + //Sets the instructions + this.szInstructions = szInstructions; + + //Displays the instructions + removeInstructionsHologram(); + displayInstructions(displayType, player, szStepName, player.getWorld()); + + //Instructions may be blank at this point, but this is fine and is displayed blank on the hologram + + this.bInstructionsSet = true; + } +} diff --git a/src/main/java/teachingtutorials/tutorials/Step.java b/src/main/java/teachingtutorials/tutorials/Step.java index ddc9c21..a12528c 100644 --- a/src/main/java/teachingtutorials/tutorials/Step.java +++ b/src/main/java/teachingtutorials/tutorials/Step.java @@ -1,13 +1,16 @@ package teachingtutorials.tutorials; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.Player; import teachingtutorials.TeachingTutorials; import teachingtutorials.fundamentalTasks.TpllListener; +import teachingtutorials.guis.locationcreatemenus.StepEditorMenu; import teachingtutorials.utils.Display; -import teachingtutorials.utils.Hologram; +import teachingtutorials.utils.User; import java.sql.ResultSet; import java.sql.SQLException; @@ -17,20 +20,25 @@ public class Step { private String szName; - private String szStepInstructions; - private String szInstructionDisplayType; - private Hologram instructions; + private Display.DisplayType instructionDisplayType; private Player player; private TeachingTutorials plugin; public Stage parentStage; + + /** + * Notes whether all tasks have been completed/set or not + */ public boolean bStepFinished; protected int iStepID; protected int iStepInStage; + //Stores the location specific step data + private LocationStep locationStep; + private int iGroupInStepLocationCreation; private Group currentGroup; - //Handle multiple tasks being registered and the way they depend on ecahother + //Handle multiple tasks being registered and the way they depend on each other private boolean selectionCompleteHold; public ArrayList handledTpllListeners = new ArrayList<>(); public boolean bTpllDistanceMessageQueued; @@ -40,8 +48,10 @@ public class Step //Tasks in groups are completed synchronously public ArrayList groups = new ArrayList<>(); - //Used for creating a step in a lesson - public Step(int iStepID, int iStepInStage, String szStepName, Player player, TeachingTutorials plugin, Stage parentStage, String szStepInstructions, String szInstructionDisplayType) + private StepEditorMenu menu; + + //Used for creating a step for a lesson + public Step(int iStepID, int iStepInStage, String szStepName, Player player, TeachingTutorials plugin, Stage parentStage, String szInstructionDisplayType) { this.player = player; this.plugin = plugin; @@ -50,17 +60,22 @@ public Step(int iStepID, int iStepInStage, String szStepName, Player player, Tea this.iStepID = iStepID; this.iStepInStage = iStepInStage; this.szName = szStepName; - this.szStepInstructions = szStepInstructions; - this.szInstructionDisplayType = szInstructionDisplayType; + setInstructionDisplayType(szInstructionDisplayType); this.selectionCompleteHold = false; + + if (parentStage.bLocationCreation) + //Initialises location step + this.locationStep = new LocationStep(parentStage.getLocationID(), iStepID, getInstructionDisplayType().equals(Display.DisplayType.hologram)); + else + //Gets the location specific data + this.locationStep = LocationStep.getFromStepAndLocation(this.iStepID, this.parentStage.tutorialPlaythrough.getLocation().getLocationID(), getInstructionDisplayType().equals(Display.DisplayType.hologram)); } //Used for adding a step to the DB - public Step(String szName, String szInstructionDisplayType, String szInstructions) + public Step(String szName, String szInstructionDisplayType) { this.szName = szName; - this.szStepInstructions = szInstructions; - this.szInstructionDisplayType = szInstructionDisplayType; + setInstructionDisplayType(szInstructionDisplayType); this.selectionCompleteHold = false; } @@ -69,14 +84,23 @@ public String getName() { return szName; } - public String getInstructions() + + public void setInstructionDisplayType(String szInstructionDisplayType) { - return szStepInstructions; + Display.DisplayType displayType; + try { + displayType = Display.DisplayType.valueOf(szInstructionDisplayType); + } + catch (IllegalArgumentException e) { + Bukkit.getConsoleSender().sendMessage("The step instruction display type was not properly specified ("+szInstructionDisplayType +"), reverting to chat"); + displayType = Display.DisplayType.chat; + } + this.instructionDisplayType = displayType; } - public String getInstructionDisplayType() + public Display.DisplayType getInstructionDisplayType() { - return szInstructionDisplayType; + return this.instructionDisplayType; } public boolean getSelectionCompleteHold() @@ -106,13 +130,13 @@ public void holdSelectionComplete() selectionCompleteHold = true; //Changes the hold back to false in 0.5 seconds - this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { + this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() + { public void run() { selectionCompleteHold = false; } }, 10L); - } public void calculateNearestTpllPointAfterWait() @@ -161,6 +185,10 @@ public void run() }, 2L); } + /** + * Starts the player on this step. Sends them the title of the step, registers the fall listener, + * teleports them to the start, displays the instructions and initialises the groups of tasks + */ public void startStep() { //Display step title @@ -182,44 +210,12 @@ public void run() { display.Title(ChatColor.AQUA +"Step " +iStepInStage +" - " +szName, 10, 60, 12); } - //TP to location? - - //Displays the step instructions - Location instructionLocation; - if (iStepInStage == 1 && parentStage.isFirstStage()) - { - instructionLocation = parentStage.tutorialPlaythrough.getLocation().calculateBukkitStartLocation(); - } - else - instructionLocation = player.getLocation(); - - switch (szInstructionDisplayType) - { - case "hologram": - display = new Display(player, szStepInstructions); - instructions = display.Hologram(ChatColor.AQUA +"" +ChatColor.UNDERLINE +ChatColor.BOLD +szName, instructionLocation); - break; - case "chat": - default: - display = new Display(player, szStepInstructions); - display.Message(); - break; - } - //Fetches the details of groups and stores them in memory fetchAndInitialiseGroups(); Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] " +groups.size() +" groups fetched"); - //If a location is being created, groups are made synchronous rather than asynchronous - if (parentStage.bLocationCreation) - { - //Register the start of the first group - currentGroup = groups.get(0); - iGroupInStepLocationCreation = 1; - currentGroup.initialRegister(); - Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Registered group "+iGroupInStepLocationCreation +" of step"); - } - else + //Player is a student doing a tutorial + if (!parentStage.bLocationCreation) { //Register the start of all groups int i; @@ -230,6 +226,33 @@ public void run() { groups.get(i).initialRegister(); Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Registered group "+(i+1)); } + + //TP to start location, and store this location for later use + Location startLocation = locationStep.teleportPlayerToStartOfStep(player, parentStage.tutorialPlaythrough.getLocation().getWorld(), plugin); + + //Updates the fall listener + parentStage.tutorialPlaythrough.setFallListenerSafeLocation(startLocation); + + //Displays the step instructions + this.locationStep.displayInstructions(getInstructionDisplayType(), player, szName, parentStage.tutorialPlaythrough.getLocation().getWorld()); + } + + //Player is a creator creating a new location for a tutorial + else + { + //Register the start of the first group + //If a location is being created, groups are made synchronous rather than asynchronous + currentGroup = groups.get(0); + iGroupInStepLocationCreation = 1; + currentGroup.initialRegister(); + Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Registered group "+iGroupInStepLocationCreation +" of step"); + + //Creates the menu, assigns it to the user + User user = parentStage.tutorialPlaythrough.getCreatorOrStudent(); + menu = new StepEditorMenu(plugin, user, this, this.locationStep); + if (user.mainGui != null) + user.mainGui.delete(); + user.mainGui = menu; } } @@ -247,10 +270,6 @@ protected void groupFinished() if (iGroupInStepLocationCreation == groups.size()) //If the current group is the last group { bAllGroupsFinished = true; - - //Remove hologram - if (szInstructionDisplayType.equals("hologram")) - instructions.removeHologram(); } else { @@ -277,27 +296,97 @@ protected void groupFinished() if (bAllGroupsFinished == true) { - //Remove hologram - if (szInstructionDisplayType.equals("hologram")) - instructions.removeHologram(); - + //Marks the step's tasks as all finished this.bStepFinished = true; - parentStage.nextStep(); + + //Player has just finished setting the answers for this step + if (parentStage.bLocationCreation) + { + //Checks whether the additional information is set - start location and instructions etc + if (locationStep.isOtherInformationSet()) + tryNextStep(); + else + { + Display display = new Display(player, Component.text("You must now set the step's start location and instructions. Use the learning menu", NamedTextColor.RED)); + display.Message(); + + //Sets the player's menu as the step editor menu + this.parentStage.tutorialPlaythrough.getCreatorOrStudent().mainGui = menu; + + //Opens the step editor menu + menu.open(this.parentStage.tutorialPlaythrough.getCreatorOrStudent()); + + //We wait and then perform the code in the if statement above once the location has been set, via tryNextStep() + } + } + else + { + //Remove hologram + if (getInstructionDisplayType().equals(Display.DisplayType.hologram)) + locationStep.removeInstructionsHologram(); + parentStage.nextStep(); + } + } + } + + /** + * Will move the player on to the next step if the current step is finished - answers AND additional information set + *

+ *

This method has two uses: it is called directly after any additional step information is set. + * It is called when the answers have just finished being set. + *

+ */ + public void tryNextStep() + { + //Blocks any processes occurring if the method has wrongly been called from outside of location creation + if (!parentStage.bLocationCreation) + return; + + if (bStepFinished) + { + if (locationStep.isOtherInformationSet()) + { + //Remove hologram + if (getInstructionDisplayType().equals(Display.DisplayType.hologram)) + locationStep.removeInstructionsHologram(); + + //Deletes menu + menu.delete(); + menu = null; + + locationStep.storeDetailsInDB(); + parentStage.nextStep(); + } + else + { + Display display = new Display(player, ChatColor.GREEN +"Continue to set the additional information, use the learning menu"); + display.Message(); + } + } + else + { + Display display = new Display(player, ChatColor.GREEN +"Continue to set the answers"); + display.Message(); } } public void terminateEarly() { //Remove holograms - if (szInstructionDisplayType.equals("hologram")) - instructions.removeHologram(); + if (getInstructionDisplayType().equals(Display.DisplayType.hologram)) + this.locationStep.removeInstructionsHologram(); + //Unregisters the current task listener if (parentStage.bLocationCreation) { currentGroup.terminateEarly(); + menu.delete(); + menu = null; + Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +" [TeachingTutorials] Unregistered group "+iGroupInStepLocationCreation); } + //Unregisters the task listeners else { int i; @@ -329,7 +418,7 @@ public static ArrayList fetchStepsByStageID(Player player, TeachingTutoria resultSet = SQL.executeQuery(sql); while (resultSet.next()) { - Step step = new Step(resultSet.getInt("StepID"), resultSet.getInt("StepInStage"), resultSet.getString("StepName") ,player, plugin, stage, resultSet.getString("StepInstructions"), resultSet.getString("InstructionDisplay")); + Step step = new Step(resultSet.getInt("StepID"), resultSet.getInt("StepInStage"), resultSet.getString("StepName") ,player, plugin, stage, resultSet.getString("InstructionDisplay")); steps.add(step); } } @@ -344,6 +433,4 @@ public static ArrayList fetchStepsByStageID(Player player, TeachingTutoria } return steps; } -} - - +} \ No newline at end of file diff --git a/src/main/java/teachingtutorials/utils/Display.java b/src/main/java/teachingtutorials/utils/Display.java index 06c7fb0..770f476 100644 --- a/src/main/java/teachingtutorials/utils/Display.java +++ b/src/main/java/teachingtutorials/utils/Display.java @@ -50,4 +50,9 @@ public Hologram Hologram(String szTitle, Location location) Hologram hologram = new Hologram(location, player, szTitle, szText); return hologram; } + + public enum DisplayType + { + hologram, chat, action_bar + } } diff --git a/src/main/java/teachingtutorials/utils/Hologram.java b/src/main/java/teachingtutorials/utils/Hologram.java index 2640d21..49fb3c0 100644 --- a/src/main/java/teachingtutorials/utils/Hologram.java +++ b/src/main/java/teachingtutorials/utils/Hologram.java @@ -1,7 +1,6 @@ package teachingtutorials.utils; import me.filoghost.holographicdisplays.api.HolographicDisplaysAPI; -import me.filoghost.holographicdisplays.api.Position; import me.filoghost.holographicdisplays.api.hologram.VisibilitySettings; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -16,98 +15,129 @@ public class Hologram public Hologram(Location location, Player player, String szTitle, String szText) { //Performs the hologram creation synchronously - Bukkit.getScheduler().runTask(TeachingTutorials.getInstance(), new Runnable() - { - @Override - public void run() - { - double[] xzAddition; - float fYaw = player.getLocation().getYaw(); + Bukkit.getScheduler().runTask(TeachingTutorials.getInstance(), () -> { + //Creates the hologram + hologram = api.createHologram(location); - //Calculates where to move the hologram to based on the player's location - if (fYaw < -135 || fYaw > 135) - { - xzAddition = new double[]{0, -4.5}; - } - else if (fYaw < -45) - { - xzAddition = new double[]{4.5, 0}; - } - else if (fYaw > 45) - { - xzAddition = new double[]{-4.5, 0}; - } - else - { - xzAddition = new double[]{0, 4.5}; - } + //Inserts the title + hologram.getLines().appendText(szTitle); + String[] szWords = szText.split(" "); - //Moves the hologram - location.set(location.getX() +xzAddition[0], location.getY(), location.getZ() +xzAddition[1]); + //At the start of the for loop, represents the current line being compiled before + // the current word has been added + String szLine = ""; - //Raises or lowers the hologram - int iHeight = location.getWorld().getHighestBlockYAt(location.getBlockX(), location.getBlockZ()); - location.set(location.getX(), iHeight + 3.1, location.getZ()); + //Represents the current line after the current word has been added + String szLineNew; - //Creates the hologram - hologram = api.createHologram(location); + //Represents the current line after the current word has been added + // but also after the text has been stripped of colour codes + String szDisplayedText; - Position position = hologram.getPosition(); + //The maximum width a hologram line can be + final int iMax_Width = TeachingTutorials.getInstance().getConfig().getInt("Hologram_Max_Width"); - //Inserts the text - hologram.getLines().appendText(szTitle); - String[] szWords = szText.split(" "); + boolean bCreateNewLineAfter; + bCreateNewLineAfter = false; - String szLine = ""; - String szLineNew; - String szDisplayedText; + //Used when a new line is manually specified and the start of the next line needs to be stored to added to the szLine at the end of the loop after the new line is added + String szStartOfNextLine = ""; - for (int iWord = 0; iWord < szWords.length ; iWord++) + //Goes through each word in the text + for (int iWord = 0; iWord < szWords.length ; iWord++) + { + //TODO: what if two line seperators together or in one word? + //-Expand algorithm time + //Checks to see if the word contains a new line separator + if (szWords[iWord].contains(System.lineSeparator())) { - szLineNew = szLine + szWords[iWord] +" "; - szDisplayedText = szLineNew.replace("&[A-Fa-f0-9]", ""); - if (szDisplayedText.length() > TeachingTutorials.getInstance().getConfig().getInt("Hologram_Max_Width") + 1) //Line is Hologram_Max_Width without the space + int iIndexOfLine = szWords[iWord].indexOf(System.lineSeparator()); + if (iIndexOfLine == 0) { - //Indicates that the line just added had one, >40 characters long word, so must display on a new line - if (szLine.equals("")) - { - //Adds the line to the hologram, removing the trailing space - hologram.getLines().appendText(szLineNew.substring(0, szLineNew.length() - 1)); - } - else //Indicates that the line already had some words in it so display those - { - //Adds the line to the hologram, removing the trailing space - hologram.getLines().appendText(szLine.substring(0, szLine.length() - 1)); - } - szLine = szWords[iWord] +" "; - if (iWord == szWords.length - 1) - { - hologram.getLines().appendText(szWords[iWord]); - } + hologram.getLines().appendText(szLine); + szLine = ""; } - else if (iWord == szWords.length - 1) + else if (iIndexOfLine == (szWords[iWord].length() - 1)) { - hologram.getLines().appendText(szLineNew); + bCreateNewLineAfter = true; } else { - szLine = szLineNew; + bCreateNewLineAfter = true; + String[] twoWords = szWords[iWord].split(System.lineSeparator()); + szWords[iWord] = twoWords[0]; + szStartOfNextLine = twoWords[1]; } } - Bukkit.getConsoleSender().sendMessage(hologram.getLines().size() +""); - //Shifts the hologram up if it is too tall - if (hologram.getLines().size() > 7) + //Adds the word to the new line being compiled + szLineNew = szLine + szWords[iWord].replaceFirst(System.lineSeparator(), ""); + + //Strips the text of colour codes so that the length can be accurately measured + szDisplayedText = szLineNew.replace("&[A-Fa-f0-9]", ""); + + //Checks to see whether the new line exceeds the maximum width + if (szDisplayedText.length() > iMax_Width) //Line is Hologram_Max_Width without the space { - position = position.add(0, 0.2 * (hologram.getLines().size() - 7) , 0); - hologram.setPosition(position); + //If the new line is too big, needs to deal with it + + //Unless the new line is purely one word (aka the old one was blank) + //How does the old one get blank? - if the same thing happened previously, see below + + //Indicates that the previous line had one > Max_Width characters long word, + // so the new word must display on a new line + if (szLine == "") + //szLine remains as "" + hologram.getLines().appendText(szLineNew); + + //Indicates that the line already had some words in it so display those + //Adding the new one to it takes it over the maximum + else + { + //Adds the previous line to the hologram, removing the trailing space + hologram.getLines().appendText(szLine.substring(0, szLine.length() - 1)); + + //Adds the new line if it is over max characters long + if (szWords[iWord].replace("&[A-Fa-f0-9]", "").length() > iMax_Width) + { + hologram.getLines().appendText(szWords[iWord]); + szLine = ""; + } + + //If this is the last word, can immediately append it on a new line + else if (iWord == szWords.length - 1) + hologram.getLines().appendText(szWords[iWord]); + + else + //Sends the line with the new word just added into the next loop, adds the space + szLine = szWords[iWord] + " "; + } } - //Sets the visibility - VisibilitySettings visibilitySettings = hologram.getVisibilitySettings(); - visibilitySettings.setGlobalVisibility(VisibilitySettings.Visibility.HIDDEN); - visibilitySettings.setIndividualVisibility(player, VisibilitySettings.Visibility.VISIBLE); + //If this is the last worst, but the length didn't max out, we can append the new line + else if (bCreateNewLineAfter) + { + hologram.getLines().appendText(szLineNew); + szLine = szStartOfNextLine + " "; + } + else if (iWord == szWords.length - 1) + { + hologram.getLines().appendText(szLineNew); + } + else + { + //Sends the line with the new word just added into the next loop, adds the space + szLine = szLineNew + " "; + } + + bCreateNewLineAfter = false; + szStartOfNextLine = ""; } + + //Sets the visibility + VisibilitySettings visibilitySettings = hologram.getVisibilitySettings(); + visibilitySettings.setGlobalVisibility(VisibilitySettings.Visibility.HIDDEN); + visibilitySettings.setIndividualVisibility(player, VisibilitySettings.Visibility.VISIBLE); }); } diff --git a/src/main/java/teachingtutorials/utils/Utils.java b/src/main/java/teachingtutorials/utils/Utils.java index f33a29f..1d57c08 100644 --- a/src/main/java/teachingtutorials/utils/Utils.java +++ b/src/main/java/teachingtutorials/utils/Utils.java @@ -5,6 +5,7 @@ import java.util.List; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.FireworkEffect; @@ -88,4 +89,70 @@ public static int getHighestYAt(World w, int x, int z) { } return 0; } -} \ No newline at end of file + + //Gives a player an item, it will be set in their main hand, if it does not already exist there. + + //If the main hand is empty, set it there. + //If then main hand is slot 8 and includes the navigator, find the first empty slot available and set it there. + //If no empty slots are available set it to slot 7. + //If the main hand has an item swap the current item to an empty slot in the inventory. + //If no empty slots are available overwrite it. + + public static void giveItem(Player p, ItemStack item, String name) { + int emptySlot = getEmptyHotbarSlot(p); + + boolean hasItemAlready = p.getInventory().containsAtLeast(item, 1); + + //If we already have the item switch to current slot. + if (hasItemAlready) + { + //Switch item to current slot. + int slot = p.getInventory().first(item); + + p.getInventory().setItem(slot, p.getInventory().getItemInMainHand()); + p.getInventory().setItemInMainHand(item); + p.sendMessage(Component.text("Set ", NamedTextColor.GREEN).append(Component.text(name, NamedTextColor.DARK_AQUA).append(Component.text(" to main hand.", NamedTextColor.GREEN)))); + } + else if (emptySlot >= 0) + { + //The current slot is empty. This also implies no navigator, and thus the item does not yet exist in the inventory. + //Set item to empty slot. + p.getInventory().setItem(emptySlot, item); + p.sendMessage(Component.text("Set ", NamedTextColor.GREEN).append(Component.text(name, NamedTextColor.DARK_AQUA).append(Component.text(" to slot " + (emptySlot + 1), NamedTextColor.GREEN)))); + + } + else + { + //Player has no empty slots and is holding the navigator and learning menu, set to item to slot 6. + p.getInventory().setItem(6, item); + p.sendMessage(Component.text("Set ", NamedTextColor.GREEN).append(Component.text(name, NamedTextColor.DARK_AQUA).append(Component.text(" to slot 8", NamedTextColor.GREEN)))); + + } + } + + //Return an empty hotbar slot, if no empty slot exists return -1. + public static int getEmptyHotbarSlot(Player p) { + + //If main hand is empty return that slot. + ItemStack heldItem = p.getInventory().getItemInMainHand(); + if (heldItem.getType() == Material.AIR) { + return p.getInventory().getHeldItemSlot(); + } + + //Check if hotbar has an empty slot. + for (int i = 0; i < 9; i++) { + + ItemStack item = p.getInventory().getItem(i); + + if (item == null) { + return i; + } + if (item.getType() == Material.AIR) { + return i; + } + } + + //No slot could be found, return -1. + return -1; + } +}