diff --git a/src/1.12_material_lists.yml b/src/1.12_material_lists.yml deleted file mode 100644 index 050589f..0000000 --- a/src/1.12_material_lists.yml +++ /dev/null @@ -1,63 +0,0 @@ -not-solid-materials: -- LEAVES -- BED_BLOCK -- CHEST -- SIGN_POST -- WOODEN_DOOR -- WALL_SIGN -- STONE_PLATE -- IRON_DOOR_BLOCK -- WOOD_PLATE -- CACTUS -- FENCE -- CAKE_BLOCK -- TRAP_DOOR -- IRON_FENCE -- FENCE_GATE -- NETHER_FENCE -- BREWING_STAND -- DRAGON_EGG -- ENDER_CHEST -- COBBLE_WALL -- ANVIL -- TRAPPED_CHEST -- GOLD_PLATE -- IRON_PLATE -- LEAVES_2 -- IRON_TRAPDOOR -- STANDING_BANNER -- WALL_BANNER -- SPRUCE_FENCE_GATE -- BIRCH_FENCE_GATE -- JUNGLE_FENCE_GATE -- DARK_OAK_FENCE_GATE -- ACACIA_FENCE_GATE -- SPRUCE_FENCE -- BIRCH_FENCE -- JUNGLE_FENCE -- DARK_OAK_FENCE -- ACACIA_FENCE -- SPRUCE_DOOR -- BIRCH_DOOR -- JUNGLE_DOOR -- ACACIA_DOOR -- DARK_OAK_DOOR -replaceable-solid-materials: -- FENCE -- CAKE_BLOCK -- IRON_FENCE -- FENCE_GATE -- NETHER_FENCE -- COBBLE_WALL -- GOLD_PLATE -- IRON_PLATE -- SPRUCE_FENCE_GATE -- BIRCH_FENCE_GATE -- JUNGLE_FENCE_GATE -- DARK_OAK_FENCE_GATE -- ACACIA_FENCE_GATE -- SPRUCE_FENCE -- BIRCH_FENCE -- JUNGLE_FENCE -- DARK_OAK_FENCE -- ACACIA_FENCE \ No newline at end of file diff --git a/src/config.yml b/src/config.yml index e9f54d5..56de0c2 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,6 +1 @@ -language: english -wand-item: gold_spade -maze: - maximum-pathwidth: 50 - maximum-wallwidth: 50 - maximum-wallheight: 100 \ No newline at end of file +wand-item: golden_shovel \ No newline at end of file diff --git a/src/english.yml b/src/english.yml deleted file mode 100644 index 29e9171..0000000 --- a/src/english.yml +++ /dev/null @@ -1,33 +0,0 @@ -help-pages: - wand-command: This command gives you a mighty maze wand. Use it considerately! Click two blocks and a clipboard will appear with the equipped shape (rectangle or circle). By clicking and dragging a blue corner you can resize your clipboard. For starting over just click any other two blocks. - start-command: 'With this command you transform your clipboard into the floor plan of a maze. \n\nYou can add or cut away other clipboards from your floor plan with:' - discard-command: Discards your floor plan and your clipboard. - select-command: 'Lets you choose between different tools to edit floor plan of your maze. Following tools can be selected:' - tools: - rectangle: Your clipboards created with a wand will form rectangles. - circle: Your clipboards will form circles. - brush: Left click on the outline of your floor plan to reduce it at that block. Right click on the outline to expand it at that block. - exit: Click on the outline of your floor plan to set exits (or entrances, just how you see it). Click on an exit a second time to delete it again. The diamond exit indicates where the maze generator will begin building. - add-cut-command: 'Adds or cuts away your clipboard from your floor plan. This only works if the clipboard is touching your maze. If you cut off an area from the main part of your maze (with diamond exit) there won''t be generated any paths (just don''t). \n\nFor undoing these actions use:' - undo-command: Undoes the last change to your maze like adding or cutting a clipboar away or brushing. - pathwidth-wallwidth-wallheight-command: These three commands are for changing the width of maze paths and walls as well as the wall height for the generation in the end. - build-command: 'Builds your maze out of a mixture of blocks you enter. Just type in the name of each block (and &2":" &a+ &2a number &aif necessary), for example:\n &2"/maze build quartz_block:1" &a(that''s chiseled quartz) \nA constructed maze cannot be edited any further.' - teleport-command: Teleports you back to your maze (if you have the permission for that). -messages: - tool-switched: Switched tool to %tool%. - tool-for-floor-plan-only: This tool can only be used for a floor plan of a maze. - maze-pathwidth-changed: Path width set to %number% blocks. - maze-wallwidth-changed: Wall width set to %number% blocks. - maze-wallheight-changed: Wall height set to %number% blocks. - maze-building-started: Started building your maze. -errors: - insufficient-permission: You do not have the permission for this command. - clipboard-not-started: Please select an area with a maze wand first. - clipboard-not-finished: Please finish your clipboard first. - maze-not-started: Please start a maze first. - clipboard-not-touching-maze: Your clipboard does not seem to touch your maze. - no-maze-border-clicked: This block is not the border of your maze... - no-maze-exit-set: Please mark an exit at the border of your maze first. - no-build-blocks-specified: Please specify a block(s) from which your maze will be built. - argument-not-matching-block: '%block% is not a block name.' - number-not-valid: '%number% is not a valid number.' \ No newline at end of file diff --git a/src/language.yml b/src/language.yml new file mode 100644 index 0000000..ae1b57c --- /dev/null +++ b/src/language.yml @@ -0,0 +1,39 @@ +help-pages: + wand-command: 'This command gives you the most legendary tool ever sighted (by me): The Maze Wand! \n\nClick two blocks on the ground to create clipboard (that''s a rectangle or circle). Click and drag a blue corner of the clipboard to resize it. This clipboard can be converted to a maze floor with /tangledmaze start.' + start-command: Converts your clipboard into the floor plan of a maze. This floor plan can now be edited by adding/cutting away other clipboards from it (/tangledmaze add/cut) or with the brush tool (/tangledmaze select brush). + discard-command: Discards your floor plan and your clipboard. + select-command: 'Lets you choose between different tools to edit floor plan of your maze. Following tools can be selected:' + tools: + rectangle: The shape of your clipboards will form rectangles. + circle: Your clipboards will form circles. + brush: Left click on the outline of your floor plan to reduce it at that block. Right click on the outline to expand it at that block. + exit: Sets exits (or entrances) for your maze. Click on the outline of your floor plan to set an exit, click it a second time to delete it again. The diamond exit shows where maze generator will start making paths from. + add-cut-command: 'Adds or cuts away your clipboard from your floor plan. This only works if the clipboard is touching your maze. In areas cut off from the main part of your maze with the diamond exit there won''t be generated any paths (just don''t).' + undo-command: Undoes the last change to your maze like adding or cutting a clipboard away or usage of the brush tool. + pathwidth-wallwidth-wallheight-command: These three commands are for changing the width of maze paths and walls as well as the wall height for the generation in the end. + pathlength-command: This command affects for how many times a path will try to expand in one direction in your maze. Depending on the size of your maze a shorter paths (1) or longer paths (10) may look more esthetic. + build-command: 'Builds your maze out of a mixture of blocks you enter. Type in the name of each block you want your maze to be built of (and &2":" &a+ &2a number &aif necessary), for example:\n &2"/maze build quartz_block:1" &a(that''s chiseled quartz).' + teleport-command: Teleports you back to your floor plan (if you have the permission for that). + unbuild-command: Unbuilds a recently generated maze (If you didn't start a new one). You then can also change it further and build it again. +messages: + plugin-reloaded: Reloaded Tangled Maze. + tool-switched: Switched tool to %tool%. + tool-for-floor-plan-only: This tool can only be used for a floor plan of a maze. + maze-pathwidth-changed: Path width set to %number% blocks. + maze-wallwidth-changed: Wall width set to %number% blocks. + maze-wallheight-changed: Wall height set to %number% blocks. + maze-pathlength-changed: Path length set to %number% blocks. + maze-building-started: Started building your maze. + maze-unbuilding-started: Started unbuilding your maze. + no-maze-to-unbuild: You have not built a maze yet that could be unbuild. +errors: + insufficient-permission: You do not have the permission for this command. + clipboard-not-started: Please select an area with a maze wand first. + clipboard-not-finished: Please finish your clipboard first. + maze-not-started: Please start a maze first. + clipboard-not-touching-maze: Your clipboard does not seem to touch your maze. + no-maze-border-clicked: This block is not the border of your maze... + no-maze-exit-set: Please mark an exit at the border of your maze first. + no-build-blocks-specified: Please specify a block(s) from which your maze will be built. + argument-not-matching-block: '%block% is not a block name.' + invalid-number: '%number% is not a valid number.' \ No newline at end of file diff --git a/src/1.13_material_lists.yml b/src/material_lists.yml similarity index 100% rename from src/1.13_material_lists.yml rename to src/material_lists.yml diff --git a/src/me/gorgeousone/tangledmaze/clip/Clip.java b/src/me/gorgeousone/tangledmaze/clip/Clip.java index 291cc44..385836f 100644 --- a/src/me/gorgeousone/tangledmaze/clip/Clip.java +++ b/src/me/gorgeousone/tangledmaze/clip/Clip.java @@ -1,207 +1,170 @@ package me.gorgeousone.tangledmaze.clip; -import java.util.Collection; import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; import java.util.TreeSet; import org.bukkit.Chunk; +import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.block.Block; -import me.gorgeousone.tangledmaze.util.MazePoint; +import me.gorgeousone.tangledmaze.util.Vec2; public class Clip { private World world; - private TreeSet fill, border; - private HashSet fillChunks, borderChunks; - - private int size, borderSize; + private Map fill; + private Set border; public Clip(World world) { this.world = world; - fill = new TreeSet<>(); + fill = new TreeMap<>(); border = new TreeSet<>(); - - fillChunks = new HashSet<>(); - borderChunks = new HashSet<>(); } public World getWorld() { return world; } - public int size() { - return size; + public Set> getFillSet() { + return fill.entrySet(); } - public int borderSize() { - return borderSize; + public Set getFill() { + return fill.keySet(); } - @SuppressWarnings("unchecked") - public HashSet getChunks() { - return (HashSet) fillChunks.clone(); + public Set getFill(Chunk chunk) { + return getLocsInChunk((TreeSet) fill.keySet(), chunk); } - - @SuppressWarnings("unchecked") - public HashSet getBorderChunks() { - return (HashSet) borderChunks.clone(); + + public void addFill(Vec2 loc, int height) { + fill.put(loc, height); } - public TreeSet getFilling() { - return fill; + public void addAllFill(Map locs) { + fill.putAll(locs); } + + public void removeFill(Vec2 loc) { - public TreeSet getBorder() { + if(fill.remove(loc) != null) + removeBorder(loc); + } + + public void removeFill(Location loc) { + removeFill(new Vec2(loc)); + } + + public Set getBorder() { return border; } + + public Set getBorder(Chunk chunk) { + return getLocsInChunk((TreeSet) getBorder(), chunk); + } + + public void addBorder(Vec2 loc) { + + if(fill.containsKey(loc)) + border.add(loc); + } - public TreeSet getFilling(Chunk chunk) { - return getPointsInChunk(fill, chunk); + public void removeBorder(Vec2 loc) { + border.remove(loc); } - public TreeSet getBorder(Chunk chunk) { - return getPointsInChunk(border, chunk); + public void removeBorder(Location loc) { + border.remove(new Vec2(loc)); } - public boolean addFilling(MazePoint point) { - - if (getWorld() != point.getWorld()) { - return false; - } - - if(fill.add(point)) { - - fillChunks.add(point.getChunk()); - size++; - return true; - } + public int size() { + return fill.size(); + } - return false; + public int borderSize() { + return border.size(); } - public boolean removeFilling(MazePoint point) { - - if(fill.remove(point)) { - - if(getFilling(point.getChunk()).isEmpty()) { - fillChunks.remove(point.getChunk()); - } - - size--; - return true; - } - - return false; + public int getHeight(Vec2 loc) { + return fill.get(loc); } - public void removeFilling(Collection points) { + public Location getLocation(Vec2 loc) { + return new Location(getWorld(), loc.getX(), getHeight(loc), loc.getZ()); + } + + public Set getBorderBlocks() { - HashSet chunks = new HashSet<>(); + Set blocks = new HashSet<>(); - for(MazePoint point : points) { - - if(fill.remove(point)) { - chunks.add(point.getChunk()); - size--; - } - } + for(Vec2 border : getBorder()) + blocks.add(new Location(getWorld(), border.getX(), getHeight(border), border.getZ())); - for(Chunk chunk : chunks) { - - if(getFilling(chunk).isEmpty()) { - fillChunks.remove(chunk); - } - } + return blocks; } - - public boolean addBorder(MazePoint point) { - if (getWorld() != point.getWorld()) { - return false; - } + public Set getBorderBlocks(Chunk chunk) { - if(border.add(point)) { - borderChunks.add(point.getChunk()); - borderSize++; - return true; - } - - return false; - } - - public boolean removeBorder(MazePoint point) { + Set blocks = new HashSet<>(); - if(border.remove(point)) { - - if(getBorder(point.getChunk()).isEmpty()) { - borderChunks.remove(point.getChunk()); - } - - borderSize--; - return true; - } + for(Vec2 border : getBorder(chunk)) + blocks.add(new Location(getWorld(), border.getX(), getHeight(border), border.getZ())); - return false; + return blocks; } - - public void removeBorder(Collection points) { + + public boolean isBorderBlock(Block block) { - HashSet chunks = new HashSet<>(); + if(block.getWorld() != getWorld()) + return false; - for(MazePoint point : points) { - - if(border.remove(point)) { - chunks.add(point.getChunk()); - size--; - } - } + Vec2 blockVec = new Vec2(block); - for(Chunk chunk : chunks) { - - if(getBorder(chunk).isEmpty()) { - fillChunks.remove(chunk); - } - } + return borderContains(blockVec) && getHeight(blockVec) == block.getY(); } + + public boolean contains(Location loc) { - public boolean contains(MazePoint point) { - - if(point.getWorld() != getWorld()) { + if(loc.getWorld() != getWorld()) return false; - } - return fill.contains(point); + return contains(new Vec2(loc)); } - public boolean borderContains(MazePoint point) { - - if(point.getWorld() != getWorld()) { - return false; - } - - return border.contains(point); + public boolean contains(Vec2 loc) { + return fill.containsKey(loc); } - private TreeSet getPointsInChunk(TreeSet set, Chunk chunk) { - - int chunkX = chunk.getX() * 16, - chunkZ = chunk.getZ() * 16, - chunkX2 = chunkX + 15, - chunkZ2 = chunkZ + 15; + public boolean borderContains(Location loc) { + return borderContains(new Vec2(loc)); + } + + public boolean borderContains(Vec2 loc) { + return border.contains(loc); + } + + private Set getLocsInChunk(TreeSet set, Chunk chunk) { + + int chunkMinX = chunk.getX() * 16, + chunkMinZ = chunk.getZ() * 16, + chunkMaxX = chunkMinX + 15, + chunkMaxZ = chunkMinZ + 15; - MazePoint - chunkStart = new MazePoint(null, chunkX, 0, chunkZ), - chunkEnd = new MazePoint(null, chunkX2, 0, chunkZ2); + Vec2 chunkStart = new Vec2(chunkMinX, chunkMinZ); + Vec2 chunkEnd = new Vec2(chunkMaxX, chunkMaxZ); - TreeSet - subSet = (TreeSet) set.subSet(chunkStart, chunkEnd), - chunkSet = new TreeSet<>(); + TreeSet subSet = (TreeSet) set.subSet(chunkStart, chunkEnd); + TreeSet chunkSet = new TreeSet<>(); - for(int iterZ = chunkZ; iterZ <= chunkZ2; iterZ++) { - + for(int iterZ = chunkMinZ; iterZ <= chunkMaxZ; iterZ++) { + chunkStart.setZ(iterZ); chunkEnd.setZ(iterZ); chunkSet.addAll(subSet.subSet(chunkStart, chunkEnd)); diff --git a/src/me/gorgeousone/tangledmaze/clip/ClipAction.java b/src/me/gorgeousone/tangledmaze/clip/ClipAction.java index 692e6c9..885cf40 100644 --- a/src/me/gorgeousone/tangledmaze/clip/ClipAction.java +++ b/src/me/gorgeousone/tangledmaze/clip/ClipAction.java @@ -1,92 +1,132 @@ package me.gorgeousone.tangledmaze.clip; import java.util.HashSet; -import java.util.TreeSet; +import java.util.Map; +import java.util.Set; -import me.gorgeousone.tangledmaze.util.MazePoint; +import org.bukkit.Location; + +import java.util.HashMap; + +import me.gorgeousone.tangledmaze.util.Vec2; public class ClipAction { - private TreeSet - addedFill, - removedFill, + private Clip clip; + + private Set addedBorder, removedBorder, removedExits; + + private Map + addedFill, + removedFill; + + public ClipAction(Clip clip) { + + this.clip = clip; + addedFill = new HashMap<>(); + removedFill = new HashMap<>(); + + addedBorder = new HashSet<>(); + removedBorder = new HashSet<>(); + removedExits = new HashSet<>(); + } - public ClipAction() { - addedFill = new TreeSet<>(); - addedBorder = new TreeSet<>(); - removedFill = new TreeSet<>(); - removedBorder = new TreeSet<>(); - removedExits = new TreeSet<>(); + public Clip getClip() { + return clip; } - public TreeSet getAddedFill() { + public Map getAddedFill() { return addedFill; } - public TreeSet getRemovedFill() { + public Map getRemovedFill() { return removedFill; } - public TreeSet getAddedBorder() { + public Set getAddedBorder() { return addedBorder; } - public TreeSet getRemovedBorder() { + public Set getRemovedBorder() { return removedBorder; } - public TreeSet getRemovedExits() { + public Set getRemovedExits() { return removedExits; } - public void addFill(MazePoint point) { - addedFill.add(point); + public void addFill(Vec2 loc, int height) { + addedFill.put(loc, height); } - public void removeFill(MazePoint point) { - removedFill.add(point); + public void removeFill(Vec2 loc, int height) { + removedFill.put(loc, height); } - public void addBorder(MazePoint point) { - addedBorder.add(point); + public void addBorder(Vec2 loc) { + addedBorder.add(loc); } - public void removeBorder(MazePoint point) { - removedBorder.add(point); + public void removeBorder(Vec2 loc) { + removedBorder.add(loc); } - public void removeExit(MazePoint point) { - removedExits.add(point); + public void removeExit(Vec2 loc) { + removedExits.add(loc); } + public Location getBorder(Vec2 loc) { + + int height; + + if(removedBorder.contains(loc)) { + + if(removedFill.containsKey(loc)) + height = removedFill.get(loc); + else + height = getClip().getHeight(loc); + + }else if(addedBorder.contains(loc)) { + + if(addedFill.containsKey(loc)) + height = addedFill.get(loc); + else + height = getClip().getHeight(loc); + + }else + return null; + + return new Location(getClip().getWorld(), loc.getX(), height, loc.getZ()); + } + public ClipAction invert() { - HashSet temporaryHolder = new HashSet<>(addedFill); + + HashMap temporaryHolder = new HashMap<>(addedFill); addedFill.clear(); - addedFill.addAll(removedFill); + addedFill.putAll(removedFill); removedFill.clear(); - removedFill.addAll(temporaryHolder); + removedFill.putAll(temporaryHolder); - temporaryHolder = new HashSet<>(addedBorder); + HashSet temporaryHolder2= new HashSet<>(addedBorder); addedBorder.clear(); addedBorder.addAll(removedBorder); removedBorder.clear(); - removedBorder.addAll(temporaryHolder); + removedBorder.addAll(temporaryHolder2); getRemovedExits().clear(); return this; } - public boolean clipWillContain(Clip clip, MazePoint point) { - return (clip.contains(point) || addedFill.contains(point)) && !removedFill.contains(point); + public boolean clipWillContain(Vec2 loc) { + return getClip().contains(loc) && !getRemovedFill().containsKey(loc) || getAddedFill().containsKey(loc); } - public boolean clipBorderWillContain(Clip clip, MazePoint point) { - return (clip.borderContains(point) || addedBorder.contains(point)) && !removedBorder.contains(point); + public boolean clipBorderWillContain(Clip clip, Vec2 loc) { + return getAddedBorder().contains(loc) || !getRemovedBorder().contains(loc) && getClip().borderContains(loc); } - } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/AddToMaze.java b/src/me/gorgeousone/tangledmaze/command/AddToMaze.java index 2b82f5f..30a601c 100644 --- a/src/me/gorgeousone/tangledmaze/command/AddToMaze.java +++ b/src/me/gorgeousone/tangledmaze/command/AddToMaze.java @@ -7,33 +7,35 @@ import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.handler.ToolHandler; import me.gorgeousone.tangledmaze.tool.ClippingTool; public class AddToMaze extends MazeCommand { public AddToMaze() { - super("add", "/maze add", 0, true, null, "merge"); + super("add", "/tangledmaze add", 0, true, null, "merge"); } @Override public boolean execute(CommandSender sender, String[] arguments) { - if(!super.execute(sender, arguments)) { + if(!super.execute(sender, arguments)) return false; - } Player player = (Player) sender; if(!MazeHandler.getMaze(player).isStarted()) { + Messages.ERROR_MAZE_NOT_STARTED.send(player); player.sendMessage("/tangledmaze start"); return false; } if(!ToolHandler.hasClipboard(player) || !ToolHandler.getClipboard(player).isStarted()) { + Messages.ERROR_CLIPBOARD_NOT_STARTED.send(player); - player.sendMessage("/tangledmaze select rectangle/ellipse"); + player.sendMessage("/tangledmaze wand"); return false; } @@ -47,16 +49,18 @@ public boolean execute(CommandSender sender, String[] arguments) { Maze maze = MazeHandler.getMaze(player); ClipAction action = maze.getAddition(clipboard.getClip()); - if(action == null) { + if(action == null) return false; - } if(action.getAddedFill().size() == clipboard.getClip().size()) { + Messages.ERROR_CLIPBOARD_NOT_TOUCHING_MAZE.send(player); return false; } - + + Renderer.hideClipboard(clipboard, true); clipboard.reset(); + maze.processAction(action, true); return true; } diff --git a/src/me/gorgeousone/tangledmaze/command/BuildMaze.java b/src/me/gorgeousone/tangledmaze/command/BuildMaze.java index ea51ec2..e808cfb 100644 --- a/src/me/gorgeousone/tangledmaze/command/BuildMaze.java +++ b/src/me/gorgeousone/tangledmaze/command/BuildMaze.java @@ -1,36 +1,40 @@ package me.gorgeousone.tangledmaze.command; import java.util.ArrayList; +import java.util.List; -import me.gorgeousone.tangledmaze.generation.MazeGenerator; +import me.gorgeousone.tangledmaze.generation.BlockGenerator; +import me.gorgeousone.tangledmaze.generation.PathGenerator; +import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.material.MaterialData; import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; import me.gorgeousone.tangledmaze.handler.ToolHandler; -import me.gorgeousone.tangledmaze.util.MaterialReader; +import me.gorgeousone.tangledmaze.util.PlaceHolder; +import me.gorgeousone.tangledmaze.util.TextException; -@SuppressWarnings("deprecation") public class BuildMaze extends MazeCommand { - private MazeGenerator generator; + private PathGenerator pathGenerator; + private BlockGenerator blockGenerator; public BuildMaze() { super("build", "/tangledmaze build ...", 1, true, null); - generator = new MazeGenerator(); + pathGenerator = new PathGenerator(); + blockGenerator = new BlockGenerator(); } @Override public boolean execute(CommandSender sender, String[] arguments) { if(!super.execute(sender, arguments)) { - return true; + return false; } Player player = (Player) sender; @@ -50,39 +54,46 @@ public boolean execute(CommandSender sender, String[] arguments) { return false; } - if(maze.getExits().isEmpty()) { + if(!maze.hasExits()) { Messages.ERROR_NO_MAZE_EXIT_SET.send(player); player.sendMessage("/tangledmaze select exit"); return false; } - ArrayList composition; + List wallMaterials; try { - composition = getWallComposition(arguments); - - } catch (Exception e) { - player.sendMessage(e.getMessage()); + wallMaterials = getWallMaterials(arguments); + + } catch (TextException ex) { + + ex.getText().send(player, ex.getPlaceHolder()); return false; } - maze.setWallComposition(composition); + maze.setWallMaterials(wallMaterials); - MazeHandler.buildMaze(maze, generator); + MazeHandler.buildMaze(maze, pathGenerator, blockGenerator); Messages.MESSAGE_MAZE_BUILDING_STARTED.send(player); ToolHandler.resetToDefaultTool(player); - MazeHandler.setMaze(player, new Maze(player)); return true; } - private static ArrayList getWallComposition(String[] serializedMaterialData) { - ArrayList composition = new ArrayList<>(); + private static List getWallMaterials(String[] serializedMaterials) throws TextException { - for(String materialData : serializedMaterialData) { - composition.add(MaterialReader.readMaterialData(materialData)); + List wallMaterials = new ArrayList<>(); + + for(String materialString : serializedMaterials) { + + Material material = Material.matchMaterial(materialString); + + if(material == null || !material.isBlock()) + throw new TextException(Messages.ERROR_NO_MATCHING_BLOCK_TYPE, new PlaceHolder("block", materialString)); + else + wallMaterials.add(material); } - return composition; + return wallMaterials; } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/CutFromMaze.java b/src/me/gorgeousone/tangledmaze/command/CutFromMaze.java index f418918..725aebf 100644 --- a/src/me/gorgeousone/tangledmaze/command/CutFromMaze.java +++ b/src/me/gorgeousone/tangledmaze/command/CutFromMaze.java @@ -7,6 +7,7 @@ import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.handler.ToolHandler; import me.gorgeousone.tangledmaze.tool.ClippingTool; @@ -19,9 +20,8 @@ public CutFromMaze() { @Override public boolean execute(CommandSender sender, String[] arguments) { - if(!super.execute(sender, arguments)) { + if(!super.execute(sender, arguments)) return false; - } Player player = (Player) sender; @@ -49,15 +49,14 @@ public boolean execute(CommandSender sender, String[] arguments) { Maze maze = MazeHandler.getMaze(player); ClipAction action = maze.getDeletion(clipboard.getClip()); - - if(action == null) { - Messages.ERROR_CLIPBOARD_NOT_TOUCHING_MAZE.send(player); + Renderer.hideClipboard(clipboard, true); + clipboard.reset(); + + if(action == null) return false; - } - clipboard.reset(); maze.processAction(action, true); return true; } -} +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/DiscardMaze.java b/src/me/gorgeousone/tangledmaze/command/DiscardMaze.java index 6f5480b..55958f0 100644 --- a/src/me/gorgeousone/tangledmaze/command/DiscardMaze.java +++ b/src/me/gorgeousone/tangledmaze/command/DiscardMaze.java @@ -3,6 +3,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.handler.MazeHandler; import me.gorgeousone.tangledmaze.handler.ToolHandler; @@ -21,7 +22,7 @@ public boolean execute(CommandSender sender, String[] arguments) { Player player = (Player) sender; - MazeHandler.getMaze(player).reset(); + MazeHandler.setMaze(player, new Maze(player)); ToolHandler.resetToDefaultTool(player); return true; } diff --git a/src/me/gorgeousone/tangledmaze/command/HelpCommand.java b/src/me/gorgeousone/tangledmaze/command/HelpCommand.java index 4cb4b4b..e374990 100644 --- a/src/me/gorgeousone/tangledmaze/command/HelpCommand.java +++ b/src/me/gorgeousone/tangledmaze/command/HelpCommand.java @@ -13,8 +13,10 @@ public class HelpCommand extends MazeCommand { + private static int commandCount = 11; + private static int pageCount = commandCount + 1; + private static RawMessage[] pageLinks; -// private static TextMessage[] helpPages; private static HelpPage[] pages; public HelpCommand() { @@ -37,12 +39,11 @@ public boolean execute(CommandSender sender, String[] arguments) { public static void sendHelpPage(CommandSender sender, int pageNumber) { - if(pageNumber < 1 || pageNumber > pages.length+1) { + if(pageNumber < 1 || pageNumber > pageCount) return; - } sender.sendMessage(""); - sender.sendMessage(Constants.prefix + "--- Help Pages --- " + ChatColor.GREEN + pageNumber + "/" + (pages.length+1)); + sender.sendMessage(Constants.prefix + "--- Help Pages --- " + ChatColor.GREEN + pageNumber + "/" + pageCount); sender.sendMessage(""); if(pageNumber == 1) { @@ -56,9 +57,22 @@ public static void sendHelpPage(CommandSender sender, int pageNumber) { pages[pageNumber-2].send(sender); } + private int getPageNumber(String[] arguments) { + + if(arguments.length == 0) + return 1; + + try { + return Utils.limit(Integer.parseInt(arguments[0]), 1, pages.length+1); + + } catch (NumberFormatException ex) { + return 1; + } + } + private void createPageLinks() { - pageLinks = new RawMessage[9]; + pageLinks = new RawMessage[commandCount]; for(int i = 0; i < pageLinks.length; i++) { pageLinks[i] = new RawMessage(); @@ -73,12 +87,14 @@ private void createPageLinks() { pageLinks[5].last().append("/maze add / cut").color(Color.GREEN); pageLinks[6].last().append("/maze undo").color(Color.GREEN); pageLinks[7].last().append("/maze pathwidth / wallwidth / wallheight ").color(Color.GREEN); - pageLinks[8].last().append("/maze build ...").color(Color.GREEN); + pageLinks[8].last().append("/maze pathlength ").color(Color.GREEN); + pageLinks[9].last().append("/maze build ...").color(Color.GREEN); + pageLinks[10].last().append("/maze unbuild").color(Color.GREEN); } private void listHelpPages() { - pages = new HelpPage[9]; + pages = new HelpPage[commandCount]; pages[0] = new HelpPage(Messages.COMMAND_WAND); pages[1] = new HelpPage(Messages.COMMAND_START); pages[2] = new HelpPage(Messages.COMMAND_DISCARD); @@ -87,20 +103,8 @@ private void listHelpPages() { pages[5] = new HelpPage(Messages.COMMAND_ADD_CUT); pages[6] = new HelpPage(Messages.COMMAND_UNDO); pages[7] = new HelpPage(Messages.COMMAND_DIMENSIONS); - pages[8] = new HelpPage(Messages.COMMAND_BUILD); - - } - - private int getPageNumber(String[] arguments) { - - if(arguments.length == 0) - return 1; - - try { - return Utils.limitInt(Integer.parseInt(arguments[0]), 1, pages.length+1); - - } catch (NumberFormatException ex) { - return 1; - } + pages[8] = new HelpPage(Messages.COMMAND_PATHLENGTH); + pages[9] = new HelpPage(Messages.COMMAND_BUILD); + pages[10] = new HelpPage(Messages.COMMAND_UNBUILD); } -} +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/MazeCommand.java b/src/me/gorgeousone/tangledmaze/command/MazeCommand.java index b44317a..fc97223 100644 --- a/src/me/gorgeousone/tangledmaze/command/MazeCommand.java +++ b/src/me/gorgeousone/tangledmaze/command/MazeCommand.java @@ -13,17 +13,17 @@ public abstract class MazeCommand { private String name; private List aliases; - private String permission; + private String extraPermission; private String usage; private int argumentCount; private boolean requieresPlayer; - public MazeCommand(String name, String usage, int argumentCount, boolean requieresPlayer, String permission, String... aliases) { + public MazeCommand(String name, String usage, int argumentCount, boolean requieresPlayer, String extraPermission, String... aliases) { this.name = name.toLowerCase(); this.aliases = createAliases(aliases); - this.permission = permission; + this.extraPermission = extraPermission; this.usage = usage; this.argumentCount = argumentCount; this.requieresPlayer = requieresPlayer; @@ -33,25 +33,25 @@ public String getName() { return name; } - public List getAliases() { - return aliases; - } - - public String getPermission() { - return permission; + public String getUsage() { + return usage; } - + public int getArgumentCount() { return argumentCount; } - - public String getUsage() { - return usage; - } - + public boolean isPlayerRequiered() { return requieresPlayer; } + + public String getExtraPermission() { + return extraPermission; + } + + public List getAliases() { + return aliases; + } public boolean isCommand(String name) { return (getName().equals(name) || getAliases().contains(name.toLowerCase())); @@ -59,13 +59,12 @@ public boolean isCommand(String name) { public boolean execute(CommandSender sender, String[] arguments) { - //TODO localize messages - if(requieresPlayer && !(sender instanceof Player)) { + if(requieresPlayer && !(sender instanceof Player)) return false; - } - if(permission != null && !sender.hasPermission(permission)) { + if(extraPermission != null && !sender.hasPermission(extraPermission)) { Messages.ERROR_NO_BUILD_PERMISSION.send(sender); + return false; } if(arguments.length < argumentCount) { @@ -86,4 +85,4 @@ private List createAliases(String[] aliases) { return allAliases; } -} +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/Reload.java b/src/me/gorgeousone/tangledmaze/command/Reload.java index 38ff10d..22504fe 100644 --- a/src/me/gorgeousone/tangledmaze/command/Reload.java +++ b/src/me/gorgeousone/tangledmaze/command/Reload.java @@ -4,6 +4,7 @@ import me.gorgeousone.tangledmaze.core.TangledMain; import me.gorgeousone.tangledmaze.data.Constants; +import me.gorgeousone.tangledmaze.data.Messages; public class Reload extends MazeCommand { @@ -19,6 +20,7 @@ public boolean execute(CommandSender sender, String[] arguments) { } TangledMain.getInstance().reloadPlugin(); + Messages.MESSAGE_PLUGIN_RELOADED.send(sender); return true; } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/SelectTool.java b/src/me/gorgeousone/tangledmaze/command/SelectTool.java index 7c32407..b578cd2 100644 --- a/src/me/gorgeousone/tangledmaze/command/SelectTool.java +++ b/src/me/gorgeousone/tangledmaze/command/SelectTool.java @@ -5,6 +5,7 @@ import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.handler.ToolHandler; import me.gorgeousone.tangledmaze.shape.Shape; import me.gorgeousone.tangledmaze.tool.*; @@ -27,6 +28,7 @@ public boolean execute(CommandSender sender, String[] arguments) { String toolType = arguments[0]; switch (toolType.toLowerCase()) { + case "rect": case "rectangle": case "square": @@ -60,7 +62,7 @@ public boolean execute(CommandSender sender, String[] arguments) { break; default: - player.sendMessage("/tangledmaze help 5"); + player.sendMessage("/tangledmaze help 6"); return false; } @@ -97,7 +99,11 @@ private boolean switchMazeTool(Player player, Tool type) { } if(ToolHandler.hasClipboard(player)) { - ToolHandler.getClipboard(player).reset(); + + ClippingTool clipboard = ToolHandler.getClipboard(player); + + Renderer.hideClipboard(clipboard, true); + clipboard.reset(); } ToolHandler.setTool(player, type); diff --git a/src/me/gorgeousone/tangledmaze/command/SetPathLength.java b/src/me/gorgeousone/tangledmaze/command/SetPathLength.java new file mode 100644 index 0000000..d0d8cac --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/command/SetPathLength.java @@ -0,0 +1,49 @@ +package me.gorgeousone.tangledmaze.command; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.data.Constants; +import me.gorgeousone.tangledmaze.data.Messages; +import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.util.PlaceHolder; +import me.gorgeousone.tangledmaze.util.Utils; + +public class SetPathLength extends MazeCommand { + + public SetPathLength() { + super("pathlength", "/tangledmaze pathlength ", 1, true, null); + } + + @Override + public boolean execute(CommandSender sender, String[] arguments) { + + if(!super.execute(sender, arguments)) + return false; + + Player player = (Player) sender; + + String pathLengthString = arguments[0]; + int pathLength; + + try { + pathLength = Utils.limit(Integer.parseInt(pathLengthString), 1, Constants.MAX_PATHLENGTH); + + } catch (NumberFormatException ex) { + + Messages.ERROR_INVALID_NUMBER.send(player, new PlaceHolder("number", pathLengthString)); + return false; + } + + Maze maze = MazeHandler.getMaze(player); + + if(maze.getWallHeight() == pathLength) + return false; + + maze.setPathLength(pathLength); + Messages.MESSAGE_PATHLENGTH_CHANGED.send(player, new PlaceHolder("number", pathLength)); + + return true; + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/SetPathWidth.java b/src/me/gorgeousone/tangledmaze/command/SetPathWidth.java index ebef33b..e931171 100644 --- a/src/me/gorgeousone/tangledmaze/command/SetPathWidth.java +++ b/src/me/gorgeousone/tangledmaze/command/SetPathWidth.java @@ -6,8 +6,8 @@ import org.bukkit.entity.Player; import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.data.Constants; import me.gorgeousone.tangledmaze.data.Messages; -import me.gorgeousone.tangledmaze.data.Settings; import me.gorgeousone.tangledmaze.handler.MazeHandler; import me.gorgeousone.tangledmaze.util.PlaceHolder; @@ -30,22 +30,21 @@ public boolean execute(CommandSender sender, String[] arguments) { int pathWidth; try { - pathWidth = Utils.limitInt(Integer.parseInt(pathWidthString), 1, Settings.MAX_PATHWIDTH); + pathWidth = Utils.limit(Integer.parseInt(pathWidthString), 1, Constants.MAX_PATHWIDTH); } catch (NumberFormatException ex) { - Messages.ERROR_NUMBER_NOT_VALID.send(player, new PlaceHolder("number", pathWidthString)); + Messages.ERROR_INVALID_NUMBER.send(player, new PlaceHolder("number", pathWidthString)); return false; } Maze maze = MazeHandler.getMaze(player); - if(maze.getPathWidth() != pathWidth) { + if(maze.getPathWidth() == pathWidth) + return false; - maze.setPathWidth(pathWidth); - Messages.MESSAGE_PATHWIDTH_CHANGED.send(player, new PlaceHolder("number", pathWidth)); - } - + maze.setPathWidth(pathWidth); + Messages.MESSAGE_PATHWIDTH_CHANGED.send(player, new PlaceHolder("number", pathWidth)); return true; } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/SetWallHeight.java b/src/me/gorgeousone/tangledmaze/command/SetWallHeight.java index cbe3f90..879fd1a 100644 --- a/src/me/gorgeousone/tangledmaze/command/SetWallHeight.java +++ b/src/me/gorgeousone/tangledmaze/command/SetWallHeight.java @@ -6,8 +6,8 @@ import org.bukkit.entity.Player; import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.data.Constants; import me.gorgeousone.tangledmaze.data.Messages; -import me.gorgeousone.tangledmaze.data.Settings; import me.gorgeousone.tangledmaze.handler.MazeHandler; import me.gorgeousone.tangledmaze.util.PlaceHolder; @@ -20,9 +20,8 @@ public SetWallHeight() { @Override public boolean execute(CommandSender sender, String[] arguments) { - if(!super.execute(sender, arguments)) { + if(!super.execute(sender, arguments)) return false; - } Player player = (Player) sender; @@ -30,19 +29,18 @@ public boolean execute(CommandSender sender, String[] arguments) { int wallHeight; try { - wallHeight = Utils.limitInt(Integer.parseInt(wallHeightString), 1, Settings.MAX_WALLHEIGHT); + wallHeight = Utils.limit(Integer.parseInt(wallHeightString), 1, Constants.MAX_WALLHEIGHT); } catch (NumberFormatException ex) { - Messages.ERROR_NUMBER_NOT_VALID.send(player, new PlaceHolder("number", wallHeightString)); + Messages.ERROR_INVALID_NUMBER.send(player, new PlaceHolder("number", wallHeightString)); return false; } Maze maze = MazeHandler.getMaze(player); - if(maze.getWallHeight() == wallHeight) { + if(maze.getWallHeight() == wallHeight) return false; - } maze.setWallHeight(wallHeight); Messages.MESSAGE_WALLHEIGHT_CHANGED.send(player, new PlaceHolder("number", wallHeight)); diff --git a/src/me/gorgeousone/tangledmaze/command/SetWallWidth.java b/src/me/gorgeousone/tangledmaze/command/SetWallWidth.java index 6206feb..0ac3004 100644 --- a/src/me/gorgeousone/tangledmaze/command/SetWallWidth.java +++ b/src/me/gorgeousone/tangledmaze/command/SetWallWidth.java @@ -6,8 +6,8 @@ import org.bukkit.entity.Player; import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.data.Constants; import me.gorgeousone.tangledmaze.data.Messages; -import me.gorgeousone.tangledmaze.data.Settings; import me.gorgeousone.tangledmaze.handler.MazeHandler; import me.gorgeousone.tangledmaze.util.PlaceHolder; @@ -20,9 +20,8 @@ public SetWallWidth() { @Override public boolean execute(CommandSender sender, String[] arguments) { - if(!super.execute(sender, arguments)) { + if(!super.execute(sender, arguments)) return false; - } Player player = (Player) sender; @@ -30,21 +29,21 @@ public boolean execute(CommandSender sender, String[] arguments) { int wallWidth; try { - wallWidth = Utils.limitInt(Integer.parseInt(wallWidthString), 1, Settings.MAX_WALLWIDTH); + wallWidth = Utils.limit(Integer.parseInt(wallWidthString), 1, Constants.MAX_WALLWIDTH); }catch (NumberFormatException ex) { - Messages.ERROR_NUMBER_NOT_VALID.send(player, new PlaceHolder("number", wallWidthString)); + Messages.ERROR_INVALID_NUMBER.send(player, new PlaceHolder("number", wallWidthString)); return false; } Maze maze = MazeHandler.getMaze(player); - if(maze.getWallWidth() != wallWidth) { - maze.setWallWidth(wallWidth); - Messages.MESSAGE_WALLWIDTH_CHANGED.send(player, new PlaceHolder("number", wallWidth)); - } - + if(maze.getWallWidth() == wallWidth) + return false; + + maze.setWallWidth(wallWidth); + Messages.MESSAGE_WALLWIDTH_CHANGED.send(player, new PlaceHolder("number", wallWidth)); return true; } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/StartMaze.java b/src/me/gorgeousone/tangledmaze/command/StartMaze.java index d9ee5c7..a0db288 100644 --- a/src/me/gorgeousone/tangledmaze/command/StartMaze.java +++ b/src/me/gorgeousone/tangledmaze/command/StartMaze.java @@ -3,9 +3,10 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import me.gorgeousone.tangledmaze.clip.Clip; +import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.handler.ToolHandler; import me.gorgeousone.tangledmaze.tool.ClippingTool; @@ -37,11 +38,18 @@ public boolean execute(CommandSender sender, String[] arguments) { return false; } - Clip clip = clipboard.getClip(); - clipboard.reset(); - - MazeHandler.getMaze(player).setClip(clip); + Renderer.hideClipboard(clipboard, false); + Maze maze = MazeHandler.getMaze(player); + + if(maze.isConstructed()) { + maze = new Maze(player).setClip(clipboard.getClip()); + MazeHandler.setMaze(player, maze); + + }else + maze.setClip(clipboard.getClip()); + + clipboard.reset(); return true; } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/TpToMaze.java b/src/me/gorgeousone/tangledmaze/command/TpToMaze.java index 6344c04..ea01f91 100644 --- a/src/me/gorgeousone/tangledmaze/command/TpToMaze.java +++ b/src/me/gorgeousone/tangledmaze/command/TpToMaze.java @@ -1,13 +1,17 @@ package me.gorgeousone.tangledmaze.command; +import java.util.TreeSet; + +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.data.Constants; import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; -import me.gorgeousone.tangledmaze.util.MazePoint; +import me.gorgeousone.tangledmaze.util.Vec2; public class TpToMaze extends MazeCommand { @@ -23,16 +27,18 @@ public boolean execute(CommandSender sender, String[] arguments) { } Player player = (Player) sender; + Maze maze = MazeHandler.getMaze(player); - if(!MazeHandler.getMaze(player).isStarted()) { + if(!maze.isStarted()) { Messages.ERROR_MAZE_NOT_STARTED.send(player); player.sendMessage("/tangledmaze start"); return false; } - MazePoint target = MazeHandler.getMaze(player).getClip().getBorder().first(); - + Vec2 firstLoc = ((TreeSet) maze.getClip().getBorder()).first(); + + Location target = maze.getClip().getLocation(firstLoc); target.add(0.5, 2, 0.5); target.setDirection(player.getLocation().getDirection()); diff --git a/src/me/gorgeousone/tangledmaze/command/UnbuildMaze.java b/src/me/gorgeousone/tangledmaze/command/UnbuildMaze.java new file mode 100644 index 0000000..b02d7cb --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/command/UnbuildMaze.java @@ -0,0 +1,41 @@ +package me.gorgeousone.tangledmaze.command; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + + +import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.data.Messages; +import me.gorgeousone.tangledmaze.generation.BlockGenerator; +import me.gorgeousone.tangledmaze.handler.MazeHandler; + +public class UnbuildMaze extends MazeCommand { + + private BlockGenerator blockGenerator; + + public UnbuildMaze() { + + super("unbuild", "/tangledmaze unbuild", 0, true, null); + blockGenerator = new BlockGenerator(); + } + + @Override + public boolean execute(CommandSender sender, String[] arguments) { + + if(!super.execute(sender, arguments)) + return false; + + Player player = (Player) sender; + Maze maze = MazeHandler.getMaze(player); + + if(!maze.isConstructed()) { + + Messages.MESSAGE_NO_MAZE_TO_UNBUILD.send(player); + return true; + } + + MazeHandler.unbuilMaze(maze, blockGenerator); + Messages.MESSAGE_MAZE_UNBUILDING_STARTED.send(player); + return true; + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/command/UndoAction.java b/src/me/gorgeousone/tangledmaze/command/Undo.java similarity index 88% rename from src/me/gorgeousone/tangledmaze/command/UndoAction.java rename to src/me/gorgeousone/tangledmaze/command/Undo.java index d597d69..507d5e0 100644 --- a/src/me/gorgeousone/tangledmaze/command/UndoAction.java +++ b/src/me/gorgeousone/tangledmaze/command/Undo.java @@ -10,33 +10,33 @@ import me.gorgeousone.tangledmaze.data.Messages; import me.gorgeousone.tangledmaze.handler.MazeHandler; -public class UndoAction extends MazeCommand { +public class Undo extends MazeCommand { - public UndoAction() { + public Undo() { super("undo", "/tangledmaze undo", 0, true, null); } @Override public boolean execute(CommandSender sender, String[] arguments) { - if(!super.execute(sender, arguments)) { + if(!super.execute(sender, arguments)) return false; - } Player player = (Player) sender; - if(!MazeHandler.getMaze(player).isStarted()) { - //TODO think about better error message + Maze maze = MazeHandler.getMaze(player); + + if(!maze.isStarted() || maze.isConstructed()) { + Messages.ERROR_MAZE_NOT_STARTED.send(player); return false; } - Maze maze = MazeHandler.getMaze(player); if(maze.getActionHistory().isEmpty()) { return false; } - + ClipAction action = maze.getActionHistory().popLastAction().invert(); maze.processAction(action, false); diff --git a/src/me/gorgeousone/tangledmaze/core/Maze.java b/src/me/gorgeousone/tangledmaze/core/Maze.java index 5df858e..efe09d3 100644 --- a/src/me/gorgeousone/tangledmaze/core/Maze.java +++ b/src/me/gorgeousone/tangledmaze/core/Maze.java @@ -1,55 +1,61 @@ package me.gorgeousone.tangledmaze.core; -import java.util.ArrayList; import java.util.List; +import java.util.Map.Entry; +import java.util.Stack; import java.util.UUID; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.entity.Player; -import org.bukkit.material.MaterialData; -import org.bukkit.util.Vector; -import me.gorgeousone.tangledmaze.clip.ActionHistory; -import me.gorgeousone.tangledmaze.clip.Clip; -import me.gorgeousone.tangledmaze.clip.ClipAction; +import me.gorgeousone.tangledmaze.clip.*; import me.gorgeousone.tangledmaze.data.Constants; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.util.Directions; -import me.gorgeousone.tangledmaze.util.MazePoint; import me.gorgeousone.tangledmaze.util.Utils; +import me.gorgeousone.tangledmaze.util.Vec2; -@SuppressWarnings("deprecation") public class Maze { + private static IllegalStateException notAlterableException = new IllegalStateException("The maze cannot be altered when it is constructed"); + private UUID builder; private ActionHistory history; private Clip clip; - private List exits; - private List wallComposition; + private Stack exits; + private List wallMaterials; + private List builtBlocks; + + private int wallWidth; + private int wallHeight; + private int pathWidth; + private int pathLength; + + private boolean isStarted, isConstructed; - private Vector dimensions; - private boolean isStarted; public Maze(World world) { clip = new Clip(world); history = new ActionHistory(); - exits = new ArrayList<>(); - dimensions = new Vector(1, 2, 1); + exits = new Stack<>(); + + wallWidth = 1; + wallHeight = 2; + pathWidth = 1; + pathLength = 5; } public Maze(Player builder) { + this(builder.getWorld()); this.builder = builder.getUniqueId(); - - clip = new Clip(builder.getWorld()); - history = new ActionHistory(); - exits = new ArrayList<>(); - dimensions = new Vector(1, 2, 1); } public Player getPlayer() { @@ -64,125 +70,127 @@ public boolean isStarted() { return isStarted; } + public boolean isConstructed() { + return isConstructed; + } + public Clip getClip() { return clip; } - public List getExits() { - return exits; + public Maze setClip(Clip clip) { + + if(getClip().size() != 0) + Renderer.hideMaze(this); + + this.clip = clip; + isStarted = true; + Renderer.displayMaze(this); + + return this; } - public MazePoint getMainExit() { - return exits.isEmpty() ? null : exits.get(exits.size()-1); + public Stack getExits() { + + Stack deepCopy = new Stack<>(); + + for(Vec2 exit : exits) + deepCopy.push(exit.clone()); + + return deepCopy; } - public ActionHistory getActionHistory() { - return history; + public boolean hasExits() { + return !exits.isEmpty(); } - public int getPathWidth() { - return dimensions.getBlockX(); + public Vec2 getMainExit() { + return hasExits() ? exits.peek().clone() : null; } - public int getWallHeight() { - return dimensions.getBlockY(); + public ActionHistory getActionHistory() { + return history; } public int getWallWidth() { - return dimensions.getBlockZ(); + return wallWidth; } - public List getWallComposition() { - return wallComposition; + public void setWallWidth(int blocks) { + wallWidth = Math.max(1, blocks); } - public void setPathWidth(int pathWidth) { - dimensions.setX(Math.max(1, pathWidth)); + public int getWallHeight() { + return wallHeight; } - public void setWallHeight(int wallHeight) { - dimensions.setY(Math.max(1, wallHeight)); + public void setWallHeight(int blocks) { + wallHeight = Math.max(1, blocks); } - public void setWallWidth(int wallWidth) { - dimensions.setZ(Math.max(1, wallWidth)); + public int getPathWidth() { + return pathWidth; } - public void setWallComposition(ArrayList composition) { - wallComposition = composition; + public void setPathWidth(int blocks) { + pathWidth = Math.max(1, blocks); } - - public void setClip(Clip clip) { - - if(getClip().size() != 0) - Renderer.hideMaze(this); - this.clip = clip; - isStarted = true; - Renderer.showMaze(this); + public int getPathLength() { + return pathLength; } - public void reset() { - - Renderer.hideMaze(this); + public void setPathLength(int blocks) { + pathLength = Math.max(1, blocks); + } - clip = new Clip(getWorld()); - exits.clear(); - history.clear(); - isStarted = false; + public List getWallMaterials() { + return wallMaterials; } - public boolean exitsContain(Location loc) { - return exits.contains(loc); + public void setWallMaterials(List materials) { + wallMaterials = materials; } - public boolean canBeExit(Block block) { - - MazePoint point = new MazePoint(block.getLocation()); - - if(!isHighlighted(point.getBlock())) { - return false; - } - - return sealsMaze(point, new ClipAction(), Directions.cardinalValues()); + public List getBuiltBlocks() { + return builtBlocks; } - public boolean isHighlighted(Block block) { - - MazePoint point = new MazePoint(block.getLocation()); - - if(!getClip().borderContains(point)) { - return false; - } + public void setConstructedBlocks(List builtBlocks) { - for(MazePoint borderPoint : getClip().getBorder()) { - if(borderPoint.equals(point) && borderPoint.getY() == point.getY()) { - return true; - } - } + this.builtBlocks = builtBlocks; - return false; + if(builtBlocks != null) + isConstructed = true; + else + isConstructed = false; + } + + public boolean exitsContain(Vec2 loc) { + return exits.contains(loc); } public boolean isExit(Block block) { - MazePoint point = new MazePoint(block.getLocation()); + Vec2 blockVec = new Vec2(block); - for(MazePoint exit : exits) { - if(point.equals(exit) && point.getY() == exit.getY()) - return true; - } + return exits.contains(blockVec) && getClip().getHeight(blockVec) == block.getY(); + } + + public boolean canBeExit(Block block) { - return false; + if(!getClip().isBorderBlock(block)) + return false; + + return sealsMaze(block.getLocation(), Directions.cardinalValues()); } public void toggleExit(Block block) { - if(!isHighlighted(block)) { + if(!getClip().isBorderBlock(block)) return; - } - - MazePoint newExit = new MazePoint(block.getLocation()); + + Vec2 clickedLoc = new Vec2(block); if(!canBeExit(block)) { Renderer.sendBlockDelayed(getPlayer(), block.getLocation(), Constants.MAZE_BORDER); @@ -191,216 +199,175 @@ public void toggleExit(Block block) { if(isExit(block)) { - exits.remove(newExit); - Renderer.sendBlockDelayed(getPlayer(), newExit, Constants.MAZE_BORDER); + exits.remove(clickedLoc); + Renderer.sendBlockDelayed(getPlayer(), block.getLocation(), Constants.MAZE_BORDER); - if(!exits.isEmpty()) { - Renderer.sendBlockDelayed(getPlayer(), exits.get(exits.size()-1), Constants.MAZE_MAIN_EXIT); - } + if(hasExits()) + Renderer.sendBlockDelayed(getPlayer(), getClip().getLocation(getMainExit()), Constants.MAZE_MAIN_EXIT); }else { - if(!exits.isEmpty()) { - Renderer.sendBlockDelayed(getPlayer(), exits.get(exits.size()-1), Constants.MAZE_EXIT); - } + if(hasExits()) + Renderer.sendBlockDelayed(getPlayer(), getClip().getLocation(getMainExit()), Constants.MAZE_EXIT); - exits.add(newExit); - Renderer.sendBlockDelayed(getPlayer(), newExit, Constants.MAZE_MAIN_EXIT); + exits.push(clickedLoc); + Renderer.sendBlockDelayed(getPlayer(), block.getLocation(), Constants.MAZE_MAIN_EXIT); } } - //TODO move updateHeight() from Maze and ClippingTool to Clip class - public Block updateHeight(Block block) { + public void processAction(ClipAction action, boolean saveToHistory) { - MazePoint updated = Utils.nearestSurface(block.getLocation()); + if(isConstructed()) + throw notAlterableException; - if(getClip().removeFilling(updated)) { - getClip().addFilling(updated); + for(Vec2 border : action.getRemovedBorder()) + getClip().removeBorder(border); - }else - return null; - - if(getClip().removeBorder(updated)) { - getClip().addBorder(updated); - } + for(Vec2 fill : action.getRemovedFill().keySet()) + getClip().removeFill(fill); - return updated.getBlock(); - } - - public void processAction(ClipAction action, boolean saveToHistory) { - - getClip().removeFilling(action.getRemovedFill()); - getClip().removeBorder(action.getRemovedBorder()); - - for(MazePoint point : action.getAddedFill()) - getClip().addFilling(point); + getClip().addAllFill(action.getAddedFill()); - for(MazePoint point : action.getAddedBorder()) - getClip().addBorder(point); + for(Vec2 border : action.getAddedBorder()) + getClip().addBorder(border); - if(saveToHistory) - history.pushAction(action); + exits.removeAll(action.getRemovedExits()); - Renderer.showMazeAction(this, action); + if(saveToHistory) + getActionHistory().pushAction(action); + + Renderer.displayMazeAction(this, action); } - public ClipAction getAddition(Clip clip) { - - ClipAction addition = new ClipAction(); - - if(!getWorld().equals(clip.getWorld())) - return addition; + public ClipAction getAddition(Clip otherClip) { + + if(!getWorld().equals(otherClip.getWorld())) + return null; - addProtrudingShapeParts(clip, addition); + ClipAction addition = new ClipAction(getClip()); + + addProtrudingFill(otherClip, addition); //return if the shapes is totally covered by the maze if(addition.getAddedFill().isEmpty()) - return addition; - - removeEnclosedBorder(clip, addition); - removeExitsInsideClip(clip, addition); + return null; + + addProtrudingBorder(otherClip, addition); + removeEnclosedBorder(otherClip, addition); + removeExitsInsideClip(otherClip, addition); return addition; } - private void addProtrudingShapeParts(Clip clip, ClipAction addition) { - //check for new border blocks - for(Chunk chunk : clip.getBorderChunks()) { + private void addProtrudingFill(Clip otherClip, ClipAction addition) { + + for(Entry otherFill : otherClip.getFillSet()) { - for(MazePoint borderPoint : clip.getBorder(chunk)) { - if(!getClip().contains(borderPoint)) { - addition.addBorder(borderPoint); - } - } + if(!getClip().contains(otherFill.getKey())) + addition.addFill(otherFill.getKey(), otherFill.getValue()); } - - //add new fill blocks - for(Chunk chunk : clip.getChunks()) { + } + + private void addProtrudingBorder(Clip otherClip, ClipAction addition) { + + for(Vec2 otherBorder : otherClip.getBorder()) { - for(MazePoint fillPoint : clip.getFilling(chunk)) { - if(!getClip().contains(fillPoint)) { - addition.addFill(fillPoint); - } - } + if(!getClip().contains(otherBorder)) + addition.addBorder(otherBorder); } } - private void removeEnclosedBorder(Clip clip, ClipAction addition) { + private void removeEnclosedBorder(Clip otherClip, ClipAction addition) { - for(Chunk chunk : clip.getChunks()) { + for(Vec2 ownBorder : getClip().getBorder()) { - if(!getClip().getBorderChunks().contains(chunk)) { - continue; - } - - for(MazePoint ownBorder : getClip().getBorder(chunk)) { - - if(!clip.contains(ownBorder) || - clip.borderContains(ownBorder) && - sealsMaze(ownBorder, addition, Directions.values())) { - continue; - } - + if(otherClip.contains(ownBorder) && + !otherClip.borderContains(ownBorder) || + !sealsMaze(ownBorder, addition, Directions.values())) addition.removeBorder(ownBorder); - } } } - private void removeExitsInsideClip(Clip clip, ClipAction changes) { + private void removeExitsInsideClip(Clip otherClip, ClipAction changes) { - for(MazePoint exit : exits) { - if(clip.contains(exit)) { + for(Vec2 exit : exits) { + + if(otherClip.contains(exit)) changes.removeExit(exit); - } } } public ClipAction getDeletion(Clip clip) { - ClipAction deletion = new ClipAction(); - if(!getWorld().equals(clip.getWorld())) - return deletion; + return null; + + ClipAction deletion = new ClipAction(getClip()); - removeIntrudingShapeParts(clip, deletion); + removeOverlappingFill(clip, deletion); if(deletion.getRemovedFill().isEmpty()) - return deletion; + return null; + //the order of these steps has not to be changed + addIntersectingBorder(clip, deletion); removeExcludedBorder(clip, deletion); removeExitsInsideClip(clip, deletion); return deletion; } - private void removeIntrudingShapeParts(Clip clip, ClipAction deletion) { - //remove all fill from the shape - for(Chunk chunk : clip.getChunks()) { - - if(!getClip().getChunks().contains(chunk)) { - continue; - } + private void removeOverlappingFill(Clip otherClip, ClipAction deletion) { + + for(Entry otherFill : otherClip.getFillSet()) { - for(MazePoint point : clip.getFilling(chunk)) - if(getClip().contains(point) && !clip.borderContains(point)) - deletion.removeFill(point); + if(!otherClip.borderContains(otherFill.getKey()) && getClip().contains(otherFill.getKey())) + deletion.removeFill(otherFill.getKey(), otherFill.getValue()); } - //get new border where shape is cutting into maze - for(Chunk chunk : clip.getBorderChunks()) { - - if(!getClip().getChunks().contains(chunk)) { - continue; - } + } + + private void addIntersectingBorder(Clip otherClip, ClipAction deletion) { + + for(Vec2 otherBorder : otherClip.getBorder()) { - for(MazePoint point : clip.getBorder(chunk)) - if(getClip().contains(point) && !getClip().borderContains(point)) - deletion.addBorder(point); + if(!getClip().borderContains(otherBorder) && getClip().contains(otherBorder)) + deletion.addBorder(otherBorder); } } - - private void removeExcludedBorder(Clip clip, ClipAction deletion) { + + private void removeExcludedBorder(Clip otherClip, ClipAction deletion) { - for(Chunk chunk : clip.getBorderChunks()) { - - if(!getClip().getBorderChunks().contains(chunk)) { - continue; - } + for(Vec2 ownBorder : getClip().getBorder()) { - for(MazePoint ownBorder : getClip().getBorder(chunk)) { - - if(!clip.contains(ownBorder) || - clip.borderContains(ownBorder) && - sealsMaze(ownBorder, deletion, Directions.values())) { - continue; - } - + if(!otherClip.borderContains(ownBorder) && !sealsMaze(ownBorder, deletion, Directions.values())) deletion.removeBorder(ownBorder); - deletion.removeFill(ownBorder); - } } } public ClipAction getExpansion(Block block) { - if(!isHighlighted(block)) + if(!getClip().isBorderBlock(block)) return null; - MazePoint point = new MazePoint(block.getLocation()); - ClipAction expansion = new ClipAction(); + Vec2 blockVec = new Vec2(block); + ClipAction expansion = new ClipAction(getClip()); - expandBorder(point, expansion); - removeIntrusiveBorder(point, expansion); + expandBorder(blockVec, expansion); + removeIntrusiveBorder(blockVec, expansion); return expansion; } - private void expandBorder(MazePoint point, ClipAction expansion) { + private void expandBorder(Vec2 loc, ClipAction expansion) { - expansion.removeBorder(point); + expansion.removeBorder(loc); for(Directions dir : Directions.values()) { - MazePoint neighbor = Utils.nearestSurface(point.clone().add(dir.toVec3())); + + Vec2 neighbor = loc.clone().add(dir.toVec2()); + int height = Utils.nearestSurfaceY(neighbor, getClip().getHeight(loc), getWorld()); if(!getClip().contains(neighbor)) { - expansion.addFill(neighbor); + + expansion.addFill(neighbor, height); expansion.addBorder(neighbor); }else if(exitsContain(neighbor) && !sealsMaze(neighbor, expansion, Directions.cardinalValues())) @@ -408,97 +375,116 @@ private void expandBorder(MazePoint point, ClipAction expansion) { } } - private void removeIntrusiveBorder(MazePoint point, ClipAction expansion) { + private void removeIntrusiveBorder(Vec2 loc, ClipAction expansion) { //look for neighbors, that are now intruding the border unnecessarily for(Directions dir : Directions.values()) { - MazePoint neighbor = Utils.nearestSurface(point.clone().add(dir.toVec3())); - if(!getClip().borderContains(neighbor) && !expansion.getAddedBorder().contains(neighbor)) - continue; - - if(!sealsMaze(neighbor, expansion, Directions.values())) + Vec2 neighbor = loc.clone().add(dir.toVec2()); + + if(getClip().borderContains(neighbor) && !sealsMaze(neighbor, expansion, Directions.values())) expansion.removeBorder(neighbor); } } public ClipAction getErasure(Block block) { - if(!isHighlighted(block)) + if(!getClip().isBorderBlock(block)) return null; - MazePoint point = new MazePoint(block.getLocation()); - ClipAction action = new ClipAction(); + Vec2 blockVec = new Vec2(block); + ClipAction action = new ClipAction(getClip()); - action.removeBorder(point); - - reduceBorder(point, action); - removeProtrusiveBorder(point, action); + action.removeBorder(blockVec); + reduceBorder(blockVec, action); + removeProtrusiveBorder(blockVec, action); return action; } - private void reduceBorder(MazePoint point, ClipAction action) { + private void reduceBorder(Vec2 loc, ClipAction erasure) { - if(exitsContain(point)) - action.removeExit(point); + if(exitsContain(loc)) + erasure.removeExit(loc); - action.removeBorder(point); - action.removeFill(point); + erasure.removeBorder(loc); + erasure.removeFill(loc, getClip().getHeight(loc)); - if(!sealsMaze(point, action, Directions.values())) + if(!sealsMaze(loc, erasure, Directions.values())) return; for(Directions dir : Directions.values()) { - MazePoint neighbor = point.clone().add(dir.toVec3()); + Vec2 neighbor = loc.clone().add(dir.toVec2()); if(getClip().contains(neighbor) && !getClip().borderContains(neighbor)) - action.addBorder(neighbor); + erasure.addBorder(neighbor); - if(exitsContain(neighbor) && !sealsMaze(neighbor, action, Directions.cardinalValues())) - action.removeExit(neighbor); + if(exitsContain(neighbor) && !sealsMaze(neighbor, erasure, Directions.cardinalValues())) + erasure.removeExit(neighbor); } } - private void removeProtrusiveBorder(MazePoint point, ClipAction changes) { - //detect outstanding neighbor borders of the block (in cardinal directions) + private void removeProtrusiveBorder(Vec2 loc, ClipAction erasure) { + //detect outstanding neighbor borders of the block for(Directions dir : Directions.values()) { - MazePoint neighbor = Utils.nearestSurface(point.clone().add(dir.toVec3())); - - if(!getClip().borderContains(neighbor)) - continue; + + Vec2 neighbor = loc.clone().add(dir.toVec2()); //remove the neighbor if it still stands out - if(!sealsMaze(neighbor, changes, Directions.values())) { - changes.removeBorder(neighbor); - changes.removeFill(neighbor); + if(getClip().borderContains(neighbor) && !sealsMaze(neighbor, erasure, Directions.values())) { + + int height = getClip().getHeight(neighbor); + erasure.removeBorder(neighbor); + erasure.removeFill(neighbor, height); } } } - public boolean sealsMaze(MazePoint point, Directions[] directions) { - return sealsMaze(point, new ClipAction(), directions); + public boolean sealsMaze(Location loc, Directions[] directions) { + return sealsMaze(new Vec2(loc), new ClipAction(getClip()), directions); } - public boolean sealsMaze(MazePoint point, ClipAction changes, Directions[] directions) { + public boolean sealsMaze(Vec2 loc, ClipAction changes, Directions[] directions) { - boolean - touchesFill = false, - touchesExternal = false; + boolean touchesFill = false; + boolean touchesExternal = false; for(Directions dir : directions) { - MazePoint neighbor = point.clone().add(dir.toVec3()); - if(!changes.clipWillContain(clip, neighbor)) { + + Vec2 neighbor = loc.clone().add(dir.toVec2()); + + if(!changes.clipWillContain(neighbor)) touchesExternal = true; - }else if(!changes.clipBorderWillContain(clip, neighbor)) { + else if(!changes.clipBorderWillContain(getClip(), neighbor)) touchesFill = true; - } - if(touchesFill && touchesExternal) { + if(touchesFill && touchesExternal) return true; - } } + return false; } + + public void updateHeights() { + + if(isConstructed()) + throw notAlterableException; + + for(Entry fill : getClip().getFillSet()) + getClip().addFill(fill.getKey(), Utils.nearestSurfaceY(fill.getKey(), fill.getValue(), getWorld())); + } + + public Location updateHeight(Block block) { + + if(isConstructed()) + throw notAlterableException; + + Location updatedBlock = Utils.nearestSurface(block.getLocation()); + Vec2 blockVec = new Vec2(block); + + getClip().addFill(blockVec, updatedBlock.getBlockY()); + + return updatedBlock; + } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/core/Renderer.java b/src/me/gorgeousone/tangledmaze/core/Renderer.java deleted file mode 100644 index fcc8a82..0000000 --- a/src/me/gorgeousone/tangledmaze/core/Renderer.java +++ /dev/null @@ -1,263 +0,0 @@ -package me.gorgeousone.tangledmaze.core; - -import me.gorgeousone.tangledmaze.clip.ClipAction; -import me.gorgeousone.tangledmaze.data.Constants; -import me.gorgeousone.tangledmaze.handler.MazeHandler; -import me.gorgeousone.tangledmaze.tool.ClippingTool; -import me.gorgeousone.tangledmaze.util.MazePoint; - -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.Listener; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; - -public abstract class Renderer implements Listener { - - private static HashMap clipVisibilities = new HashMap<>(); - private static HashMap mazeVisibilities = new HashMap<>(); - - public static void reload() { - - for (ClippingTool selection : clipVisibilities.keySet()) { - if (isClipboardVisible(selection)) { - hideClipboard(selection, false); - } - } - - for(Maze maze : mazeVisibilities.keySet()) { - if(isMazeVisible(maze)) { - hideMaze(maze); - } - } - } - - public static void registerClip(ClippingTool clipboard) { - - if(clipboard.getPlayer() == null) { - return; - } - - clipVisibilities.put(clipboard, false); - } - - public static void registerMaze(Maze maze) { - - if(maze.getPlayer() == null) - return; - - mazeVisibilities.put(maze, false); - } - - public static void unregisterShape(ClippingTool clipboard) { - clipVisibilities.remove(clipboard); - } - - public static void unregisterMaze(Maze maze) { - mazeVisibilities.remove(maze); - } - - public static boolean isClipboardVisible(ClippingTool shape) { - return clipVisibilities.get(shape); - } - - public static boolean isMazeVisible(Maze maze) { - return mazeVisibilities.get(maze); - } - - @SuppressWarnings("deprecation") - public static void showClipboard(ClippingTool clipboard) { - - clipVisibilities.put(clipboard, true); - Player player = clipboard.getPlayer(); - - new BukkitRunnable() { - @Override - public void run() { - - if(clipboard.isComplete()) { - for(MazePoint point : clipboard.getClip().getBorder()) { - player.sendBlockChange(point, Constants.CLIPBOARD_BORDER, (byte) 0); - } - } - - for(Location vertex : clipboard.getVertices()) { - player.sendBlockChange(vertex, Constants.CLIPBOARD_CORNER, (byte) 0); - } - //TODO change back to runTask() if you can find out why block click still interferes block change after 1 tick - } - }.runTaskLater(TangledMain.getInstance(), 2); - } - - @SuppressWarnings("deprecation") - public static void showMaze(Maze maze) { - - mazeVisibilities.put(maze, true); - Player player = maze.getPlayer(); - - new BukkitRunnable() { - @Override - public void run() { - - for(MazePoint point : maze.getClip().getBorder()) { - player.sendBlockChange(point, Constants.MAZE_BORDER, (byte) 0); - } - - - for(Location exit : maze.getExits()) { - player.sendBlockChange(exit, Constants.MAZE_EXIT, (byte) 0); - } - - if(!maze.getExits().isEmpty()) { - player.sendBlockChange(maze.getExits().get(0), Constants.MAZE_MAIN_EXIT, (byte) 0); - } - } - }.runTask(TangledMain.getInstance()); - } - - @SuppressWarnings("deprecation") - public static void hideClipboard(ClippingTool clipboard, boolean updateMaze) { - - if(!isClipboardVisible(clipboard)) { - return; - } - - clipVisibilities.put(clipboard, false); - Player player = clipboard.getPlayer(); - - if(clipboard.isComplete()) { - for(Location point : clipboard.getClip().getBorder()) { - player.sendBlockChange(point, point.getBlock().getType(), point.getBlock().getData()); - } - } - - for(Location vertex : clipboard.getVertices()) { - player.sendBlockChange(vertex, vertex.getBlock().getType(), vertex.getBlock().getData()); - } - - if(updateMaze && MazeHandler.getMaze(player) != null && isMazeVisible(MazeHandler.getMaze(player))) - refreshMaze(player, clipboard, MazeHandler.getMaze(player)); - } - - @SuppressWarnings("deprecation") - public static void hideMaze(Maze maze) { - - if(!isMazeVisible(maze)) { - return; - } - - mazeVisibilities.put(maze, false); - Player player = maze.getPlayer(); - - for(MazePoint point : maze.getClip().getBorder()) { - player.sendBlockChange(point, point.getBlock().getType(), point.getBlock().getData()); - } - } - - @SuppressWarnings("deprecation") - public static void showMazeAction(Maze maze, ClipAction action) { - - Player player = maze.getPlayer(); - - for(MazePoint point : action.getRemovedExits()) { - player.sendBlockChange(point, Constants.MAZE_BORDER, (byte) 0); - - if(maze.getExits().indexOf(point) == 0 && maze.getExits().size() > 1) { - player.sendBlockChange(maze.getExits().get(1), Constants.MAZE_MAIN_EXIT, (byte) 0); - } - } - - for(Location point : action.getAddedBorder()) { - player.sendBlockChange(point, Constants.MAZE_BORDER, (byte) 0); - } - - for(Location point : action.getRemovedBorder()) { - player.sendBlockChange(point, point.getBlock().getType(), point.getBlock().getData()); - } - } - - public static void updateChunk(Chunk chunk) { - - for(Maze maze : mazeVisibilities.keySet()) { - - if(!maze.isStarted() || !isMazeVisible(maze) || !maze.getClip().getChunks().contains(chunk)) { - continue; - } - - sendBlocksDelayed(maze.getPlayer(), maze.getClip().getBorder(chunk), Constants.MAZE_BORDER); - } - - for(ClippingTool clipboard : clipVisibilities.keySet()) { - - if(!isClipboardVisible(clipboard) || !clipboard.isComplete() || !clipboard.getClip().getChunks().contains(chunk)) { - continue; - } - - Player player = clipboard.getPlayer(); - - sendBlocksDelayed(player, clipboard.getClip().getBorder(chunk), Constants.CLIPBOARD_BORDER); - sendBlocksDelayed(player, clipboard.getVertices(), Constants.CLIPBOARD_CORNER); - } - } - - @SuppressWarnings("deprecation") - private static void refreshMaze(Player player, ClippingTool clipboard, Maze maze) { - - for(Location vertex : clipboard.getVertices()) { - if(maze.isHighlighted(vertex.getBlock())) { - player.sendBlockChange(vertex, Constants.MAZE_BORDER, (byte) 0); - } - } - - if(!clipboard.isComplete()) { - return; - } - - HashSet mazeBorderChunks = maze.getClip().getBorderChunks(); - - for(Chunk clipBorderChunk : clipboard.getClip().getBorderChunks()) { - - if(!mazeBorderChunks.contains(clipBorderChunk)) - return; - - for(MazePoint borderPoint : clipboard.getClip().getBorder(clipBorderChunk)) { - if(maze.isHighlighted(borderPoint.getBlock())) { - maze.getPlayer().sendBlockChange(borderPoint, Constants.MAZE_BORDER , (byte) 0); - } - } - } - } - - public static void sendBlockDelayed(Player player, Location point, Material mat) { - - new BukkitRunnable() { - - @SuppressWarnings("deprecation") - @Override - public void run() { - player.sendBlockChange(point, mat, (byte) 0); - } - }.runTask(TangledMain.getInstance()); - } - - public static void sendBlocksDelayed(Player player, Collection points, Material mat) { - - BukkitRunnable delay = new BukkitRunnable() { - - @SuppressWarnings("deprecation") - @Override - public void run() { - - for(MazePoint point : points) { - player.sendBlockChange(point, mat, (byte) 0); - } - } - }; - delay.runTask(TangledMain.getInstance()); - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/core/TangledCompleter.java b/src/me/gorgeousone/tangledmaze/core/TangledCompleter.java index 52f4ccb..5f3b604 100644 --- a/src/me/gorgeousone/tangledmaze/core/TangledCompleter.java +++ b/src/me/gorgeousone/tangledmaze/core/TangledCompleter.java @@ -9,26 +9,19 @@ import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; +import me.gorgeousone.tangledmaze.command.MazeCommand; import me.gorgeousone.tangledmaze.data.Constants; public class TangledCompleter implements TabCompleter { - private ArrayList commandNames, selectionTypes; + private List commands; + private List selectionTypes; - public TangledCompleter() { + public TangledCompleter(List commands) { - commandNames = new ArrayList<>(Arrays.asList( - "wand", - "start", - "discard", - "select", - "add", - "cut", - "pathwidth", - "wallheight", - "wallwidth", - "build")); + this.commands = commands; + //TODO find complicated solution to soft code this list selectionTypes = new ArrayList<>(Arrays.asList( "rect", "circle", @@ -39,42 +32,27 @@ public TangledCompleter() { @Override public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { - if(!(sender instanceof Player)) + if(!cmd.getName().equalsIgnoreCase("tangledmaze") || !(sender instanceof Player)) return null; - if(!cmd.getName().equalsIgnoreCase("tangledmaze")) - return null; - - Player p = (Player) sender; + Player player = (Player) sender; - if(!p.hasPermission("tm.build")) + if(!player.hasPermission(Constants.BUILD_PERM)) return null; - ArrayList options = new ArrayList<>(); + + List options = new ArrayList<>(); switch (args.length) { case 1: - if(args[0].equals("")) { - - options.addAll(commandNames); - - if(p.hasPermission(Constants.MAZE_TP_PERM)) - options.add("teleport"); - - }else { - - for(String command : commandNames) { - - if(command.startsWith(args[0].toLowerCase())) { - options.add(command); - return options; - } - } - - if("teleport".startsWith(args[0].toLowerCase()) && p.hasPermission(Constants.MAZE_TP_PERM)) { - options.add("teleport"); - } + for(MazeCommand command : commands) { + + if(!command.getName().startsWith(args[0].toLowerCase())) + continue; + + if(command.getExtraPermission() == null || player.hasPermission(command.getExtraPermission())) + options.add(command.getName()); } break; @@ -82,10 +60,11 @@ public List onTabComplete(CommandSender sender, Command cmd, String labe case 2: if(args[0].equalsIgnoreCase("select")) { + options.addAll(selectionTypes); break; } - + default: break; } diff --git a/src/me/gorgeousone/tangledmaze/core/TangledMain.java b/src/me/gorgeousone/tangledmaze/core/TangledMain.java index d93b06e..355402b 100644 --- a/src/me/gorgeousone/tangledmaze/core/TangledMain.java +++ b/src/me/gorgeousone/tangledmaze/core/TangledMain.java @@ -8,47 +8,34 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; -import me.gorgeousone.tangledmaze.command.AddToMaze; -import me.gorgeousone.tangledmaze.command.BuildMaze; -import me.gorgeousone.tangledmaze.command.CutFromMaze; -import me.gorgeousone.tangledmaze.command.DiscardMaze; -import me.gorgeousone.tangledmaze.command.GiveWand; -import me.gorgeousone.tangledmaze.command.HelpCommand; -import me.gorgeousone.tangledmaze.command.Reload; -import me.gorgeousone.tangledmaze.command.SelectTool; -import me.gorgeousone.tangledmaze.command.SetPathWidth; -import me.gorgeousone.tangledmaze.command.SetWallHeight; -import me.gorgeousone.tangledmaze.command.SetWallWidth; -import me.gorgeousone.tangledmaze.command.StartMaze; -import me.gorgeousone.tangledmaze.command.TpToMaze; -import me.gorgeousone.tangledmaze.data.Constants; -import me.gorgeousone.tangledmaze.data.Messages; -import me.gorgeousone.tangledmaze.data.Settings; -import me.gorgeousone.tangledmaze.handler.MazeCommandHandler; -import me.gorgeousone.tangledmaze.listener.BlockUpdateListener; -import me.gorgeousone.tangledmaze.listener.PlayerListener; -import me.gorgeousone.tangledmaze.listener.ToolActionListener; +import me.gorgeousone.tangledmaze.command.*; +import me.gorgeousone.tangledmaze.data.*; +import me.gorgeousone.tangledmaze.handler.CommandHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; +import me.gorgeousone.tangledmaze.listener.*; public class TangledMain extends JavaPlugin { private static TangledMain plugin; - private MazeCommandHandler commandHandler; + private CommandHandler commandHandler; @Override public void onEnable() { plugin = this; - commandHandler = new MazeCommandHandler(); loadConfig(); + loadLanguage(); Constants.loadConstants(); Settings.loadSettings(getConfig()); - loadLanguage(); registerListeners(); registerCommands(); + + getCommand("tangledmaze").setExecutor(commandHandler); + getCommand("tangledmaze").setTabCompleter(new TangledCompleter(commandHandler.getCommands())); } @Override @@ -71,19 +58,24 @@ public void reloadPlugin() { private void registerCommands() { - commandHandler.registerCommand(new Reload()); + commandHandler = new CommandHandler(); + commandHandler.registerCommand(new HelpCommand()); + commandHandler.registerCommand(new Reload()); commandHandler.registerCommand(new GiveWand()); commandHandler.registerCommand(new StartMaze()); commandHandler.registerCommand(new DiscardMaze()); commandHandler.registerCommand(new SelectTool()); commandHandler.registerCommand(new AddToMaze()); commandHandler.registerCommand(new CutFromMaze()); - commandHandler.registerCommand(new SetPathWidth()); commandHandler.registerCommand(new SetWallWidth()); commandHandler.registerCommand(new SetWallHeight()); + commandHandler.registerCommand(new SetPathWidth()); + commandHandler.registerCommand(new SetPathLength()); commandHandler.registerCommand(new TpToMaze()); commandHandler.registerCommand(new BuildMaze()); + commandHandler.registerCommand(new UnbuildMaze()); + commandHandler.registerCommand(new Undo()); } private void loadConfig() { @@ -95,32 +87,18 @@ private void loadConfig() { private void loadLanguage() { - File langFolder = new File(getDataFolder() + File.separator + "languages"); - File englishFile = new File(langFolder + File.separator + "english.yml"); - YamlConfiguration defEnglish = Utils.getDefaultConfig("english.yml"); + File langFile = new File(getDataFolder() + File.separator + "language.yml"); + YamlConfiguration defLangConfig = Utils.getDefaultConfig("language.yml"); - if(!englishFile.exists()) { - Utils.saveConfig(defEnglish, englishFile); - } - - YamlConfiguration langConfig; - File langFile = new File(langFolder + File.separator + Settings.LANGUAGE + ".yml"); - - if(langFile.exists()) { - - langConfig = YamlConfiguration.loadConfiguration(langFile); - langConfig.setDefaults(defEnglish); - langConfig.options().copyDefaults(true); - - Utils.saveConfig(langConfig, langFile); - getLogger().info("Loaded " + Settings.LANGUAGE + " successfully."); - - }else { - - langConfig = defEnglish; - getLogger().info("Unable to find language file: " + Settings.LANGUAGE + ".yml. Loading default english."); - } + if(!langFile.exists()) + Utils.saveConfig(defLangConfig, langFile); + YamlConfiguration langConfig = YamlConfiguration.loadConfiguration(langFile); + + langConfig.setDefaults(defLangConfig); + langConfig.options().copyDefaults(true); + + Utils.saveConfig(langConfig, langFile); Messages.loadMessages(langConfig); } @@ -131,8 +109,5 @@ private void registerListeners() { manager.registerEvents(new ToolActionListener(), this); manager.registerEvents(new PlayerListener(), this); manager.registerEvents(new BlockUpdateListener(), this); - - getCommand("tangledmaze").setExecutor(commandHandler); - getCommand("tangledmaze").setTabCompleter(new TangledCompleter()); } } diff --git a/src/me/gorgeousone/tangledmaze/data/Constants.java b/src/me/gorgeousone/tangledmaze/data/Constants.java index 4d3b343..06d7d18 100644 --- a/src/me/gorgeousone/tangledmaze/data/Constants.java +++ b/src/me/gorgeousone/tangledmaze/data/Constants.java @@ -1,6 +1,5 @@ package me.gorgeousone.tangledmaze.data; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.file.YamlConfiguration; @@ -12,13 +11,11 @@ public class Constants { - public static int BUKKIT_VERSION; - public static final String INSUFFICIENT_PERMS = ChatColor.RED + "You do not have the Permission for this command.", RELOAD_PERM = "tangledmaze.reload", - BUILD_PERM = "tangledmaze.build", - WAND_PERM = "tangledmaze.getwand", + BUILD_PERM = "tangledmaze.build", + WAND_PERM = "tangledmaze.getwand", MAZE_TP_PERM = "tangledmaze.teleport"; public static final String prefix = @@ -27,10 +24,16 @@ public class Constants { ChatColor.DARK_GREEN + "] " + ChatColor.YELLOW; + public static int + MAX_WALLWIDTH = 255, + MAX_WALLHEIGHT = 255, + MAX_PATHWIDTH = 255, + MAX_PATHLENGTH = 10; + public static final Material - MAZE_BORDER = Material.REDSTONE_BLOCK, - MAZE_MAIN_EXIT = Material.DIAMOND_BLOCK, - MAZE_EXIT = Material.EMERALD_BLOCK, + MAZE_BORDER = Material.REDSTONE_BLOCK, + MAZE_MAIN_EXIT = Material.DIAMOND_BLOCK, + MAZE_EXIT = Material.EMERALD_BLOCK, CLIPBOARD_BORDER = Material.GOLD_BLOCK, CLIPBOARD_CORNER = Material.LAPIS_BLOCK; @@ -53,16 +56,7 @@ public class Constants { @SuppressWarnings("unchecked") public static void loadConstants() { - BUKKIT_VERSION = Integer.valueOf(Bukkit.getBukkitVersion().split("\\.")[1]); - - YamlConfiguration materialLists; - - if(BUKKIT_VERSION < 13) { - materialLists = Utils.getDefaultConfig("1.12_material_lists.yml"); - - }else { - materialLists = Utils.getDefaultConfig("1.13_material_lists.yml"); - } + YamlConfiguration materialLists = Utils.getDefaultConfig("material_lists.yml"); for(String materialName : (List) materialLists.getList("not-solid-materials")) { diff --git a/src/me/gorgeousone/tangledmaze/data/Messages.java b/src/me/gorgeousone/tangledmaze/data/Messages.java index 1ccc20f..e4034f2 100644 --- a/src/me/gorgeousone/tangledmaze/data/Messages.java +++ b/src/me/gorgeousone/tangledmaze/data/Messages.java @@ -16,18 +16,24 @@ public class Messages { COMMAND_ADD_CUT, COMMAND_UNDO, COMMAND_DIMENSIONS, + COMMAND_PATHLENGTH, COMMAND_BUILD, COMMAND_TELEPORT, + COMMAND_UNBUILD, TOOL_RECT, TOOL_CIRCLE, TOOL_BRUSH, TOOL_EXIT, + MESSAGE_PLUGIN_RELOADED, MESSAGE_TOOL_SWITCHED, MESSAGE_TOOL_FOR_MAZE_ONLY, - MESSAGE_PATHWIDTH_CHANGED, MESSAGE_WALLWIDTH_CHANGED, MESSAGE_WALLHEIGHT_CHANGED, + MESSAGE_PATHWIDTH_CHANGED, + MESSAGE_PATHLENGTH_CHANGED, MESSAGE_MAZE_BUILDING_STARTED, + MESSAGE_MAZE_UNBUILDING_STARTED, + MESSAGE_NO_MAZE_TO_UNBUILD, ERROR_NO_BUILD_PERMISSION, ERROR_CLIPBOARD_NOT_STARTED, ERROR_CLIPBOARD_NOT_FINISHED, @@ -37,7 +43,7 @@ public class Messages { ERROR_NO_MAZE_EXIT_SET, ERROR_NO_BUILD_BLOCKS_SPECIFIED, ERROR_NO_MATCHING_BLOCK_TYPE, - ERROR_NUMBER_NOT_VALID; + ERROR_INVALID_NUMBER; public static void loadMessages(FileConfiguration langConfig) { @@ -48,11 +54,13 @@ public static void loadMessages(FileConfiguration langConfig) { COMMAND_START = new TextMessage(ChatColor.DARK_GREEN + "/maze start\n" + ChatColor.GREEN + helpPages.getString("start-command"), true); COMMAND_DISCARD = new TextMessage(ChatColor.DARK_GREEN + "/maze discard\n"+ ChatColor.GREEN + helpPages.getString("discard-command"), true); COMMAND_SELECT = new TextMessage(ChatColor.DARK_GREEN + "/maze select \n" + ChatColor.GREEN + helpPages.getString("select-command"), true); - COMMAND_ADD_CUT = new TextMessage(ChatColor.DARK_GREEN + "/maze add / cut" + ChatColor.GREEN + helpPages.getString("add-cut-command"), true); + COMMAND_ADD_CUT = new TextMessage(ChatColor.DARK_GREEN + "/maze add / cut\n" + ChatColor.GREEN + helpPages.getString("add-cut-command"), true); COMMAND_UNDO = new TextMessage(ChatColor.DARK_GREEN + "/maze undo\n" + ChatColor.GREEN + helpPages.getString("undo-command"), true); COMMAND_DIMENSIONS = new TextMessage(ChatColor.DARK_GREEN + "/maze pathwidth / wallwidth / wallheight \n" + ChatColor.GREEN + helpPages.getString("pathwidth-wallwidth-wallheight-command"), true); + COMMAND_PATHLENGTH = new TextMessage(ChatColor.DARK_GREEN + "/maze pathlength \n" + ChatColor.GREEN + helpPages.getString("pathlength-command"), true); COMMAND_BUILD = new TextMessage(ChatColor.DARK_GREEN + "/maze build ...\n" + ChatColor.GREEN + helpPages.getString("build-command"), true); COMMAND_TELEPORT = new TextMessage(ChatColor.DARK_GREEN + "/maze teleport\n" + ChatColor.GREEN + helpPages.getString("teleport-command"), true); + COMMAND_UNBUILD = new TextMessage(ChatColor.DARK_GREEN + "/maze unbuild\n" + ChatColor.GREEN + helpPages.getString("unbuild-command"), true); ConfigurationSection tools = helpPages.getConfigurationSection("tools"); @@ -63,67 +71,28 @@ public static void loadMessages(FileConfiguration langConfig) { ConfigurationSection messages = langConfig.getConfigurationSection("messages"); - MESSAGE_TOOL_SWITCHED = new TextMessage(Constants.prefix + messages.getString("tool-switched"), false); - MESSAGE_TOOL_FOR_MAZE_ONLY = new TextMessage(Constants.prefix + messages.getString("tool-for-floor-plan-only"), false); - MESSAGE_PATHWIDTH_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-pathwidth-changed"), false); - MESSAGE_WALLWIDTH_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-wallwidth-changed"), false); - MESSAGE_WALLHEIGHT_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-wallheight-changed"), false); - MESSAGE_MAZE_BUILDING_STARTED = new TextMessage(Constants.prefix + messages.getString("maze-building-started"), false); + MESSAGE_PLUGIN_RELOADED = new TextMessage(Constants.prefix + messages.getString("plugin-reloaded"), false); + MESSAGE_TOOL_SWITCHED = new TextMessage(Constants.prefix + messages.getString("tool-switched"), false); + MESSAGE_TOOL_FOR_MAZE_ONLY = new TextMessage(Constants.prefix + messages.getString("tool-for-floor-plan-only"), false); + MESSAGE_WALLWIDTH_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-wallwidth-changed"), false); + MESSAGE_WALLHEIGHT_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-wallheight-changed"), false); + MESSAGE_PATHWIDTH_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-pathwidth-changed"), false); + MESSAGE_PATHLENGTH_CHANGED = new TextMessage(Constants.prefix + messages.getString("maze-pathlength-changed"), false); + MESSAGE_MAZE_BUILDING_STARTED = new TextMessage(Constants.prefix + messages.getString("maze-building-started"), false); + MESSAGE_MAZE_UNBUILDING_STARTED = new TextMessage(Constants.prefix + messages.getString("maze-unbuilding-started"), false); + MESSAGE_NO_MAZE_TO_UNBUILD = new TextMessage(Constants.prefix + messages.getString("no-maze-to-unbuild"), false); ConfigurationSection errors = langConfig.getConfigurationSection("errors"); - ERROR_NO_BUILD_PERMISSION = new TextMessage(ChatColor.RED + errors.getString("insufficient-permission"), false); - ERROR_CLIPBOARD_NOT_STARTED = new TextMessage(ChatColor.RED + errors.getString("clipboard-not-started"), false); - ERROR_CLIPBOARD_NOT_FINISHED = new TextMessage(ChatColor.RED + errors.getString("clipboard-not-finished"), false); - ERROR_MAZE_NOT_STARTED = new TextMessage(ChatColor.RED + errors.getString("maze-not-started"), false); + ERROR_NO_BUILD_PERMISSION = new TextMessage(ChatColor.RED + errors.getString("insufficient-permission"), false); + ERROR_CLIPBOARD_NOT_STARTED = new TextMessage(ChatColor.RED + errors.getString("clipboard-not-started"), false); + ERROR_CLIPBOARD_NOT_FINISHED = new TextMessage(ChatColor.RED + errors.getString("clipboard-not-finished"), false); + ERROR_MAZE_NOT_STARTED = new TextMessage(ChatColor.RED + errors.getString("maze-not-started"), false); ERROR_CLIPBOARD_NOT_TOUCHING_MAZE = new TextMessage(ChatColor.RED + errors.getString("clipboard-not-touching-maze"), false); - ERROR_NO_MAZE_BORDER_CLICKED = new TextMessage(ChatColor.GRAY + "" + ChatColor.ITALIC + errors.getString("no-maze-border-clicked"), false); - ERROR_NO_MAZE_EXIT_SET = new TextMessage(ChatColor.RED + errors.getString("no-maze-exit-set"), false); - ERROR_NO_BUILD_BLOCKS_SPECIFIED = new TextMessage(ChatColor.RED + errors.getString("no-build-blocks-specified"), false); - ERROR_NO_MATCHING_BLOCK_TYPE = new TextMessage(ChatColor.RED + errors.getString("argument-not-matching-block"), false); - ERROR_NUMBER_NOT_VALID = new TextMessage(ChatColor.RED + errors.getString("number-not-valid"), false); - } - - public static void reloadMessages(FileConfiguration langConfig) { - - ConfigurationSection helpPages = langConfig.getConfigurationSection("help-pages"); - - COMMAND_WAND.setText(ChatColor.GREEN + helpPages.getString("wand-command") , false); - COMMAND_START.setText(ChatColor.GREEN + helpPages.getString("start-command"), true); - COMMAND_DISCARD.setText(ChatColor.GREEN + helpPages.getString("discard-command"), true); - COMMAND_SELECT.setText(ChatColor.GREEN + helpPages.getString("select-command"), true); - COMMAND_ADD_CUT.setText(ChatColor.GREEN + helpPages.getString("add-cut-command"), true); - COMMAND_UNDO.setText(ChatColor.GREEN + helpPages.getString("undo-command"), true); - COMMAND_DIMENSIONS.setText(ChatColor.GREEN + helpPages.getString("pathwidth-wallwidth-wallheight-command"), true); - COMMAND_BUILD.setText(ChatColor.GREEN + helpPages.getString("build-command"), true); - COMMAND_TELEPORT.setText(ChatColor.GREEN + helpPages.getString("teleport-command"), true); - - ConfigurationSection tools = helpPages.getConfigurationSection("tools"); - - TOOL_RECT.setText(ChatColor.GREEN + tools.getString("rectangle"), false); - TOOL_CIRCLE.setText(ChatColor.GREEN + tools.getString("circle"), false); - TOOL_BRUSH.setText(ChatColor.GREEN + tools.getString("brush"), false); - TOOL_EXIT.setText(ChatColor.GREEN + tools.getString("exit"), false); - - ConfigurationSection messages = langConfig.getConfigurationSection("messages"); - - MESSAGE_TOOL_SWITCHED.setText(Constants.prefix + messages.getString("tool-switched"), false); - MESSAGE_TOOL_FOR_MAZE_ONLY.setText(Constants.prefix + messages.getString("tool-for-floor-plan-only"), false); - MESSAGE_PATHWIDTH_CHANGED.setText(Constants.prefix + messages.getString("maze-pathwidth-changed"), false); - MESSAGE_WALLWIDTH_CHANGED.setText(Constants.prefix + messages.getString("maze-wallwidth-changed"), false); - MESSAGE_WALLHEIGHT_CHANGED.setText(Constants.prefix + messages.getString("maze-wallheight-changed"), false); - MESSAGE_MAZE_BUILDING_STARTED.setText(Constants.prefix + messages.getString("maze-building-started"), false); - - ConfigurationSection errors = langConfig.getConfigurationSection("errors"); - - ERROR_NO_BUILD_PERMISSION.setText(ChatColor.RED + errors.getString("insufficient-permission"), false); - ERROR_CLIPBOARD_NOT_STARTED.setText(ChatColor.RED + errors.getString("clipboard-not-started"), false); - ERROR_CLIPBOARD_NOT_FINISHED.setText(ChatColor.RED + errors.getString("clipboard-not-finished"), false); - ERROR_MAZE_NOT_STARTED.setText(ChatColor.RED + errors.getString("maze-not-started"), false); - ERROR_CLIPBOARD_NOT_TOUCHING_MAZE.setText(ChatColor.RED + errors.getString("no-maze-border-clicke"), false); - ERROR_NO_MAZE_EXIT_SET.setText(ChatColor.RED + errors.getString("no-maze-exit-set"), false); - ERROR_NO_BUILD_BLOCKS_SPECIFIED.setText(ChatColor.RED + errors.getString("no-build-blocks-specified"), false); - ERROR_NO_MATCHING_BLOCK_TYPE.setText(ChatColor.RED + errors.getString("argument-not-matching-block"), false); - ERROR_NUMBER_NOT_VALID.setText(ChatColor.RED + errors.getString("number-not-valid"), false); + ERROR_NO_MAZE_BORDER_CLICKED = new TextMessage(ChatColor.GRAY + "" + ChatColor.ITALIC + errors.getString("no-maze-border-clicked"), false); + ERROR_NO_MAZE_EXIT_SET = new TextMessage(ChatColor.RED + errors.getString("no-maze-exit-set"), false); + ERROR_NO_BUILD_BLOCKS_SPECIFIED = new TextMessage(ChatColor.RED + errors.getString("no-build-blocks-specified"), false); + ERROR_NO_MATCHING_BLOCK_TYPE = new TextMessage(ChatColor.RED + errors.getString("argument-not-matching-block"), false); + ERROR_INVALID_NUMBER = new TextMessage(ChatColor.RED + errors.getString("invalid-number"), false); } -} +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/data/Settings.java b/src/me/gorgeousone/tangledmaze/data/Settings.java index e939ce2..2ece549 100644 --- a/src/me/gorgeousone/tangledmaze/data/Settings.java +++ b/src/me/gorgeousone/tangledmaze/data/Settings.java @@ -10,50 +10,26 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import me.gorgeousone.tangledmaze.util.MaterialReader; -import me.gorgeousone.tangledmaze.util.Utils; - public final class Settings { - public static String LANGUAGE; - public static ItemStack MAZE_WAND; - public static Material MAZE_WAND_ITEM; + public static Material MAZE_WAND_MATERIAL; - public static int - MAX_PATHWIDTH, - MAX_WALLWIDTH, - MAX_WALLHEIGHT; - private Settings() {} public static void loadSettings(FileConfiguration config) { - LANGUAGE = config.getString("language", "english"); - - MAX_PATHWIDTH = Utils.limitInt(config.getInt("maze.maximum-pathwidth", 50), 1, 255); - MAX_WALLWIDTH = Utils.limitInt(config.getInt("maze.maximum-wallwidth", 50), 1, 255); - MAX_WALLHEIGHT = Utils.limitInt(config.getInt("maze.maximum-wallheight", 100), 1, 255); - - MAZE_WAND_ITEM = MaterialReader.readMaterial(config.getString("wand-item")); - - if(MAZE_WAND_ITEM != null) { - return; - } - - if(Constants.BUKKIT_VERSION < 13) { - MAZE_WAND_ITEM = Material.valueOf("GOLD_SPADE"); + MAZE_WAND_MATERIAL = Material.matchMaterial(config.getString("wand-item")); - }else { - MAZE_WAND_ITEM = Material.GOLDEN_SHOVEL; - } + if(MAZE_WAND_MATERIAL == null) + MAZE_WAND_MATERIAL = Material.GOLDEN_SHOVEL; createMazeWand(); } private static void createMazeWand() { - MAZE_WAND = new ItemStack(Settings.MAZE_WAND_ITEM); + MAZE_WAND = new ItemStack(Settings.MAZE_WAND_MATERIAL); ItemMeta meta = MAZE_WAND.getItemMeta(); meta.setDisplayName(ChatColor.DARK_GREEN + "Maze Wand"); diff --git a/src/me/gorgeousone/tangledmaze/event/MazeBuildEvent.java b/src/me/gorgeousone/tangledmaze/event/MazeBuildEvent.java deleted file mode 100644 index 3cb4787..0000000 --- a/src/me/gorgeousone/tangledmaze/event/MazeBuildEvent.java +++ /dev/null @@ -1,59 +0,0 @@ -package me.gorgeousone.tangledmaze.event; - -import me.gorgeousone.tangledmaze.core.Maze; -import me.gorgeousone.tangledmaze.core.TangledMain; -import me.gorgeousone.tangledmaze.generation.MazeGenerator; -import me.gorgeousone.tangledmaze.handler.MazeHandler; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.bukkit.scheduler.BukkitRunnable; - -public class MazeBuildEvent extends Event implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - private boolean isCancelled; - - private Maze maze; - private MazeGenerator generator; - - public MazeBuildEvent(Maze maze, MazeGenerator generator) { - - this.maze = maze; - this.generator = generator; - - new BukkitRunnable() { - @Override - public void run() { - - if(!isCancelled) { - System.out.println(MazeBuildEvent.this.maze); - MazeHandler.buildMaze(MazeBuildEvent.this.maze, generator); - } - } - }.runTask(TangledMain.getInstance()); - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - - @Override - public void setCancelled(boolean b) { - isCancelled = b; - } - - public MazeGenerator getMazeGeneraor() { - return generator; - } - - public void setExitGenerator(MazeGenerator generator) { - this.generator = generator; - } -} diff --git a/src/me/gorgeousone/tangledmaze/generation/BlockGenerator.java b/src/me/gorgeousone/tangledmaze/generation/BlockGenerator.java index f84d9f6..c4063aa 100644 --- a/src/me/gorgeousone/tangledmaze/generation/BlockGenerator.java +++ b/src/me/gorgeousone/tangledmaze/generation/BlockGenerator.java @@ -1,12 +1,14 @@ package me.gorgeousone.tangledmaze.generation; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.block.BlockState; -import org.bukkit.material.MaterialData; import org.bukkit.scheduler.BukkitRunnable; import me.gorgeousone.tangledmaze.core.Maze; @@ -15,28 +17,67 @@ import me.gorgeousone.tangledmaze.util.Utils; import me.gorgeousone.tangledmaze.util.Vec2; -@SuppressWarnings("deprecation") public class BlockGenerator { + + private Random rnd; - public void generateBlocks(BuildMap map) { + public BlockGenerator() { + rnd = new Random(); + } + + public void generateBlocks(BuildMap buildMap) { - simplifyMap(map); - flattenTrees(map); - raiseLowMapParts(map); + cullTrees(buildMap); + raiseTooLowWalls(buildMap); new BukkitRunnable() { @Override public void run() { - buildBlocksContinuously(getMazeBlocks(map)); + listMazeWallBlocks(buildMap); } }.runTask(TangledMain.getInstance()); } - protected void buildBlocksContinuously(List blocksToUpdate) { + private void listMazeWallBlocks(BuildMap buildMap) { + + Maze maze = buildMap.getMaze(); + + List wallMaterials = maze.getWallMaterials(); + List blocksToUpdate = new ArrayList<>(); + List backupBlocks = new ArrayList<>(); + + for(int x = buildMap.getMinX(); x < buildMap.getMaxX(); x++) { + for(int z = buildMap.getMinZ(); z < buildMap.getMaxZ(); z++) { + + if(buildMap.getType(x, z) != MazeFillType.WALL) + continue; + + for(int height = buildMap.getGroundHeight(x, z) + 1; height <= buildMap.getMazeHeight(x, z); height++) { + + Block block = new Location(maze.getWorld(), x, height, z).getBlock(); + + if(Utils.canBeOverbuild(block.getType())) { + + Material rndMaterial = wallMaterials.get(rnd.nextInt(wallMaterials.size())); + + BlockState blockToUpdate = block.getState(); + blockToUpdate.setType(rndMaterial); + + blocksToUpdate.add(blockToUpdate); + backupBlocks.add(block.getState()); + } + } + } + } + + maze.setConstructedBlocks(backupBlocks); + updateBlocksContinuously(blocksToUpdate, null); + } + + public void updateBlocksContinuously(List blocksToUpdate, ActionListener callback) { BukkitRunnable builder = new BukkitRunnable() { - @Override public void run() { @@ -52,132 +93,77 @@ public void run() { } this.cancel(); - } - }; - builder.runTaskTimer(TangledMain.getInstance(), 0, 1); - } - - protected List getMazeBlocks(BuildMap map) { - - Maze maze = map.getMaze(); - Random rnd = new Random(); - - List composition = maze.getWallComposition(); - List blocksToUpdate = new ArrayList<>(); - - int mazeMinX = map.getMinX(), - mazeMinZ = map.getMinZ(); - - for(int x = 0; x < map.getDimX(); x++) { - for(int z = 0; z < map.getDimZ(); z++) { - if(map.getType(x, z) != MazeFillType.WALL) { - continue; - } - - for(int i = map.getGroundHeight(x, z) + 1; i <= map.getMazeHeight(x, z); i++) { - - BlockState block = new Location(maze.getWorld(), x + mazeMinX, i, z + mazeMinZ).getBlock().getState(); - - if(!Utils.canBeOverbuild(block.getType())) { - continue; - } - - MaterialData rndMatData = composition.get(rnd.nextInt(composition.size())); - - block.setType(rndMatData.getItemType()); - block.setRawData(rndMatData.getData()); - blocksToUpdate.add(block); - } + if(callback != null) + callback.actionPerformed(null); } - } - - return blocksToUpdate; - } - - protected void simplifyMap(BuildMap map) { + }; - for(int x = 0; x < map.getDimX(); x++) { - for(int z = 0; z < map.getDimZ(); z++) { - - MazeFillType type = map.getType(x, z); - - if(type == MazeFillType.UNDEFINED) { - map.setType(x, z, MazeFillType.WALL); - - }else if(type == MazeFillType.EXIT) { - map.setType(x, z, MazeFillType.PATH); - } - } - } + builder.runTaskTimer(TangledMain.getInstance(), 0, 1); } - protected void flattenTrees(BuildMap map) { + //lowers wall heights at points where spikes of wall would stick out of the maze + private void cullTrees(BuildMap buildMap) { - int wallHeight = map.getMaze().getWallHeight(); + int wallHeight = buildMap.getMaze().getWallHeight(); - for(int x = 0; x < map.getDimX(); x++) { - for(int z = 0; z < map.getDimZ(); z++) { + for(int x = buildMap.getMinX(); x < buildMap.getMaxX(); x++) { + for(int z = buildMap.getMinZ(); z < buildMap.getMaxZ(); z++) { - if(map.getType(x, z) == MazeFillType.NOT_MAZE) { + if(buildMap.getType(x, z) == MazeFillType.NOT_MAZE) continue; - } - Vec2 maxNeighbor = getHeighestNeighbor(x, z, map, null); + Vec2 maxNeighbor = getHeighestNeighbor(x, z, buildMap, null); - int mazeHeight = map.getMazeHeight(x, z), - minimumMazeHeight = map.getGroundHeight(maxNeighbor) + wallHeight; + int mazeHeight = buildMap.getMazeHeight(x, z); + int defaultMazeHeight = buildMap.getGroundHeight(maxNeighbor) + wallHeight; - if(mazeHeight <= minimumMazeHeight) { + if(mazeHeight <= defaultMazeHeight) continue; - } - int groundHeightDiff = getNeighborGroundHeightDiff(map, x, z); + int groundDiffToNeighbors = getGroundDiffToNeighbors(buildMap, x, z); - if(map.getType(x, z) == MazeFillType.PATH) { - map.setGroundHeight(x, z, map.getGroundHeight(x, z) + groundHeightDiff); - - }else { - map.setMazeHeight(x, z, Math.min(minimumMazeHeight, mazeHeight + groundHeightDiff)); - } + //adapt ground height of path points to surrounding ground height + if(buildMap.getType(x, z) == MazeFillType.PATH) + buildMap.setGroundHeight(x, z, buildMap.getGroundHeight(x, z) + groundDiffToNeighbors); + //adapt wall height of wall points to default wall height or neighbor wall heights + else + buildMap.setMazeHeight(x, z, Math.min(defaultMazeHeight, mazeHeight + groundDiffToNeighbors)); } } } - protected void raiseLowMapParts(BuildMap map) { + //raises walls with a low height to surrounding paths + private void raiseTooLowWalls(BuildMap buildMap) { - int wallHeight = map.getMaze().getWallHeight(); + int wallHeight = buildMap.getMaze().getWallHeight(); - for(int x = 0; x < map.getDimX(); x++) { - for(int z = 0; z < map.getDimZ(); z++) { + for(int x = buildMap.getMinX(); x < buildMap.getMaxX(); x++) { + for(int z = buildMap.getMinZ(); z < buildMap.getMaxZ(); z++) { - if(map.getType(x, z) == MazeFillType.NOT_MAZE) { + if(buildMap.getType(x, z) == MazeFillType.NOT_MAZE) continue; - } - Vec2 maxNeighbor = getHeighestNeighbor(x, z, map, MazeFillType.PATH); + Vec2 maxNeighbor = getHeighestNeighbor(x, z, buildMap, MazeFillType.PATH); - if(maxNeighbor == null) { + if(maxNeighbor == null) continue; - } - int maxNeighborsWallHeight = map.getWallHeight(maxNeighbor); + int maxNeighborsWallHeight = buildMap.getWallHeight(maxNeighbor); - if(maxNeighborsWallHeight <= 0) { + if(maxNeighborsWallHeight <= 0) continue; - } - int mazeHeight = map.getGroundHeight(x, z), - maxNeighborsGroundHeight = map.getGroundHeight(maxNeighbor); + int mazeHeight = buildMap.getMazeHeight(x, z), + maxNeighborsGroundHeight = buildMap.getGroundHeight(maxNeighbor); - if(mazeHeight < maxNeighborsGroundHeight + wallHeight) { - map.setMazeHeight(x, z, maxNeighborsGroundHeight + wallHeight); - } + if(mazeHeight < maxNeighborsGroundHeight + wallHeight) + buildMap.setMazeHeight(x, z, maxNeighborsGroundHeight + wallHeight); } } } - protected Vec2 getHeighestNeighbor(int x, int z, BuildMap map, MazeFillType limitation) { + private Vec2 getHeighestNeighbor(int x, int z, BuildMap buildMap, MazeFillType limitation) { Vec2 maxNeighbor = null; int maxHeight = 0; @@ -186,17 +172,15 @@ protected Vec2 getHeighestNeighbor(int x, int z, BuildMap map, MazeFillType limi Vec2 neighbor = new Vec2(x, z).add(dir.toVec2()); - if(neighbor.getIntX() < 0 || neighbor.getIntX() >= map.getDimX() || - neighbor.getIntZ() < 0 || neighbor.getIntZ() >= map.getDimZ()) { + if(!buildMap.contains(neighbor)) continue; - } - if(map.getType(neighbor) == MazeFillType.NOT_MAZE || limitation != null && - map.getType(neighbor) != limitation) { + if(buildMap.getType(neighbor) == MazeFillType.NOT_MAZE || limitation != null && + buildMap.getType(neighbor) != limitation) { continue; } - int neighborHeight = map.getMazeHeight(neighbor); + int neighborHeight = buildMap.getMazeHeight(neighbor); if(maxNeighbor == null || neighborHeight > maxHeight) { maxNeighbor = neighbor; @@ -207,23 +191,20 @@ protected Vec2 getHeighestNeighbor(int x, int z, BuildMap map, MazeFillType limi return maxNeighbor; } - protected int getNeighborGroundHeightDiff(BuildMap map, int x, int z) { + private int getGroundDiffToNeighbors(BuildMap buildMap, int x, int z) { - int groundHeight = map.getGroundHeight(x, z), - heightDiff = 0, - neighborsCount = 0; + int groundHeight = buildMap.getGroundHeight(x, z); + int heightDiff = 0; + int neighborsCount = 0; for(Directions dir : Directions.values()) { Vec2 neighbor = new Vec2(x, z).add(dir.toVec2()); - if(neighbor.getIntX() < 0 || neighbor.getIntX() >= map.getDimX() || - neighbor.getIntZ() < 0 || neighbor.getIntZ() >= map.getDimZ() || - map.getType(neighbor) == MazeFillType.NOT_MAZE) { + if(!buildMap.contains(neighbor) || buildMap.getType(neighbor) == MazeFillType.NOT_MAZE) continue; - } - heightDiff += map.getGroundHeight(neighbor) - groundHeight; + heightDiff += buildMap.getGroundHeight(neighbor) - groundHeight; neighborsCount++; } diff --git a/src/me/gorgeousone/tangledmaze/generation/BuildMap.java b/src/me/gorgeousone/tangledmaze/generation/BuildMap.java index f0615ec..00103ec 100644 --- a/src/me/gorgeousone/tangledmaze/generation/BuildMap.java +++ b/src/me/gorgeousone/tangledmaze/generation/BuildMap.java @@ -1,11 +1,10 @@ package me.gorgeousone.tangledmaze.generation; -import java.util.HashSet; - -import org.bukkit.Chunk; +import java.util.Map.Entry; +import me.gorgeousone.tangledmaze.clip.Clip; import me.gorgeousone.tangledmaze.core.Maze; -import me.gorgeousone.tangledmaze.util.MazePoint; +import me.gorgeousone.tangledmaze.generation.path.PathSegment; import me.gorgeousone.tangledmaze.util.Vec2; public class BuildMap { @@ -14,7 +13,7 @@ public class BuildMap { private MazeFillType[][] shapeMap; private int[][] groundHeightMap, mazeHeightMap; - private Vec2 minimum; + private Vec2 minimum, maximum; private Vec2 pathStart; public BuildMap(Maze maze) { @@ -22,7 +21,7 @@ public BuildMap(Maze maze) { this.maze = maze; calculateMapSize(); - drawBlankMazeOnMap(); + copyMazeOntoMap(); } public Maze getMaze() { @@ -30,181 +29,197 @@ public Maze getMaze() { } public int getMinX() { - return minimum.getIntX(); + return minimum.getX(); } public int getMinZ() { - return minimum.getIntZ(); + return minimum.getZ(); } - public int getDimX() { - return shapeMap.length; + public int getMaxX() { + return maximum.getX(); + } + + public int getMaxZ() { + return maximum.getZ(); } - public int getDimZ() { - return shapeMap[0].length; + public boolean contains(Vec2 point) { + return + point.getX() >= getMinX() && point.getX() < getMaxX() && + point.getZ() >= getMinZ() && point.getZ() < getMaxZ(); } - + public MazeFillType getType(int x, int z) { - return shapeMap[x][z]; + return shapeMap[x-getMinX()][z-getMinZ()]; + } + + public MazeFillType getType(Vec2 point) { + return getType(point.getX(), point.getZ()); } public int getGroundHeight(int x, int z) { - return groundHeightMap[x][z]; + return groundHeightMap[x-getMinX()][z-getMinZ()]; } public int getGroundHeight(Vec2 point) { - return groundHeightMap[point.getIntX()][point.getIntZ()]; + return getGroundHeight(point.getX(), point.getZ()); } public int getMazeHeight(int x, int z) { - return mazeHeightMap[x][z]; + return mazeHeightMap[x-getMinX()][z-getMinZ()]; } public int getMazeHeight(Vec2 point) { - return mazeHeightMap[point.getIntX()][point.getIntZ()]; + return getMazeHeight(point.getX(), point.getZ()); } public int getWallHeight(Vec2 point) { return getMazeHeight(point) - getGroundHeight(point); } - public MazeFillType getType(Vec2 point) { - return shapeMap[point.getIntX()][point.getIntZ()]; - } - public Vec2 getStart() { return pathStart; } + public void setType(int x, int z, MazeFillType type) { + shapeMap[x-getMinX()][z-getMinZ()] = type; + } + + public void setType(Vec2 point, MazeFillType type) { + setType(point.getX(), point.getZ(), type); + } + public void setGroundHeight(int x, int z, int newY) { - groundHeightMap[x][z] = newY; + groundHeightMap[x-getMinX()][z-getMinZ()] = newY; } public void setGroundHeight(Vec2 point, int newY) { - setGroundHeight(point.getIntX(), point.getIntZ(), newY); + setGroundHeight(point.getX(), point.getZ(), newY); } public void setMazeHeight(int x, int z, int newY) { - mazeHeightMap[x][z] = newY; + mazeHeightMap[x-getMinX()][z-getMinZ()] = newY; } public void setMazeHeight(Vec2 point, int newY) { - setMazeHeight(point.getIntX(), point.getIntZ(), newY); - } - - public void setType(int x, int z, MazeFillType type) { - shapeMap[x][z] = type; - } - - public void setType(Vec2 point, MazeFillType type) { - shapeMap[point.getIntX()] - [point.getIntZ()] = type; + setMazeHeight(point.getX(), point.getZ(), newY); } - + public void setStart(Vec2 pathStart) { this.pathStart = pathStart; } - public void drawSegment(PathSegment segment, MazeFillType type) { + public void mapSegment(PathSegment segment, MazeFillType type) { for(Vec2 point : segment.getFill()) { - if(point.getIntX() >= 0 && point.getIntX() < getDimX() && - point.getIntZ() >= 0 && point.getIntZ() < getDimZ()) { + if(contains(point)) + setType(point.getX(), point.getZ(), type); + } + } + + public void flip() { + + for(int x = getMinX(); x < getMaxX(); x++) { + for(int z = getMinZ(); z < getMaxZ(); z++) { - setType(point, type); + MazeFillType fillType = getType(x, z); + + if(fillType == MazeFillType.UNDEFINED) + setType(x, z, MazeFillType.WALL); + + else if(fillType == MazeFillType.EXIT) + setType(x, z, MazeFillType.PATH); } } } + //TODO overthink map size calculation private void calculateMapSize() { - HashSet chunks = maze.getClip().getChunks(); - - minimum = getMinPoint(chunks); - Vec2 max = getMaxPoint(chunks); - - shapeMap = new MazeFillType - [max.getIntX() - minimum.getIntX()] - [max.getIntZ() - minimum.getIntZ()]; + minimum = getMinLoc(); + maximum = getMaxLoc(); + + shapeMap = new MazeFillType + [maximum.getX() - minimum.getX()] + [maximum.getZ() - minimum.getZ()]; groundHeightMap = new int - [max.getIntX() - minimum.getIntX()] - [max.getIntZ() - minimum.getIntZ()]; + [maximum.getX() - minimum.getX()] + [maximum.getZ() - minimum.getZ()]; mazeHeightMap = new int - [max.getIntX() - minimum.getIntX()] - [max.getIntZ() - minimum.getIntZ()]; + [maximum.getX() - minimum.getX()] + [maximum.getZ() - minimum.getZ()]; } - private void drawBlankMazeOnMap() { - - int wallHeight = maze.getWallHeight(); + private void copyMazeOntoMap() { - for(int x = 0; x < getDimX(); x++) { - for(int z = 0; z < getDimZ(); z++) { - shapeMap[x][z] = MazeFillType.NOT_MAZE; + for(int x = getMinX(); x < getMaxX(); x++) { + for(int z = getMinZ(); z < getMaxZ(); z++) { + setType(x, z, MazeFillType.NOT_MAZE); } } + int wallHeight = maze.getWallHeight(); + Clip clip = maze.getClip(); + //mark the maze's area in mazeMap as undefined area (open for paths and walls) - for(MazePoint point : maze.getClip().getFilling()) { + for(Entry loc : clip.getFillSet()) { - shapeMap [point.getBlockX() - getMinX()][point.getBlockZ() - getMinZ()] = MazeFillType.UNDEFINED; - groundHeightMap[point.getBlockX() - getMinX()][point.getBlockZ() - getMinZ()] = point.getBlockY(); - mazeHeightMap [point.getBlockX() - getMinX()][point.getBlockZ() - getMinZ()] = point.getBlockY() + wallHeight; + setType(loc.getKey(), MazeFillType.UNDEFINED); + setGroundHeight(loc.getKey(), loc.getValue()); + setMazeHeight(loc.getKey(), loc.getValue() + wallHeight); } //mark the border in mazeMap as walls - for(MazePoint point : maze.getClip().getBorder()) { - shapeMap[point.getBlockX() - getMinX()][point.getBlockZ() - getMinZ()] = MazeFillType.WALL; - } + for(Vec2 loc : maze.getClip().getBorder()) + setType(loc, MazeFillType.WALL); } - - private Vec2 getMinPoint(HashSet chunks) { + + private Vec2 getMinLoc() { Vec2 minimum = null; +// Vec2 maximum = null; - for(Chunk chunk : chunks) { + for(Vec2 loc : maze.getClip().getFill()) { if(minimum == null) { - minimum = new Vec2(chunk.getX(), chunk.getZ()); + + minimum = loc.clone(); +// maximum = loc.clone(); continue; } - if(chunk.getX() < minimum.getX()) { - minimum.setX(chunk.getX()); - } + if(loc.getX() < minimum.getX()) + minimum.setX(loc.getX()); - if(chunk.getZ() < minimum.getZ()) { - minimum.setZ(chunk.getZ()); - } + if(loc.getZ() < minimum.getZ()) + minimum.setZ(loc.getZ()); } - return minimum.mult(16); + return minimum; } - private Vec2 getMaxPoint(HashSet chunks) { + private Vec2 getMaxLoc() { Vec2 maximum = null; - for(Chunk chunk : chunks) { + for(Vec2 chunk : maze.getClip().getFill()) { if(maximum == null) { - maximum = new Vec2(chunk.getX(), chunk.getZ()); + maximum = chunk.clone(); continue; } - if(chunk.getX() > maximum.getX()) { + if(chunk.getX() > maximum.getX()) maximum.setX(chunk.getX()); - } - if(chunk.getZ() > maximum.getZ()) { + if(chunk.getZ() > maximum.getZ()) maximum.setZ(chunk.getZ()); - } } - return maximum.add(1, 1).mult(16); + return maximum.add(1, 1); } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/generation/ExitGenerator.java b/src/me/gorgeousone/tangledmaze/generation/ExitGenerator.java deleted file mode 100644 index 9a0dce2..0000000 --- a/src/me/gorgeousone/tangledmaze/generation/ExitGenerator.java +++ /dev/null @@ -1,132 +0,0 @@ -package me.gorgeousone.tangledmaze.generation; - -import org.bukkit.Location; - -import me.gorgeousone.tangledmaze.core.Maze; -import me.gorgeousone.tangledmaze.util.Directions; -import me.gorgeousone.tangledmaze.util.MazePoint; -import me.gorgeousone.tangledmaze.util.Vec2; - -public class ExitGenerator { - - public void generateExits(BuildMap map) { - - Maze maze = map.getMaze(); - - int pathWidth = maze.getPathWidth(), - wallWidth = maze.getWallWidth(); - - PathSegment mainExit = generateEntrance( - map, - maze.getMainExit().clone(), - pathWidth, - wallWidth); - - Vec2 pathStart = mainExit.getEnd(); - map.setStart(pathStart); - map.drawSegment(mainExit, MazeFillType.PATH); - - if(maze.getExits().size() < 2) { - return; - } - - int pathGridOffsetX = pathStart.getIntX() % (pathWidth + wallWidth), - pathGridOffsetZ = pathStart.getIntZ() % (pathWidth + wallWidth); - - for(int i = 0; i < maze.getExits().size() - 1; i++) { - - generateExit( - map, - maze.getExits().get(i).clone(), - pathWidth, - wallWidth, - pathGridOffsetX, - pathGridOffsetZ); - } - } - - protected PathSegment generateEntrance( - BuildMap map, - MazePoint entrance, - int pathWidth, - int wallWidth) { - - entrance.subtract(map.getMinX(), 0, map.getMinZ()); - - PathSegment entranceSegment = new PathSegment( - new Vec2(entrance.toVector()), - getExitsFacing(entrance, map).toVec2(), - wallWidth + pathWidth, - pathWidth, - true); - - return entranceSegment; - } - - protected void generateExit( - BuildMap map, - MazePoint exit, - int pathWidth, - int wallWidth, - int pathGridOffsetX, - int pathGridOffsetZ) { - - exit.subtract(map.getMinX(), 0, map.getMinZ()); - Vec2 facing = getExitsFacing(exit, map).toVec2(); - - PathSegment exitSegment = new PathSegment( - new Vec2(exit.toVector()), - facing, - pathWidth, - pathWidth, - true); - - //TODO normal - check if maze exits are placed correctly, maybe there is a bug - - //calculate calculate how long the exit has to be to reach the path grid - int exitOffset; - - //start with getting the exits position relative to the path grid - if(facing.getIntX() != 0) { - exitOffset = exitSegment.getStart().getIntX() - pathGridOffsetX; - }else { - exitOffset = exitSegment.getStart().getIntZ() - pathGridOffsetZ; - } - - //reduce the relative position to the actual possible offset - if(Math.abs(exitOffset) > pathWidth + wallWidth) { - exitOffset %= pathWidth + wallWidth; - } - - //invert offset if the exit's facing is not along with the grid's facing (simply -x or -z) - if(facing.getIntX() == 1 || facing.getIntZ() == 1) { - exitOffset = (pathWidth + wallWidth) - exitOffset; - } - - //get rid off negative values - if(exitOffset <= 0) { - exitOffset += pathWidth + wallWidth; - } - - exitSegment.expand(exitOffset); - map.drawSegment(exitSegment, MazeFillType.EXIT); - } - - protected Directions getExitsFacing(Location exit, BuildMap map) { - - for(Directions dir : Directions.cardinalValues()) { - - Vec2 nextToExit = new Vec2(exit.toVector()); - nextToExit.add(dir.toVec2()); - - if(nextToExit.getIntX() < 0 || nextToExit.getIntX() >= map.getDimX() || - nextToExit.getIntZ() < 0 || nextToExit.getIntZ() >= map.getDimZ()) - continue; - - if(map.getType(nextToExit) == MazeFillType.UNDEFINED) - return dir; - } - - return null; - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/generation/MazeGenerator.java b/src/me/gorgeousone/tangledmaze/generation/MazeGenerator.java deleted file mode 100644 index 4cd5fac..0000000 --- a/src/me/gorgeousone/tangledmaze/generation/MazeGenerator.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.gorgeousone.tangledmaze.generation; - -import me.gorgeousone.tangledmaze.core.Maze; - -public class MazeGenerator { - - private ExitGenerator exitGenerator; - private PathGenerator pathGenerator; - private BlockGenerator blockGenerator; - - public MazeGenerator() { - - exitGenerator = new ExitGenerator(); - pathGenerator = new PathGenerator(); - blockGenerator = new BlockGenerator(); - } - - public void buildMaze(Maze maze) { - - BuildMap map = new BuildMap(maze); - exitGenerator.generateExits(map); - pathGenerator.generatePaths(map); - blockGenerator.generateBlocks(map); - } -} diff --git a/src/me/gorgeousone/tangledmaze/generation/PathGenerator.java b/src/me/gorgeousone/tangledmaze/generation/PathGenerator.java index bc3333c..257cb15 100644 --- a/src/me/gorgeousone/tangledmaze/generation/PathGenerator.java +++ b/src/me/gorgeousone/tangledmaze/generation/PathGenerator.java @@ -6,95 +6,337 @@ import java.util.Random; import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.generation.path.PathSegment; import me.gorgeousone.tangledmaze.util.Directions; import me.gorgeousone.tangledmaze.util.Vec2; public class PathGenerator { - protected ArrayList shuffledCardinals; - protected Random rnd; + private ArrayList shuffledCardinalDirs; + private Random rnd; public PathGenerator() { - shuffledCardinals = new ArrayList<>(Arrays.asList(Directions.cardinalValues())); + + shuffledCardinalDirs = new ArrayList<>(Arrays.asList(Directions.cardinalValues())); rnd = new Random(); } - public void generatePaths(BuildMap map) { + public void generatePaths(BuildMap buildMap) { + + generateExits(buildMap); + generatePathMap(buildMap); + buildMap.flip(); + } + + private void generateExits(BuildMap buildMap) { + + Maze maze = buildMap.getMaze(); - Maze maze = map.getMaze(); + int pathWidth = maze.getPathWidth(), + wallWidth = maze.getWallWidth(); - ArrayList openEnds = new ArrayList<>(); - openEnds.add(map.getStart()); + PathSegment entrance = createEntranceSegment( + maze.getMainExit(), + getExitFacing(maze.getMainExit(), buildMap), + pathWidth, + wallWidth); - int pathWidth = maze.getPathWidth(), - wallWidth = maze.getWallWidth(), - linkedPathsLength = 0; - - while(!openEnds.isEmpty()) { + Vec2 pathStart = entrance.getEnd(); + + buildMap.setStart(pathStart); + buildMap.mapSegment(entrance, MazeFillType.PATH); + + if(maze.getExits().size() < 2) + return; + + int pathGridOffsetX = pathStart.getX() % (pathWidth + wallWidth), + pathGridOffsetZ = pathStart.getZ() % (pathWidth + wallWidth); + + for(Vec2 exit : maze.getExits()) { - Vec2 currentEnd; + if(exit.equals(maze.getMainExit())) + continue; - if(linkedPathsLength < 3) { - currentEnd = openEnds.get(openEnds.size()-1); + createExitSegment( + exit, + buildMap, + pathGridOffsetX, + pathGridOffsetZ, + pathWidth, + wallWidth); + } + } + + private PathSegment createEntranceSegment( + Vec2 entrance, + Directions facing, + int pathWidth, + int wallWidth) { + + PathSegment entranceSegment = new PathSegment( + entrance, + wallWidth + pathWidth, + pathWidth, + facing, + true); + + return entranceSegment; + } + + private PathSegment createExitSegment( + Vec2 exit, + BuildMap buildMap, + int pathGridOffsetX, + int pathGridOffsetZ, + int pathWidth, + int wallWidth) { + + Directions facing = getExitFacing(exit, buildMap); + + PathSegment exitSegment = new PathSegment( + exit, + pathWidth, + pathWidth, + facing, + true); + + exitSegment.expand(facing.isXAligned() ? + getExitOffsetToPathGrid(exitSegment.getStart().getX(), facing, pathGridOffsetX, pathWidth, wallWidth) : + getExitOffsetToPathGrid(exitSegment.getStart().getZ(), facing, pathGridOffsetZ, pathWidth, wallWidth)); + + +// if(!segmentIsFree(buildMap, exitSegment)) +// return null; + +// buildMap.mapSegment(exitSegment, MazeFillType.EXIT); +// +// Vec2 verticalOffset = facing.isXAligned() ? +// getVerticalOffsetToPathGrid(exitSegment.getEnd().getZ(), facing, pathGridOffsetZ, pathWidth, wallWidth) : +// getVerticalOffsetToPathGrid(exitSegment.getEnd().getX(), facing, pathGridOffsetX, pathWidth, wallWidth); +// +// System.out.println(facing + " " + facing.toVec2().toString()); +// System.out.println(Directions.cardinalValueOf(verticalOffset) + " " + verticalOffset.toString()); +// +// if(!verticalOffset.isZero()) { +// +// exitSegment = new PathSegment( +// exitSegment.getEnd(), +// pathWidth, +// pathWidth, +// Directions.cardinalValueOf(verticalOffset), +// false); +// +// exitSegment.expand(verticalOffset.length()); +// +// if(!segmentIsFree(buildMap, exitSegment)) +// return null; +// +// } + + buildMap.mapSegment(exitSegment, MazeFillType.EXIT); + return exitSegment; + } + + //calculate how long the exit has to be to reach the grid of paths + private int getExitOffsetToPathGrid( + int exitSegmentStart, + Directions exitFacing, + int pathGridOffset, + int pathWidth, + int wallWidth) { + + //start with getting the exit's position relative to the path grid + int exitOffset = exitSegmentStart - pathGridOffset; + + //reduce the relative position to the actual possible offset + exitOffset %= pathWidth + wallWidth; + + //invert offset if it is calculated to opposing path in the grid + if(exitFacing.isPositive()) + exitOffset = (int) Math.signum(exitOffset) * (pathWidth + wallWidth) - exitOffset; + + //increase offset if it's under possible minimum of 1 block + if(exitOffset < 1) + exitOffset += pathWidth + wallWidth; + + return exitOffset; + } + + //calculate how long the exit has to be to reach the grid of paths +// private Vec2 getVerticalOffsetToPathGrid( +// int exitSegmentStart, +// Directions exitFacing, +// int pathGridOffset, +// int pathWidth, +// int wallWidth) { +// +// //start with getting the exit's position relative to the path grid +// int exitOffset = exitSegmentStart - pathGridOffset; +// +// //reduce the relative position to the actual possible offset +// exitOffset %= pathWidth + wallWidth; +// +// //invert offset if it is calculated to opposing path in the grid +// if(exitFacing.isPositive()) +// exitOffset = (pathWidth + wallWidth) - exitOffset; +// +// //increase offset if it's under possible minimum of 1 block +// if(exitOffset < 1) +// exitOffset += pathWidth + wallWidth; +// +// return exitFacing.toVec2().mult(exitOffset); +// } + + private void generatePathMap(BuildMap buildMap) { + + Maze maze = buildMap.getMaze(); + + ArrayList pathEnds = new ArrayList<>(); + pathEnds.add(buildMap.getStart()); + + int wallWidth = maze.getWallWidth(); + int pathWidth = maze.getPathWidth(); + int pathLength = maze.getPathLength(); + + int maxLinkedPathsCount = 3; + int linkedPathsCount = 0; + + Vec2 currentPathEnd; + + boolean lastSegmentWasExpanded = false; + + while(!pathEnds.isEmpty()) { + + if(linkedPathsCount < maxLinkedPathsCount) { + currentPathEnd = pathEnds.get(pathEnds.size()-1); }else { - currentEnd = openEnds.get(rnd.nextInt(openEnds.size())); - linkedPathsLength = 0; + currentPathEnd = pathEnds.get(rnd.nextInt(pathEnds.size())); + linkedPathsCount = 0; } - PathSegment path = createPathSegment(map, currentEnd, pathWidth, wallWidth); + Collections.shuffle(shuffledCardinalDirs); + PathSegment newPath = createPathSegment(buildMap, currentPathEnd, wallWidth, pathWidth, pathLength); + + if(newPath == null) { - if(path == null) { - - openEnds.remove(currentEnd); - linkedPathsLength = 0; + pathEnds.remove(currentPathEnd); + linkedPathsCount = 0; + continue; - }else { - - map.drawSegment(path, MazeFillType.PATH); - openEnds.add(path.getEnd()); - linkedPathsLength++; - } + //if this cardinal direction is the last one in shuffledCardinals the path end cannot have further junctions + }else if(shuffledCardinalDirs.indexOf(newPath.getFacing()) == 3) + pathEnds.remove(currentPathEnd); + + if(pathLength > 1 && !lastSegmentWasExpanded) + lastSegmentWasExpanded = tryExpandSegment(buildMap, newPath, wallWidth, pathWidth, rnd.nextInt(pathLength)); + else + lastSegmentWasExpanded = false; + + buildMap.mapSegment(newPath, MazeFillType.PATH); + + pathEnds.add(newPath.getEnd()); + linkedPathsCount++; } } - - protected PathSegment createPathSegment(BuildMap map, Vec2 currentEnd, int pathWidth, int wallWidth) { + + private PathSegment createPathSegment( + BuildMap buildMap, + Vec2 lastPathEnd, + int wallWidth, + int pathWidth, + int pathLength) { + + Collections.shuffle(shuffledCardinalDirs); - Collections.shuffle(shuffledCardinals); + PathSegment newPath = null; - for(Directions dir : shuffledCardinals) { + for(Directions dir : shuffledCardinalDirs) { - Vec2 - facing = dir.toVec2(), - start = new Vec2(currentEnd.getIntX() + facing.getIntX() * pathWidth, - currentEnd.getIntZ() + facing.getIntZ() * pathWidth); + Vec2 facing = dir.toVec2(); + Vec2 start = new Vec2( + lastPathEnd.getX() + facing.getX() * pathWidth, + lastPathEnd.getZ() + facing.getZ() * pathWidth); - PathSegment path = new PathSegment( + PathSegment possiblePath = new PathSegment( start, - facing, pathWidth + wallWidth, pathWidth, + dir, false); - - if(pathIsFree(map, path)) { - return path; + + if(segmentIsFree(buildMap, possiblePath)) { + newPath = possiblePath; + break; } } - return null; + return newPath; + } + + private boolean tryExpandSegment( + BuildMap buildMap, + PathSegment segment, + int wallWidth, + int pathWidth, + int maxPathLength) { + + Vec2 facing = segment.getFacing().toVec2(); + int extensionLength = pathWidth + wallWidth; + + PathSegment extension = new PathSegment( + segment.getEnd().add(facing.clone().mult(pathWidth)), + extensionLength, + pathWidth, + segment.getFacing(), + false); + + if(!segmentIsFree(buildMap, extension)) + return false; + + segment.expand(extensionLength); + + for(int i = 2; i < maxPathLength; i++) { + + extension.translate( + facing.getX() * extensionLength, + facing.getZ() * extensionLength); + + if(segmentIsFree(buildMap, extension)) + segment.expand(extensionLength); + else + break; + } + + return true; + } + + private static Directions getExitFacing(Vec2 exit, BuildMap buildMap) { + + for(Directions dir : Directions.cardinalValues()) { + + Vec2 neighbor = exit.clone().add(dir.toVec2()); + + if(!buildMap.contains(neighbor)) + continue; + + //check if location next to exit is inside maze + if(buildMap.getType(neighbor) == MazeFillType.UNDEFINED) + return dir; + } + + throw new IllegalArgumentException("The passed location cannot be an exit of this maze."); } - protected boolean pathIsFree(BuildMap map, PathSegment path) { + private boolean segmentIsFree(BuildMap buildMap, PathSegment segment) { - for(Vec2 point : path.getFill()) { + for(Vec2 point : segment.getFill()) { - if(point.getIntX() < 0 || point.getIntX() >= map.getDimX() || - point.getIntZ() < 0 || point.getIntZ() >= map.getDimZ()) { + if(!buildMap.contains(point)) return false; - } - if(map.getType(point) != MazeFillType.UNDEFINED && - map.getType(point) != MazeFillType.EXIT) { + if(buildMap.getType(point) != MazeFillType.UNDEFINED && + buildMap.getType(point) != MazeFillType.EXIT) { return false; } } diff --git a/src/me/gorgeousone/tangledmaze/generation/PathSegment.java b/src/me/gorgeousone/tangledmaze/generation/PathSegment.java deleted file mode 100644 index 5c7d3fe..0000000 --- a/src/me/gorgeousone/tangledmaze/generation/PathSegment.java +++ /dev/null @@ -1,101 +0,0 @@ -package me.gorgeousone.tangledmaze.generation; - -import java.util.ArrayList; - -import me.gorgeousone.tangledmaze.util.Vec2; - -public class PathSegment { - - public static final int - UNDEFINED = 1, - WALL = 2, - PATH = 3, - EXIT = 4; - - private Vec2 start, end, facing, relativeMin, dimension; - - public PathSegment(Vec2 start, Vec2 facing, int length, int width, boolean isExit) { - - //the segment can either face aligned to x or z axis. in positive or negative direction - this.start = start; - this.end = start.clone(); - this.facing = facing; - - //a vector relative to start, pointing to minimum corner of segment - relativeMin = new Vec2(); - dimension = new Vec2(); - - calculateDimensions(length, width, isExit); - } - - public Vec2 getStart() { - return start.clone(); - } - - public Vec2 getEnd() { - return end.clone(); - } - - public ArrayList getFill() { - - ArrayList fill = new ArrayList<>(); - - Vec2 min = start.clone().add(relativeMin); - Vec2 max = min.clone().add(dimension); - - for(int x = min.getIntX(); x < max.getIntX(); x++) - for(int z = min.getIntZ(); z < max.getIntZ(); z++) - fill.add(new Vec2(x, z)); - - return fill; - } - - private void move(int dx, int dz) { - start.add(dx, dz); - end.add(dx, dz); - } - - public void expand(int dLength) { - - Vec2 expansion = facing.clone().mult(dLength); - - dimension.add(expansion.getAbs()); - end.add(expansion); - - if(facing.getIntX() == -1 || - facing.getIntZ() == -1) { - - relativeMin.add(expansion); - } - } - - private void calculateDimensions(int length, int width, boolean isExit) { - - Vec2 dStartToEnd = facing.clone().mult(length - width); - end.add(dStartToEnd); - - if(facing.getIntX() != 0) { - dimension.set(length, width); - - if(facing.getIntX() == -1) { - relativeMin = dStartToEnd; - - if(isExit) { - move(-width+1, -width+1); - } - } - - }else { - dimension.set(width, length); - - if(facing.getIntZ() == -1) { - relativeMin = dStartToEnd; - - if(isExit) - move(0, -width+1); - - }else if(isExit) - move(-width+1, 0); - } - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/generation/path/PathSection.java b/src/me/gorgeousone/tangledmaze/generation/path/PathSection.java new file mode 100644 index 0000000..73ff50b --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/generation/path/PathSection.java @@ -0,0 +1,47 @@ +package me.gorgeousone.tangledmaze.generation.path; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public class PathSection { + + private Random random; + private List openPathEnds; + private Map pathLengths; + + public PathSection(PathSegment start, Random random) { + + this.random = random; + + openPathEnds = new ArrayList<>(); + pathLengths = new HashMap<>(); + + openPathEnds.add(start); + pathLengths.put(start, 1); + } + + public boolean hasOpenPathEnds() { + return !openPathEnds.isEmpty(); + } + + public PathSegment getLastOpenPath() { + return openPathEnds.get(openPathEnds.size()-1); + } + + public PathSegment getRandomOpenPath() { + return openPathEnds.get(random.nextInt(openPathEnds.size())); + } + + public void addPath(PathSegment newPath, PathSegment parentPath) { + + openPathEnds.add(newPath); + pathLengths.put(newPath, pathLengths.get(parentPath) + 1); + } + + public void closePath(PathSegment path) { + openPathEnds.remove(path); + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/generation/path/PathSegment.java b/src/me/gorgeousone/tangledmaze/generation/path/PathSegment.java new file mode 100644 index 0000000..49fe9a1 --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/generation/path/PathSegment.java @@ -0,0 +1,104 @@ +package me.gorgeousone.tangledmaze.generation.path; + +import java.util.HashSet; +import java.util.Set; + +import me.gorgeousone.tangledmaze.util.Directions; +import me.gorgeousone.tangledmaze.util.Vec2; + +public class PathSegment { + + private Vec2 start; + private Vec2 end; + private Vec2 size; + private Vec2 relativeMin; + + private Directions facing; + + public PathSegment(Vec2 start, int length, int width, Directions facing, boolean isExit) { + + //the segment can either face aligned to x or z axis. in positive or negative direction + this.start = start; + this.facing = facing; + + calculateDimensions(length, width, isExit); + } + + public Vec2 getStart() { + return start.clone(); + } + + public Vec2 getEnd() { + return end.clone(); + } + + public Directions getFacing() { + return facing; + } + + public Set getFill() { + + Set fill = new HashSet<>(); + + Vec2 min = start.clone().add(relativeMin); + Vec2 max = min.clone().add(size); + + for(int x = min.getX(); x < max.getX(); x++) { + for(int z = min.getZ(); z < max.getZ(); z++) { + fill.add(new Vec2(x, z)); + } + } + + return fill; + } + + public void expand(int blocks) { + + Vec2 expansion = facing.toVec2().clone().mult(blocks); + + size.add(expansion.getAbs()); + end.add(expansion); + + if(!facing.isPositive()) + relativeMin.add(expansion); + } + + private void calculateDimensions(int length, int width, boolean isExit) { + + Vec2 deltaStartToEnd = facing.toVec2().clone().mult(length - width); + + end = start.clone().add(deltaStartToEnd); + relativeMin = new Vec2(); + + if(facing.isXAligned()) { + + size = new Vec2(length, width); + + if(!facing.isPositive()) { + relativeMin = deltaStartToEnd; + + if(isExit) + translate(-width+1, -width+1); + } + + }else { + + size = new Vec2(width, length); + + if(!facing.isPositive()) { + relativeMin = deltaStartToEnd; + + if(isExit) + translate(0, -width+1); + + }else if(isExit) + translate(-width+1, 0); + } + } + + public void translate(int blocksX, int blocksZ) { + + start.add(blocksX, blocksZ); + end.add(blocksX, blocksZ); + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/handler/MazeCommandHandler.java b/src/me/gorgeousone/tangledmaze/handler/CommandHandler.java similarity index 76% rename from src/me/gorgeousone/tangledmaze/handler/MazeCommandHandler.java rename to src/me/gorgeousone/tangledmaze/handler/CommandHandler.java index b90c774..ab9f3b6 100644 --- a/src/me/gorgeousone/tangledmaze/handler/MazeCommandHandler.java +++ b/src/me/gorgeousone/tangledmaze/handler/CommandHandler.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -12,22 +13,22 @@ import me.gorgeousone.tangledmaze.data.Constants; import me.gorgeousone.tangledmaze.data.Messages; -public class MazeCommandHandler implements CommandExecutor { +public class CommandHandler implements CommandExecutor { - private ArrayList mazeCommands; + private List mazeCommands; - public MazeCommandHandler() { + public CommandHandler() { mazeCommands = new ArrayList<>(); } - + @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] arguments) { - if(!sender.hasPermission(Constants.BUILD_PERM)) { + if(!sender.hasPermission(Constants.BUILD_PERM)) Messages.ERROR_NO_BUILD_PERMISSION.send(sender); - } if(arguments.length < 1) { + HelpCommand.sendHelpPage(sender, 1); return true; } @@ -36,7 +37,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St for(MazeCommand mazeCommand : mazeCommands) { - if(mazeCommand.isCommand(subCommandName)) { + if(mazeCommand.getName().equalsIgnoreCase(subCommandName)) { mazeCommand.execute(sender, getSubArguents(arguments)); return true; } @@ -45,15 +46,18 @@ public boolean onCommand(CommandSender sender, Command command, String label, St return false; } + public List getCommands() { + return mazeCommands; + } + public void registerCommand(MazeCommand command) { mazeCommands.add(command); } private String[] getSubArguents(String[] arguments) { - if(arguments.length < 2) { + if(arguments.length < 2) return new String[] {}; - } return Arrays.copyOfRange(arguments, 1, arguments.length); } diff --git a/src/me/gorgeousone/tangledmaze/handler/MazeHandler.java b/src/me/gorgeousone/tangledmaze/handler/MazeHandler.java index 4cbea08..9b5a038 100644 --- a/src/me/gorgeousone/tangledmaze/handler/MazeHandler.java +++ b/src/me/gorgeousone/tangledmaze/handler/MazeHandler.java @@ -1,5 +1,7 @@ package me.gorgeousone.tangledmaze.handler; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.UUID; @@ -9,7 +11,6 @@ import org.bukkit.scheduler.BukkitRunnable; import me.gorgeousone.tangledmaze.core.Maze; -import me.gorgeousone.tangledmaze.core.Renderer; import me.gorgeousone.tangledmaze.core.TangledMain; public abstract class MazeHandler { @@ -42,15 +43,31 @@ public static void removeMaze(Player player) { mazes.remove(player.getUniqueId()); } - public static void buildMaze(Maze maze, MazeGenerator generator) { + public static void buildMaze(Maze maze, PathGenerator pathGenerator, BlockGenerator blockGenerator) { Renderer.hideMaze(maze); - BukkitRunnable async = new BukkitRunnable() { + new BukkitRunnable() { @Override public void run() { - generator.buildMaze(maze); + + BuildMap buildMap = new BuildMap(maze); + + pathGenerator.generatePaths(buildMap); + blockGenerator.generateBlocks(buildMap); } - }; - async.runTaskAsynchronously(TangledMain.getInstance()); + }.runTaskAsynchronously(TangledMain.getInstance()); + } + + public static void unbuilMaze(Maze maze, BlockGenerator blockGenerator) { + + blockGenerator.updateBlocksContinuously(maze.getBuiltBlocks(), new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + + maze.setConstructedBlocks(null); + maze.updateHeights(); + Renderer.displayMaze(maze); + } + }); } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/handler/Renderer.java b/src/me/gorgeousone/tangledmaze/handler/Renderer.java new file mode 100644 index 0000000..860dd19 --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/handler/Renderer.java @@ -0,0 +1,249 @@ +package me.gorgeousone.tangledmaze.handler; + +import me.gorgeousone.tangledmaze.clip.Clip; +import me.gorgeousone.tangledmaze.clip.ClipAction; +import me.gorgeousone.tangledmaze.core.Maze; +import me.gorgeousone.tangledmaze.core.TangledMain; +import me.gorgeousone.tangledmaze.data.Constants; +import me.gorgeousone.tangledmaze.tool.ClippingTool; +import me.gorgeousone.tangledmaze.util.Vec2; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +public abstract class Renderer implements Listener { + + private static HashMap clipVisibilities = new HashMap<>(); + private static HashMap mazeVisibilities = new HashMap<>(); + + public static void reload() { + + for (ClippingTool selection : clipVisibilities.keySet()) { + if (isClipboardVisible(selection)) { + hideClipboard(selection, false); + } + } + + for(Maze maze : mazeVisibilities.keySet()) { + if(isMazeVisible(maze)) { + hideMaze(maze); + } + } + } + + public static void registerClip(ClippingTool clipboard) { + clipVisibilities.put(clipboard, false); + } + + public static void registerMaze(Maze maze) { + mazeVisibilities.put(maze, false); + } + + public static void unregisterShape(ClippingTool clipboard) { + clipVisibilities.remove(clipboard); + } + + public static void unregisterMaze(Maze maze) { + mazeVisibilities.remove(maze); + } + + public static boolean isClipboardVisible(ClippingTool shape) { + return clipVisibilities.get(shape); + } + + public static boolean isMazeVisible(Maze maze) { + return mazeVisibilities.get(maze); + } + + @SuppressWarnings("deprecation") + public static void displayClipboard(ClippingTool clipboard) { + + clipVisibilities.put(clipboard, true); + Player player = clipboard.getPlayer(); + + new BukkitRunnable() { + @Override + public void run() { + + if(clipboard.isComplete()) { + for(Location loc : clipboard.getClip().getBorderBlocks()) + player.sendBlockChange(loc, Constants.CLIPBOARD_BORDER, (byte) 0); + } + + for(Location vertex : clipboard.getVertices()) + player.sendBlockChange(vertex, Constants.CLIPBOARD_CORNER, (byte) 0); + } + }.runTask(TangledMain.getInstance()); + } + + @SuppressWarnings("deprecation") + public static void hideClipboard(ClippingTool clipboard, boolean updateMaze) { + + clipVisibilities.put(clipboard, false); + Player player = clipboard.getPlayer(); + + if(clipboard.isComplete()) { + + for(Location loc : clipboard.getClip().getBorderBlocks()) + player.sendBlockChange(loc, loc.getBlock().getType(), loc.getBlock().getData()); + } + + for(Location vertex : clipboard.getVertices()) + player.sendBlockChange(vertex, vertex.getBlock().getType(), vertex.getBlock().getData()); + + if(!updateMaze) + return; + + Maze maze = MazeHandler.getMaze(player); + + if(maze.isStarted() && isMazeVisible(maze)) + redisplayMaze(maze, clipboard); + } + + @SuppressWarnings("deprecation") + public static void displayMaze(Maze maze) { + + if(maze.isConstructed()) + return; + + mazeVisibilities.put(maze, true); + Player player = maze.getPlayer(); + + new BukkitRunnable() { + @Override + public void run() { + + for(Location loc : maze.getClip().getBorderBlocks()) + player.sendBlockChange(loc, Constants.MAZE_BORDER, (byte) 0); + + for(Vec2 exit : maze.getExits()) + player.sendBlockChange(maze.getClip().getLocation(exit), Constants.MAZE_EXIT, (byte) 0); + + if(maze.hasExits()) + player.sendBlockChange(maze.getClip().getLocation(maze.getMainExit()), Constants.MAZE_MAIN_EXIT, (byte) 0); + } + }.runTask(TangledMain.getInstance()); + } + + @SuppressWarnings("deprecation") + public static void hideMaze(Maze maze) { + + if(maze.isConstructed() || !isMazeVisible(maze)) + return; + + mazeVisibilities.put(maze, false); + Player player = maze.getPlayer(); + + for(Location loc : maze.getClip().getBorderBlocks()) + player.sendBlockChange(loc, loc.getBlock().getType(), loc.getBlock().getData()); + } + + public static void redisplayClipboardBorder(ClippingTool clipboard, Location loc) { + + Player player = clipboard.getPlayer(); + + if(clipboard.isVertex(loc.getBlock())) + sendBlockDelayed(player, loc, Constants.CLIPBOARD_CORNER); + + else + sendBlockDelayed(player, loc, Constants.CLIPBOARD_BORDER); + } + + public static void redisplayMazeBorder(Maze maze, Location loc) { + + Player player = maze.getPlayer(); + + Vec2 locVec = new Vec2(loc); + + if(locVec.equals(maze.getMainExit())) + sendBlockDelayed(player, loc, Constants.MAZE_MAIN_EXIT); + + else if(maze.exitsContain(locVec)) + sendBlockDelayed(player, loc, Constants.MAZE_EXIT); + + else + sendBlockDelayed(player, loc, Constants.MAZE_BORDER); + } + + @SuppressWarnings("deprecation") + public static void displayMazeAction(Maze maze, ClipAction action) { + + Player player = maze.getPlayer(); + Clip clip = maze.getClip(); + + for(Vec2 exit : action.getRemovedExits()) { + + player.sendBlockChange(clip.getLocation(exit), Constants.MAZE_BORDER, (byte) 0); + + List mazeExits = maze.getExits(); + + if(exit.equals(maze.getMainExit()) && mazeExits.size() > 1) + player.sendBlockChange(clip.getLocation(mazeExits.get(mazeExits.size()-2)), Constants.MAZE_MAIN_EXIT, (byte) 0); + } + + for(Vec2 loc : action.getAddedBorder()) + player.sendBlockChange(action.getBorder(loc), Constants.MAZE_BORDER, (byte) 0); + + for(Vec2 loc : action.getRemovedBorder()) { + + Location block = action.getBorder(loc); + player.sendBlockChange(block, block.getBlock().getType(), (byte) 0); + + } + } + + //Displays maze parts that were covered under a clipboard. + @SuppressWarnings("deprecation") + private static void redisplayMaze(Maze maze, ClippingTool hiddenClipboard) { + + Player player = maze.getPlayer(); + + for(Location vertex : hiddenClipboard.getVertices()) { + + if(maze.getClip().isBorderBlock(vertex.getBlock())) + player.sendBlockChange(vertex, Constants.MAZE_BORDER, (byte) 0); + } + + if(!hiddenClipboard.isComplete()) + return; + + for(Location border : hiddenClipboard.getClip().getBorderBlocks()) { + + if(maze.getClip().isBorderBlock(border.getBlock())) + maze.getPlayer().sendBlockChange(border, Constants.MAZE_BORDER , (byte) 0); + } + } + + public static void sendBlockDelayed(Player player, Location loc, Material mat) { + + new BukkitRunnable() { + + @SuppressWarnings("deprecation") + @Override + public void run() { + player.sendBlockChange(loc, mat, (byte) 0); + } + }.runTask(TangledMain.getInstance()); + } + + public static void sendBlocksDelayed(Player player, Collection locs, Material mat) { + + new BukkitRunnable() { + + @SuppressWarnings("deprecation") + @Override + public void run() { + + for(Location loc : locs) + player.sendBlockChange(loc, mat, (byte) 0); + } + }.runTask(TangledMain.getInstance()); + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/handler/ToolHandler.java b/src/me/gorgeousone/tangledmaze/handler/ToolHandler.java index 598d0cf..ff48739 100644 --- a/src/me/gorgeousone/tangledmaze/handler/ToolHandler.java +++ b/src/me/gorgeousone/tangledmaze/handler/ToolHandler.java @@ -6,7 +6,6 @@ import org.bukkit.entity.Player; -import me.gorgeousone.tangledmaze.core.Renderer; import me.gorgeousone.tangledmaze.shape.Shape; import me.gorgeousone.tangledmaze.tool.ClippingTool; import me.gorgeousone.tangledmaze.tool.Tool; @@ -44,9 +43,14 @@ public static void setTool(Player p, Tool tool) { public static void resetToDefaultTool(Player player) { if(hasClipboard(player)) { - - if(getClipboard(player).isStarted()) - getClipboard(player).reset(); + + ClippingTool clipboard = getClipboard(player); + + if(clipboard.isStarted()) { + + Renderer.hideClipboard(clipboard, true); + clipboard.reset(); + } }else { setTool(player, new ClippingTool(player, Shape.RECT)); diff --git a/src/me/gorgeousone/tangledmaze/listener/BlockUpdateListener.java b/src/me/gorgeousone/tangledmaze/listener/BlockUpdateListener.java index fb212d3..83a0ec1 100644 --- a/src/me/gorgeousone/tangledmaze/listener/BlockUpdateListener.java +++ b/src/me/gorgeousone/tangledmaze/listener/BlockUpdateListener.java @@ -1,23 +1,24 @@ package me.gorgeousone.tangledmaze.listener; +import org.bukkit.event.block.*; +import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.*; import org.bukkit.event.entity.EntityChangeBlockEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.scheduler.BukkitRunnable; import me.gorgeousone.tangledmaze.core.Maze; -import me.gorgeousone.tangledmaze.core.Renderer; import me.gorgeousone.tangledmaze.core.TangledMain; import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.handler.ToolHandler; import me.gorgeousone.tangledmaze.tool.ClippingTool; import me.gorgeousone.tangledmaze.tool.Tool; -import me.gorgeousone.tangledmaze.util.MazePoint; +import me.gorgeousone.tangledmaze.util.Vec2; import java.util.HashSet; @@ -80,85 +81,73 @@ public void onEntityChangeBlock(EntityChangeBlockEvent e) { private void checkForUpdates(Block block, boolean hideAffectedElements) { - MazePoint point = new MazePoint(block.getLocation()); - HashSet affectedMazes = getAffectedMazes(point); - HashSet affectedClipboards = getAffectedClipboards(point); + Vec2 loc = new Vec2(block); + HashSet affectedMazes = getAffectedMazes(loc); + HashSet affectedClipboards = getAffectedClipboards(loc); - if(affectedClipboards.isEmpty() && affectedMazes.isEmpty()) { + if(affectedClipboards.isEmpty() && affectedMazes.isEmpty()) return; - } update(block, affectedMazes, affectedClipboards, hideAffectedElements); } - private HashSet getAffectedMazes(MazePoint point) { + private HashSet getAffectedMazes(Vec2 loc) { HashSet affectedMazes = new HashSet<>(); for(Maze maze : MazeHandler.getMazes()) { - if(!maze.getClip().contains(new MazePoint(point))) - continue; - - affectedMazes.add(maze); + if(maze.isStarted() && !maze.isConstructed() && maze.getClip().contains(loc)) + affectedMazes.add(maze); } return affectedMazes; } - private HashSet getAffectedClipboards(MazePoint point) { + private HashSet getAffectedClipboards(Vec2 loc) { HashSet affectedClipboards = new HashSet<>(); for(Tool tool : ToolHandler.getTools()) { - if(!(tool instanceof ClippingTool)) { + if(!(tool instanceof ClippingTool)) continue; - } ClippingTool clipboard = (ClippingTool) tool; - if(!clipboard.getClip().contains(point)) { - continue; - } - - affectedClipboards.add(clipboard); + if(clipboard.getClip().contains(loc)) + affectedClipboards.add(clipboard); } return affectedClipboards; } private void update(Block changedBlock, HashSet affectedMazes, HashSet affectedClipboards, boolean hideAffectedElements) { - + new BukkitRunnable() { @Override public void run() { - + for(Maze maze : affectedMazes) { - if(hideAffectedElements && Renderer.isMazeVisible(maze) && maze.isHighlighted(changedBlock)) { + if(hideAffectedElements && Renderer.isMazeVisible(maze) && maze.getClip().isBorderBlock(changedBlock)) Renderer.hideMaze(maze); - } - - Block updatedBlock = maze.updateHeight(changedBlock); - //TODO only update visibility of changed block - if(!hideAffectedElements && updatedBlock != null) { - Renderer.updateChunk(updatedBlock.getChunk()); - } + Location updatedBlock = maze.updateHeight(changedBlock); + + if(!hideAffectedElements && updatedBlock != null && Renderer.isMazeVisible(maze) && maze.getClip().isBorderBlock(updatedBlock.getBlock())) + Renderer.redisplayMazeBorder(maze, updatedBlock); } for(ClippingTool clipboard : affectedClipboards) { - if(hideAffectedElements && Renderer.isClipboardVisible(clipboard) && clipboard.isHighlighted(changedBlock)) { + if(hideAffectedElements && Renderer.isClipboardVisible(clipboard) && clipboard.getClip().isBorderBlock(changedBlock)) Renderer.hideClipboard(clipboard, true); - } - Block updatedBlock = clipboard.updateHeight(changedBlock); + Location updatedBlock = clipboard.updateHeight(changedBlock); - if(!hideAffectedElements && updatedBlock != null) { - Renderer.updateChunk(updatedBlock.getChunk()); - } + if(!hideAffectedElements && updatedBlock != null && Renderer.isClipboardVisible(clipboard) && clipboard.getClip().isBorderBlock(updatedBlock.getBlock())) + Renderer.redisplayClipboardBorder(clipboard, updatedBlock); } } }.runTask(TangledMain.getInstance()); diff --git a/src/me/gorgeousone/tangledmaze/listener/PlayerListener.java b/src/me/gorgeousone/tangledmaze/listener/PlayerListener.java index 6293e8d..f14c7e0 100644 --- a/src/me/gorgeousone/tangledmaze/listener/PlayerListener.java +++ b/src/me/gorgeousone/tangledmaze/listener/PlayerListener.java @@ -55,7 +55,7 @@ public void onChangeWorld(PlayerChangedWorldEvent e) { Player player = e.getPlayer(); if(player.hasPermission(Constants.BUILD_PERM)) { - MazeHandler.getMaze(player).reset(); + MazeHandler.setMaze(player, new Maze(player)); ToolHandler.resetToDefaultTool(player); } } diff --git a/src/me/gorgeousone/tangledmaze/listener/ToolActionListener.java b/src/me/gorgeousone/tangledmaze/listener/ToolActionListener.java index c0a51ee..4af8bdf 100644 --- a/src/me/gorgeousone/tangledmaze/listener/ToolActionListener.java +++ b/src/me/gorgeousone/tangledmaze/listener/ToolActionListener.java @@ -1,9 +1,9 @@ package me.gorgeousone.tangledmaze.listener; import org.bukkit.ChatColor; -import org.bukkit.Effect; import org.bukkit.Particle; import org.bukkit.Sound; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -13,14 +13,15 @@ import org.bukkit.event.player.PlayerItemDamageEvent; import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import me.gorgeousone.tangledmaze.core.Renderer; +import me.gorgeousone.tangledmaze.core.Maze; import me.gorgeousone.tangledmaze.data.Constants; import me.gorgeousone.tangledmaze.handler.MazeHandler; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.handler.ToolHandler; +import me.gorgeousone.tangledmaze.tool.ClippingTool; import me.gorgeousone.tangledmaze.util.Utils; @SuppressWarnings("deprecation") @@ -36,70 +37,86 @@ public void onItemDamage(PlayerItemDamageEvent e) { } @EventHandler - public void onBlockClick(PlayerInteractEvent e) { + public void onBlockClick(PlayerInteractEvent event) { - Action action = e.getAction(); + Action action = event.getAction(); if(action != Action.LEFT_CLICK_BLOCK && - action != Action.RIGHT_CLICK_BLOCK) + action != Action.RIGHT_CLICK_BLOCK || + event.getHand() != EquipmentSlot.HAND) return; - try { - if(e.getHand() != EquipmentSlot.HAND) - return; - } catch (NoSuchMethodError err) {} - - if(!Utils.isMazeWand(e.getItem())) - return; + Player player = event.getPlayer(); + Block block = event.getClickedBlock(); - e.setCancelled(true); + if(Utils.isMazeWand(event.getItem())) { - Player p = e.getPlayer(); - ItemStack wand = e.getItem(); + event.setCancelled(true); + + if(!player.hasPermission(Constants.BUILD_PERM)) { + destroyMazeWand(player, event.getItem()); + return; + } + + ToolHandler.getTool(player).interact(block, action); - if(!p.hasPermission(Constants.BUILD_PERM)) { - destroyMazeWand(p, wand); - return; + }else if(player.hasPermission(Constants.BUILD_PERM)) { + + Maze maze = MazeHandler.getMaze(player); + + if(Renderer.isMazeVisible(maze) && maze.getClip().isBorderBlock(block)) + Renderer.hideMaze(maze); + + if(!ToolHandler.hasClipboard(player)) + return; + + ClippingTool clipboard = ToolHandler.getClipboard(player); + + if(Renderer.isClipboardVisible(clipboard) && (clipboard.isVertex(block) || clipboard.getClip().isBorderBlock(block))) + Renderer.hideClipboard(clipboard, false); } - - ToolHandler.getTool(p).interact(e.getClickedBlock(), action); } - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public void onSlotSwitch(PlayerItemHeldEvent e) { + public void onSlotSwitch(PlayerItemHeldEvent event) { + + Player player = event.getPlayer(); - Player p = e.getPlayer(); - ItemStack newItem = p.getInventory().getItem(e.getNewSlot()); + if(!player.hasPermission(Constants.BUILD_PERM)) + return; + + ItemStack newItem = player.getInventory().getItem(event.getNewSlot()); - if(Utils.isMazeWand(newItem)) { + if(!Utils.isMazeWand(newItem)) + return; - if(MazeHandler.hasMaze(p) && !Renderer.isMazeVisible(MazeHandler.getMaze(p))) - Renderer.showMaze(MazeHandler.getMaze(p)); + Maze maze = MazeHandler.getMaze(player); - if(ToolHandler.hasClipboard(p) && !Renderer.isClipboardVisible(ToolHandler.getClipboard(p))) - Renderer.showClipboard(ToolHandler.getClipboard(p)); - } + if(!maze.isConstructed() || !Renderer.isMazeVisible(maze)) + Renderer.displayMaze(MazeHandler.getMaze(player)); + + if(ToolHandler.hasClipboard(player) && !Renderer.isClipboardVisible(ToolHandler.getClipboard(player))) + Renderer.displayClipboard(ToolHandler.getClipboard(player)); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onPickUp(PlayerPickupItemEvent e) { if(Utils.isMazeWand(e.getItem().getItemStack())) { - Player p = e.getPlayer(); + Player player = e.getPlayer(); - if(MazeHandler.hasMaze(p) && !Renderer.isMazeVisible(MazeHandler.getMaze(p))) - Renderer.showMaze(MazeHandler.getMaze(p)); + if(MazeHandler.hasMaze(player) && !Renderer.isMazeVisible(MazeHandler.getMaze(player))) + Renderer.displayMaze(MazeHandler.getMaze(player)); - if(ToolHandler.hasClipboard(p) && !Renderer.isClipboardVisible(ToolHandler.getClipboard(p))) - Renderer.showClipboard(ToolHandler.getClipboard(p)); + if(ToolHandler.hasClipboard(player) && !Renderer.isClipboardVisible(ToolHandler.getClipboard(player))) + Renderer.displayClipboard(ToolHandler.getClipboard(player)); } } - @EventHandler - public void onChunkLoad(ChunkLoadEvent e) { - Renderer.updateChunk(e.getChunk()); - } +// @EventHandler +// public void onChunkLoad(ChunkLoadEvent e) { +// Renderer.updateChunk(e.getChunk()); +// } private void destroyMazeWand(Player p, ItemStack wand) { @@ -107,13 +124,7 @@ private void destroyMazeWand(Player p, ItemStack wand) { p.sendMessage(ChatColor.GRAY + "" + ChatColor.ITALIC + "It seems like you are unworthy to use such mighty tool, it broke apart."); p.damage(0); - if(Constants.BUKKIT_VERSION == 8) { - p.getWorld().playSound(p.getEyeLocation(), Sound.valueOf("ITEM_BREAK"), 1f, 1f); - p.getWorld().playEffect(p.getLocation().add(0, 1, 0), Effect.valueOf("EXPLOSION_HUGE"), 0); - - }else { - p.getWorld().playSound(p.getEyeLocation(), Sound.ENTITY_ITEM_BREAK, 1f, 1f); - p.getWorld().spawnParticle(Particle.EXPLOSION_HUGE, p.getLocation(), 1); - } + p.getWorld().playSound(p.getEyeLocation(), Sound.ENTITY_ITEM_BREAK, 1f, 1f); + p.getWorld().spawnParticle(Particle.EXPLOSION_HUGE, p.getLocation(), 1); } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/shape/Circle.java b/src/me/gorgeousone/tangledmaze/shape/Circle.java index 2d1e34d..4bf9f57 100644 --- a/src/me/gorgeousone/tangledmaze/shape/Circle.java +++ b/src/me/gorgeousone/tangledmaze/shape/Circle.java @@ -2,61 +2,58 @@ import java.util.ArrayList; +import org.bukkit.Location; + import me.gorgeousone.tangledmaze.clip.Clip; import me.gorgeousone.tangledmaze.util.Directions; -import me.gorgeousone.tangledmaze.util.MazePoint; import me.gorgeousone.tangledmaze.util.Utils; import me.gorgeousone.tangledmaze.util.Vec2; public class Circle implements Shape { + private static float circleSmoothing = -0.25f; + @Override public int getVertexCount() { return 2; } @Override - public Clip createClip(ArrayList vertices) { + public Clip createClip(ArrayList vertices) { if(vertices.size() < 2) throw new IllegalArgumentException("An ellipse neeeds 2 vertices to be determined."); - MazePoint - vertex0 = vertices.get(0), - vertex1 = vertices.get(1); + Location vertex0 = vertices.get(0); + Location vertex1 = vertices.get(1); vertices.clear(); vertices.addAll(Shape.createRectangularVertices(vertex0, vertex1)); - MazePoint - minVertex = vertices.get(0).clone(), - maxVertex = vertices.get(2).clone().add(1, 0, 1); + Vec2 minVertex = new Vec2(vertices.get(0)); + Vec2 maxVertex = new Vec2(vertices.get(2)).add(1, 1); - Clip clip = new Clip(minVertex.getWorld()); + Clip clip = new Clip(vertices.get(0).getWorld()); - float - radiusX = (float) (maxVertex.getX() - minVertex.getX()) / 2, - radiusZ = (float) (maxVertex.getZ() - minVertex.getZ()) / 2, - distortionZ = 1 / (radiusZ / radiusX); + float radiusX = (float) (maxVertex.getX() - minVertex.getX()) / 2; + float radiusZ = (float) (maxVertex.getZ() - minVertex.getZ()) / 2; + float distortionZ = 1 / (radiusZ / radiusX); int maxY = Utils.getMaxHeight(vertices); for(float x = (float) -radiusX; x <= radiusX; x++) { for(float z = (float) -radiusZ; z <= radiusZ; z++) { - if(!isInEllipse(x+0.5f, z+0.5f, distortionZ, radiusX - 0.25f)) { + if(!isInEllipse(x+0.5f, z+0.5f, distortionZ, radiusX + circleSmoothing)) continue; - } - MazePoint point = minVertex.clone().add(radiusX + x, 0, radiusZ + z); - point.setY(maxY); - point = Utils.nearestSurface(point); + Vec2 loc = minVertex.clone().add((int) (radiusX + x), (int) (radiusZ + z)); + int height = Utils.nearestSurfaceY(loc, maxY, clip.getWorld()); - clip.addFilling(point); + clip.addFill(loc, height); - if(isEllipseBorder(x+0.5f, z+0.5f, distortionZ, radiusX - 0.25f)) { - clip.addBorder(point); - } + if(isEllipseBorder(x + 0.5f, z + 0.5f, distortionZ, radiusX + circleSmoothing)) + clip.addBorder(loc); } } diff --git a/src/me/gorgeousone/tangledmaze/shape/Rectangle.java b/src/me/gorgeousone/tangledmaze/shape/Rectangle.java index 3f22885..47b46df 100644 --- a/src/me/gorgeousone/tangledmaze/shape/Rectangle.java +++ b/src/me/gorgeousone/tangledmaze/shape/Rectangle.java @@ -2,9 +2,11 @@ import java.util.ArrayList; +import org.bukkit.Location; + import me.gorgeousone.tangledmaze.clip.Clip; -import me.gorgeousone.tangledmaze.util.MazePoint; import me.gorgeousone.tangledmaze.util.Utils; +import me.gorgeousone.tangledmaze.util.Vec2; public class Rectangle implements Shape { @@ -14,44 +16,40 @@ public int getVertexCount() { } @Override - public Clip createClip(ArrayList vertices) { + public Clip createClip(ArrayList vertices) { if(vertices.size() < 2) throw new IllegalArgumentException("A rectangle needs 2 vertices to be determined."); - MazePoint - vertex0 = vertices.get(0), - vertex2 = vertices.get(1); + Location vertex0 = vertices.get(0); + Location vertex2 = vertices.get(1); vertices.clear(); vertices.addAll(Shape.createRectangularVertices(vertex0, vertex2)); - MazePoint - minVertex = vertices.get(0).clone(), - maxVertex = vertices.get(2).clone().add(1, 0, 1); - + Vec2 minVertex = new Vec2(vertices.get(0)); + Vec2 maxVertex = new Vec2(vertices.get(2)).add(1, 1); Clip clip = new Clip(vertex0.getWorld()); int maxY = Utils.getMaxHeight(vertices); - for(int x = minVertex.getBlockX(); x < maxVertex.getX(); x++) { - for(int z = minVertex.getBlockZ(); z < maxVertex.getZ(); z++) { - - MazePoint point = new MazePoint(minVertex.getWorld(), x, maxY, z); - point = Utils.nearestSurface(point); + for(int x = minVertex.getX(); x < maxVertex.getX(); x++) { + for(int z = minVertex.getZ(); z < maxVertex.getZ(); z++) { - clip.addFilling(point); + Vec2 loc = new Vec2(x, z); + int height = Utils.nearestSurfaceY(loc, maxY, clip.getWorld()); - if(isBorder(x, z, minVertex, maxVertex)) { - clip.addBorder(point); - } + clip.addFill(loc, height); + + if(isBorder(x, z, minVertex, maxVertex)) + clip.addBorder(loc); } } - + return clip; } - private boolean isBorder(int x, int z, MazePoint minVertex, MazePoint maxVertex) { + private boolean isBorder(int x, int z, Vec2 minVertex, Vec2 maxVertex) { return x == minVertex.getX() || x == maxVertex.getX() - 1 || z == minVertex.getZ() || z == maxVertex.getZ() - 1; diff --git a/src/me/gorgeousone/tangledmaze/shape/Shape.java b/src/me/gorgeousone/tangledmaze/shape/Shape.java index 6fa76ee..6992f60 100644 --- a/src/me/gorgeousone/tangledmaze/shape/Shape.java +++ b/src/me/gorgeousone/tangledmaze/shape/Shape.java @@ -3,10 +3,10 @@ import java.util.ArrayList; import java.util.Arrays; +import org.bukkit.Location; import org.bukkit.World; import me.gorgeousone.tangledmaze.clip.Clip; -import me.gorgeousone.tangledmaze.util.MazePoint; import me.gorgeousone.tangledmaze.util.Utils; public interface Shape { @@ -16,24 +16,25 @@ public interface Shape { public int getVertexCount(); - public Clip createClip(ArrayList vertices); + public Clip createClip(ArrayList vertices); - public static ArrayList createRectangularVertices(MazePoint v0, MazePoint v2) { - ArrayList vertices = new ArrayList<>(); - World w = v0.getWorld(); + public static ArrayList createRectangularVertices(Location vertex0, Location vertex2) { - int minY = Math.min(v0.getBlockY(), v2.getBlockY()); + ArrayList vertices = new ArrayList<>(); + World world = vertex0.getWorld(); - int minX = Math.min(v0.getBlockX(), v2.getBlockX()), - minZ = Math.min(v0.getBlockZ(), v2.getBlockZ()), - maxX = Math.max(v0.getBlockX(), v2.getBlockX()), - maxZ = Math.max(v0.getBlockZ(), v2.getBlockZ()); + int maxY = Math.max(vertex0.getBlockY(), vertex2.getBlockY()); + + int minX = Math.min(vertex0.getBlockX(), vertex2.getBlockX()), + minZ = Math.min(vertex0.getBlockZ(), vertex2.getBlockZ()), + maxX = Math.max(vertex0.getBlockX(), vertex2.getBlockX()), + maxZ = Math.max(vertex0.getBlockZ(), vertex2.getBlockZ()); vertices = new ArrayList<>(Arrays.asList( - Utils.nearestSurface(new MazePoint(w, minX, minY, minZ)), - Utils.nearestSurface(new MazePoint(w, maxX, minY, minZ)), - Utils.nearestSurface(new MazePoint(w, maxX, minY, maxZ)), - Utils.nearestSurface(new MazePoint(w, minX, minY, maxZ)))); + Utils.nearestSurface(new Location(world, minX, maxY, minZ)), + Utils.nearestSurface(new Location(world, maxX, maxY, minZ)), + Utils.nearestSurface(new Location(world, maxX, maxY, maxZ)), + Utils.nearestSurface(new Location(world, minX, maxY, maxZ)))); return vertices; } diff --git a/src/me/gorgeousone/tangledmaze/shape/Triangle.java b/src/me/gorgeousone/tangledmaze/shape/Triangle.java deleted file mode 100644 index 2c15437..0000000 --- a/src/me/gorgeousone/tangledmaze/shape/Triangle.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.gorgeousone.tangledmaze.shape; - -import java.util.ArrayList; - -import me.gorgeousone.tangledmaze.clip.Clip; -import me.gorgeousone.tangledmaze.util.MazePoint; - -public class Triangle implements Shape { - - @Override - public int getVertexCount() { - return 3; - } - - @Override - public Clip createClip(ArrayList vertices) { - return null; - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/tool/ClippingTool.java b/src/me/gorgeousone/tangledmaze/tool/ClippingTool.java index 11b4f77..d2ef03e 100644 --- a/src/me/gorgeousone/tangledmaze/tool/ClippingTool.java +++ b/src/me/gorgeousone/tangledmaze/tool/ClippingTool.java @@ -9,22 +9,23 @@ import org.bukkit.event.block.Action; import me.gorgeousone.tangledmaze.clip.Clip; -import me.gorgeousone.tangledmaze.core.Renderer; +import me.gorgeousone.tangledmaze.handler.Renderer; import me.gorgeousone.tangledmaze.shape.Shape; -import me.gorgeousone.tangledmaze.util.MazePoint; import me.gorgeousone.tangledmaze.util.Utils; +import me.gorgeousone.tangledmaze.util.Vec2; public class ClippingTool extends Tool { private Shape shape; private Clip clip; - private ArrayList vertices; + private ArrayList vertices; private boolean isComplete, isResizing; private int indexOfResizedVertex; public ClippingTool(World world, Shape type) { + super(null); clip = new Clip(world); @@ -77,15 +78,14 @@ public void setType(Shape shape) { calculateShape(); } - Renderer.showClipboard(this); + Renderer.displayClipboard(this); } @Override public void interact(Block clicked, Action interaction) { - if(clicked.getWorld() != getWorld()) { + if(clicked.getWorld() != getWorld()) reset(); - } if(vertices.size() < shape.getVertexCount()-1) { vertices.add(Utils.nearestSurface(clicked.getLocation())); @@ -114,7 +114,7 @@ public void interact(Block clicked, Action interaction) { } } - Renderer.showClipboard(this); + Renderer.displayClipboard(this); } private void calculateShape() { @@ -124,90 +124,76 @@ private void calculateShape() { isResizing = false; } - private void resizeShape(Block b) { + private void resizeShape(Block block) { Renderer.hideClipboard(this, true); - MazePoint oppositeVertex = vertices.get((indexOfResizedVertex+2) % 4); + Location oppositeVertex = vertices.get((indexOfResizedVertex+2) % 4); vertices.clear(); vertices.add(oppositeVertex); - vertices.add(Utils.nearestSurface(b.getLocation())); + vertices.add(Utils.nearestSurface(block.getLocation())); calculateShape(); } public void reset() { - Renderer.hideClipboard(this, true); - clip = new Clip(getPlayer() != null ? getPlayer().getWorld() : getWorld()); vertices.clear(); isComplete = false; isResizing = false; } - public ArrayList getVertices() { + public ArrayList getVertices() { return vertices; } - public boolean isVertex(Block b) { + public boolean isVertex(Block block) { - for(MazePoint vertex : vertices) { - - if(vertex.equals(b.getLocation())) { + if(getWorld() != block.getWorld()) + return false; + + Location loc = block.getLocation(); + + for(Location vertex : vertices) { + if(vertex.equals(loc)) return true; - } } return false; } - public int indexOfVertex(Block b) { - - if(!isComplete() || !b.getWorld().equals(getWorld())) - return -1; + public int indexOfVertex(Block block) { for(Location vertex : vertices) { - if(b.getX() == vertex.getX() && - b.getZ() == vertex.getZ()) + + if(block.getX() == vertex.getX() && + block.getZ() == vertex.getZ()) return vertices.indexOf(vertex); } return -1; } - public boolean isHighlighted(Block b) { - - if(!isComplete() ||!b.getWorld().equals(getWorld())) - return false; + public Location updateHeight(Block block) { - MazePoint point = new MazePoint(b.getLocation()); - - if(!getClip().borderContains(point)) - return false; - - for(MazePoint borderPoint : getClip().getBorder()) { - if(borderPoint.equals(point) && borderPoint.getBlockY() == point.getBlockY()) - return true; + Location updatedBlock = null; + + if(isVertex(block)) { + + updatedBlock = Utils.nearestSurface(block.getLocation()); + vertices.get(indexOfVertex(block)).setY(updatedBlock.getBlockY()); } - return false; - } - - public Block updateHeight(Block block) { - - MazePoint point = Utils.nearestSurface(block.getLocation()); - - if(getClip().removeFilling(point)) { - getClip().addFilling(point); + if(!isComplete()) + return updatedBlock; + else + updatedBlock = Utils.nearestSurface(block.getLocation()); + + Vec2 blockVec = new Vec2(block); - }else - return null; + getClip().addFill(blockVec, updatedBlock.getBlockY()); - if(getClip().removeBorder(point)) { - getClip().addBorder(point); - } - - return point.getBlock(); + return updatedBlock; } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/tool/ExitSettingTool.java b/src/me/gorgeousone/tangledmaze/tool/ExitSettingTool.java index 4c66455..70210ad 100644 --- a/src/me/gorgeousone/tangledmaze/tool/ExitSettingTool.java +++ b/src/me/gorgeousone/tangledmaze/tool/ExitSettingTool.java @@ -9,8 +9,8 @@ public class ExitSettingTool extends Tool { - public ExitSettingTool(Player p) { - super(p); + public ExitSettingTool(Player builder) { + super(builder); } @Override diff --git a/src/me/gorgeousone/tangledmaze/util/Directions.java b/src/me/gorgeousone/tangledmaze/util/Directions.java index 80e97c2..03925e8 100644 --- a/src/me/gorgeousone/tangledmaze/util/Directions.java +++ b/src/me/gorgeousone/tangledmaze/util/Directions.java @@ -20,6 +20,27 @@ public enum Directions { this.facing = facing; } + /** + * Returns if the diretion's vector is pointing towards positive or negative (with it's x or z coordinate) + */ + public boolean isPositive() { + return facing.getZ() == 0 ? facing.getX() == 1 : facing.getZ() == 1; + } + + /** + * Returns if the x coordinate of the direction's vector is not 0 + */ + public boolean isXAligned() { + return facing.getX() != 0; + } + + /** + * Returns if the z coordinate of the direction's vector is not 0 + */ + public boolean isZAligned() { + return facing.getZ() != 0; + } + public Vec2 toVec2() { return facing.clone(); } @@ -31,4 +52,12 @@ public Vector toVec3() { public static Directions[] cardinalValues() { return new Directions[] {EAST, WEST, SOUTH, NORTH}; } + + public static Directions cardinalValueOf(Vec2 vec) { + + if(vec.getX() != 0) + return vec.getX() > 0 ? EAST : WEST; + + return vec.getZ() > 0 ? SOUTH : NORTH; + } } \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/MaterialReader.java b/src/me/gorgeousone/tangledmaze/util/MaterialReader.java deleted file mode 100644 index 89120ce..0000000 --- a/src/me/gorgeousone/tangledmaze/util/MaterialReader.java +++ /dev/null @@ -1,56 +0,0 @@ -package me.gorgeousone.tangledmaze.util; - -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.material.MaterialData; - -import me.gorgeousone.tangledmaze.data.Constants; - -@SuppressWarnings("deprecation") -public class MaterialReader { - - public static Material readMaterial(String materialName) { - - if(Constants.BUKKIT_VERSION <= 12) { - return ReflectionMaterials.getMaterial(materialName); - - }else { - return Material.matchMaterial(materialName); - } - } - - public static MaterialData readMaterialData(String materialData) { - - Material type; - byte data; - - String typeString; - String dataString; - - if(materialData.contains(":")) { - - String[] split = materialData.split(":"); - typeString = split[0]; - dataString = split[1]; - - }else { - - typeString = materialData; - dataString = "0"; - } - - type = readMaterial(typeString); - - if(type == null) { - throw new IllegalArgumentException(ChatColor.RED + "\"" + typeString + "\" does not match any block."); - } - - try { - data = Byte.parseByte(dataString); - } catch (Exception e) { - throw new IllegalArgumentException(ChatColor.RED + "\"" + dataString + "\" is not a valid number."); - } - - return new MaterialData(type, data); - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/MazePoint.java b/src/me/gorgeousone/tangledmaze/util/MazePoint.java deleted file mode 100644 index 1ccc44b..0000000 --- a/src/me/gorgeousone/tangledmaze/util/MazePoint.java +++ /dev/null @@ -1,102 +0,0 @@ -package me.gorgeousone.tangledmaze.util; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.util.Vector; - -public class MazePoint extends Location implements Comparable { - - public MazePoint(Location loc) { - super( - loc.getWorld(), - loc.getBlockX(), - loc.getBlockY(), - loc.getBlockZ()); - } - - public MazePoint(World w, double x, double y, double z) { - super(w, (int) x, (int) y, (int) z); - } - - @Override - public void setX(double x) { - super.setX((int) x); - } - - @Override - public void setY(double y) { - super.setY((int) y); - } - - @Override - public void setZ(double z) { - super.setZ((int) z); - } - - @Override - public int compareTo(Location loc) { - - int deltaX = Double.compare(getX(), loc.getX()); - - return deltaX != 0 ? deltaX : Double.compare(getZ(), loc.getZ()); - } - - @Override - public MazePoint add(double x, double y, double z) { - super.add((int) x, (int) y, (int) z); - return this; - } - - @Override - public MazePoint add(Vector vec) { - super.add(vec); - return this; - } - - @Override - public MazePoint subtract(Vector vec) { - super.subtract(vec); - return this; - } - - @Override - public boolean equals(Object obj) { - - - if(obj == null || !obj.getClass().isAssignableFrom(super.getClass())) { - return false; - } - - Location other = (Location) obj; - - if(getWorld() != other.getWorld()) { - return false; - } - - return - getBlockX() == other.getBlockX() && - getBlockZ() == other.getBlockZ(); - } - - @Override - public String toString() { - return "[" + getWorld().getName() + ",x:" + getBlockX() + ",y:" + getBlockY() + ",z:" + getBlockZ() + "]"; - } - - @Override - public MazePoint clone() { - return new MazePoint(this); - } - - @Override - public int hashCode() { - - int hash = 3; - - hash = 19 * hash + (getWorld() != null ? getWorld().hashCode() : 0); - hash = 19 * hash + (getBlockX() ^ getBlockX() >>> 32); - hash = 19 * hash + (getBlockZ() ^ getBlockZ() >>> 32); - - return hash; - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/ReflectionMaterials.java b/src/me/gorgeousone/tangledmaze/util/ReflectionMaterials.java deleted file mode 100644 index 68a1028..0000000 --- a/src/me/gorgeousone/tangledmaze/util/ReflectionMaterials.java +++ /dev/null @@ -1,103 +0,0 @@ -package me.gorgeousone.tangledmaze.util; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Objects; - -public final class ReflectionMaterials { - - private static final String version = Bukkit.getServer().getClass().getName().split("\\.")[3]; - - private static final Class MINECRAFT_KEY = getMcClass("net.minecraft.server.%s.MinecraftKey"); - private static final Constructor MINECRAFT_KEY_CONSTRUCTOR = getConstructor(Objects.requireNonNull(MINECRAFT_KEY), String.class); - - private static final Class ITEM_CLASS = getMcClass("net.minecraft.server.%s.Item"); - private static final Object ITEM_REGISTRY = getFieldInstance(Objects.requireNonNull(getDeclaredField(ITEM_CLASS, "REGISTRY")), null); - - private static final Class MINECRAFT_REGISTRY = getMcClass("net.minecraft.server.%s.RegistryMaterials"); - private static final Method MINECRAFT_REGISTRY_GET = getDeclaredMethod(Objects.requireNonNull(MINECRAFT_REGISTRY), "get", Object.class); - - private static final Class CRAFTITEMSTACK = getMcClass("org.bukkit.craftbukkit.%s.inventory.CraftItemStack"); - private static final Method CRAFTITEMSTACK_NEW_CRAFTSTACK = getDeclaredMethod(Objects.requireNonNull(CRAFTITEMSTACK), "asNewCraftStack", ITEM_CLASS); - - private ReflectionMaterials() {} - - public static Material getMaterial(String mcName){ - - try { - Object mcKey = Objects.requireNonNull(MINECRAFT_KEY_CONSTRUCTOR).newInstance(mcName); - ItemStack itemStack = (ItemStack) Objects.requireNonNull(CRAFTITEMSTACK_NEW_CRAFTSTACK).invoke(null, Objects.requireNonNull(MINECRAFT_REGISTRY_GET).invoke(ITEM_REGISTRY, mcKey)); - - if(itemStack.getType() == Material.AIR && !mcName.equalsIgnoreCase("AIR")) { - return null; - } - - return itemStack.getType(); - - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - return null; - } - - private static Class getMcClass(String clazz){ - - try { - return Class.forName(String.format(clazz, version)); - - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - private static Method getDeclaredMethod(Class clazz, String name, Class... parameters){ - - try { - return clazz.getDeclaredMethod(name, parameters); - - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - return null; - } - - private static Field getDeclaredField(Class clazz, String name){ - - try { - return clazz.getDeclaredField(name); - - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } - return null; - } - - private static Object getFieldInstance(Field field, Object handle){ - - try { - return field.get(handle); - - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - - private static Constructor getConstructor(Class clazz, Class... parameters){ - - try { - return clazz.getConstructor(parameters); - - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - return null; - } -} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/Serializer.java b/src/me/gorgeousone/tangledmaze/util/Serializer.java new file mode 100644 index 0000000..ba3c0aa --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/util/Serializer.java @@ -0,0 +1,54 @@ +package me.gorgeousone.tangledmaze.util; + +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; + +import me.gorgeousone.tangledmaze.clip.Clip; +import me.gorgeousone.tangledmaze.core.Maze; + +public final class Serializer { + + private Serializer() {} + + public static void saveMaze(Maze maze, FileConfiguration config, String path) { + + config.set(path + ".world", maze.getWorld()); + saveClip(maze.getClip(), config, path + ".clip"); + config.set(path + ".exits", maze.getExits()); + + config.set(path + ".path-width", maze.getPathWidth()); + config.set(path + ".wall-width", maze.getWallWidth()); + config.set(path + ".wall-height", maze.getWallHeight()); + } + + public static void saveClip(Clip clip, FileConfiguration config, String path) { + + config.set(path + ".fill", clip.getFillSet()); + config.set(path + ".border", clip.getBorder()); + } + + @SuppressWarnings("unchecked") + public static Maze loadMaze(FileConfiguration config, String path) { + + World mazeWorld = Bukkit.getWorld(config.getString(path + ".world")); + Maze maze = new Maze(mazeWorld); + + maze.setClip(loadClip(config, path + ".clip")); + maze.getExits().addAll((List) config.getList(path + ".exits")); + + maze.setPathWidth(config.getInt(path + ".path-width", 1)); + maze.setWallWidth(config.getInt(path + ".wall-width", 1)); + maze.setWallHeight(config.getInt(path + ".wall-height", 2)); + + return maze; + } + + public static Clip loadClip(FileConfiguration config, String path) { + + + return null; + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/TextException.java b/src/me/gorgeousone/tangledmaze/util/TextException.java new file mode 100644 index 0000000..eebc2b1 --- /dev/null +++ b/src/me/gorgeousone/tangledmaze/util/TextException.java @@ -0,0 +1,22 @@ +package me.gorgeousone.tangledmaze.util; + +public class TextException extends Exception { + + private static final long serialVersionUID = 1L; + private TextMessage text; + private PlaceHolder placeHolder; + + public TextException(TextMessage message, PlaceHolder placeHolder) { + + this.text = message; + this.placeHolder = placeHolder; + } + + public TextMessage getText() { + return text; + } + + public PlaceHolder getPlaceHolder() { + return placeHolder; + } +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/TextMessage.java b/src/me/gorgeousone/tangledmaze/util/TextMessage.java index 385d762..9769ef6 100644 --- a/src/me/gorgeousone/tangledmaze/util/TextMessage.java +++ b/src/me/gorgeousone/tangledmaze/util/TextMessage.java @@ -23,7 +23,7 @@ public void setText(String message, boolean readColorCodes) { paragraphs = alteredMessage.split("\\\\n"); - if(paragraphs.length < 2 || !readColorCodes) { + if(paragraphs.length < 2) { return; } @@ -41,8 +41,13 @@ public void send(CommandSender sender) { public void send(CommandSender sender, PlaceHolder placeHolder) { - for(String paragraph : paragraphs) { - sender.sendMessage(paragraph.replaceAll("%" + placeHolder.getKey() + "%", placeHolder.getValueString())); + if(placeHolder == null) { + + send(sender); + return; } + + for(String paragraph : paragraphs) + sender.sendMessage(paragraph.replaceAll("%" + placeHolder.getKey() + "%", placeHolder.getValueString())); } -} +} \ No newline at end of file diff --git a/src/me/gorgeousone/tangledmaze/util/Utils.java b/src/me/gorgeousone/tangledmaze/util/Utils.java index f43d6b4..803d67d 100644 --- a/src/me/gorgeousone/tangledmaze/util/Utils.java +++ b/src/me/gorgeousone/tangledmaze/util/Utils.java @@ -14,6 +14,7 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; @@ -26,7 +27,7 @@ public static boolean isMazeWand(ItemStack item) { if(item == null) return false; - if(item.getType() != Settings.MAZE_WAND_ITEM) { + if(item.getType() != Settings.MAZE_WAND_MATERIAL) { return false; } @@ -39,13 +40,13 @@ public static boolean isMazeWand(ItemStack item) { public static ItemStack getMazeWand() { - ItemMeta rndMeta = Settings.MAZE_WAND.getItemMeta(); + ItemStack wand = Settings.MAZE_WAND.clone(); + ItemMeta rndMeta = wand.getItemMeta(); List lore = rndMeta.getLore(); lore.set(0, ChatColor.GRAY + getRndMazeWandEnchantment()); rndMeta.setLore(lore); - ItemStack wand = Settings.MAZE_WAND.clone(); wand.setItemMeta(rndMeta); return wand; @@ -56,7 +57,8 @@ private static String getRndMazeWandEnchantment() { int rndIndex = (int) (Math.random() * Constants.MAZE_WAND_ENCHANTS.length); return Constants.MAZE_WAND_ENCHANTS[rndIndex]; } - + + //use methos mat.is public static boolean isLikeGround(Material mat) { return mat.isSolid() && !Constants.NOT_SOLIDS.contains(mat); } @@ -65,9 +67,9 @@ public static boolean canBeOverbuild(Material mat) { return !mat.isSolid() || Constants.REPLACEABLE_SOLIDS.contains(mat); } - public static MazePoint nearestSurface(Location loc) { - - MazePoint iter = new MazePoint(loc); + public static Location nearestSurface(Location loc) { + + Location iter = loc.clone(); if(isLikeGround(iter.getBlock().getType())) { @@ -91,21 +93,52 @@ public static MazePoint nearestSurface(Location loc) { } } - return new MazePoint(loc); + return loc; + } + + public static int nearestSurfaceY(Vec2 loc, int height, World world) { + + Location iter = new Location(world, loc.getX(), height, loc.getZ()); + + if(isLikeGround(iter.getBlock().getType())) { + + while(iter.getY() <= 255) { + + iter.add(0, 1, 0); + + if(!isLikeGround(iter.getBlock().getType())) { + iter.add(0, -1, 0); + return iter.getBlockY(); + } + } + + }else { + + while(iter.getY() >= 0) { + + iter.add(0, -1, 0); + + if(isLikeGround(iter.getBlock().getType())) { + return iter.getBlockY(); + } + } + } + + return height; } - public static int limitInt(int value, int min, int max) { + public static int limit(int value, int min, int max) { return Math.min(max, Math.max(min, value)); } - public static int getMaxHeight(ArrayList points) { + public static int getMaxHeight(ArrayList locs) { int min = 0; - for(MazePoint point : points) { - if(point.getBlockY() > min) { + for(Location point : locs) { + + if(point.getBlockY() > min) min = point.getBlockY(); - } } return min; diff --git a/src/me/gorgeousone/tangledmaze/util/Vec2.java b/src/me/gorgeousone/tangledmaze/util/Vec2.java index f25144f..056f734 100644 --- a/src/me/gorgeousone/tangledmaze/util/Vec2.java +++ b/src/me/gorgeousone/tangledmaze/util/Vec2.java @@ -1,63 +1,84 @@ package me.gorgeousone.tangledmaze.util; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.util.Vector; -public class Vec2 { +public class Vec2 implements Comparable, ConfigurationSerializable { - private float x, z; + private int x, z; public Vec2() { this.x = 0; this.z = 0; } - public Vec2(float x, float z) { + public Vec2(int x, int z) { this.x = x; this.z = z; } - public Vec2(Vector vec3) { - this.x = vec3.getBlockX(); - this.z = vec3.getBlockZ(); + public Vec2(Location loc) { + this.x = loc.getBlockX(); + this.z = loc.getBlockZ(); } - public float getX() { - return x; + public Vec2(Block block) { + this.x = block.getX(); + this.z = block.getZ(); } - public float getZ() { - return z; + public Vec2(String serialized) { + + if(!serialized.startsWith("vec2[x:") || !serialized.endsWith("]")) + throw new IllegalArgumentException(); + + String[] location = serialized.substring(5, serialized.length()-1).split(","); + + if(location.length != 2) + throw new IllegalArgumentException(); + + this.x = Integer.parseInt(location[0].substring(3)); + this.z = Integer.parseInt(location[1].substring(3)); + } + + public int getX() { + return x; } - public int getIntX() { - return (int) x; + public int getZ() { + return z; } - public int getIntZ() { - return (int) z; + public int length() { + return (int) Math.sqrt(x*x + z*z); } - public float length() { - return (float) Math.sqrt(x*x + z*z); + public boolean isZero() { + return x == 0 && z == 0; } - public Vec2 set(float x, float z) { + public Vec2 set(int x, int z) { this.x = x; this.z = z; return this; } - public Vec2 setX(float x) { + public Vec2 setX(int x) { this.x = x; return this; } - public Vec2 setZ(float z) { + public Vec2 setZ(int z) { this.z = z; return this; } - public Vec2 add(float dx, float dz) { + public Vec2 add(int dx, int dz) { x += dx; z += dz; return this; @@ -75,23 +96,12 @@ public Vec2 sub(Vec2 vec2) { return this; } - public Vec2 mult(float i) { + public Vec2 mult(int i) { x *= i; z *= i; return this; } - public Vec2 cross(Vec2 vec2) { - x *= vec2.z; - z *= vec2.x; - return this; - } - - public Vec2 normalize() { - mult(1f / length()); - return this; - } - public Vec2 getAbs() { return new Vec2(Math.abs(x), Math.abs(z)); } @@ -102,7 +112,7 @@ public Vector toVec3() { @Override public String toString() { - return "vec2[x:" + x + ", z:" + z + "]"; + return "vec2[x:" + x + ",z:" + z + "]"; } @Override @@ -115,9 +125,45 @@ public int hashCode() { int hash = 3; - hash = 19 * hash + (getIntX() ^ getIntX() >>> 32); - hash = 19 * hash + (getIntZ() ^ getIntZ() >>> 32); + hash = 19 * hash + (getX() ^ getX() >>> 32); + hash = 19 * hash + (getZ() ^ getZ() >>> 32); return hash; } + + @Override + public boolean equals(Object obj) { + + if(obj == null || obj.getClass() != this.getClass()) + return false; + + Vec2 otherVec = (Vec2) obj; + + return otherVec.getX() == getX() && otherVec.getZ() == getZ(); + } + + @Override + public int compareTo(Vec2 vec) { + + int deltaX = Double.compare(getX(), vec.getX()); + return deltaX != 0 ? deltaX : Double.compare(getZ(), vec.getZ()); + } + + @Override + public Map serialize() { + + Map data = new HashMap<>(); + + data.put("x", Integer.valueOf(x)); + data.put("z", Integer.valueOf(z)); + + return data; + } + + public static Vec2 desrialize(Map data) { + + return new Vec2( + Integer.parseInt(data.get("x").toString()), + Integer.parseInt(data.get("z").toString())); + } } \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml index 6cc4f01..1223d86 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,6 +1,7 @@ name: TangledMaze -version: 1.2.1 +version: 1.2.4 authors: [GorgeousOne] +api-version: 1.13 main: me.gorgeousone.tangledmaze.core.TangledMain @@ -9,6 +10,7 @@ commands: usage: / help description: 'Main command for all sub-commands: reload, wand, start, select, add, cut, discard, build, teleport.' aliases: [maze, tm] + default: op permissions: tangledmaze.reload: