From ad53066846fb168255499a332a1ad4bca39f5935 Mon Sep 17 00:00:00 2001 From: bowser0000 Date: Sat, 27 Feb 2021 18:25:51 -0500 Subject: Move features into their own files --- .../features/puzzlesolvers/TriviaSolver.java | 105 +++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java (limited to 'src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java') diff --git a/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java new file mode 100644 index 0000000..ac2cd0c --- /dev/null +++ b/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java @@ -0,0 +1,105 @@ +package me.Danker.features.puzzlesolvers; + +import me.Danker.commands.ToggleCommand; +import me.Danker.utils.Utils; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StringUtils; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.HashMap; +import java.util.Map; + +public class TriviaSolver { + + static Map triviaSolutions = new HashMap<>(); + static String[] triviaAnswers = null; + public static String TRIVIA_WRONG_ANSWER_COLOUR; + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + triviaSolutions.put("What is the status of The Watcher?", new String[]{"Stalker"}); + triviaSolutions.put("What is the status of Bonzo?", new String[]{"New Necromancer"}); + triviaSolutions.put("What is the status of Scarf?", new String[]{"Apprentice Necromancer"}); + triviaSolutions.put("What is the status of The Professor?", new String[]{"Professor"}); + triviaSolutions.put("What is the status of Thorn?", new String[]{"Shaman Necromancer"}); + triviaSolutions.put("What is the status of Livid?", new String[]{"Master Necromancer"}); + triviaSolutions.put("What is the status of Sadan?", new String[]{"Necromancer Lord"}); + triviaSolutions.put("What is the status of Maxor?", new String[]{"Young Wither"}); + triviaSolutions.put("What is the status of Goldor?", new String[]{"Wither Soldier"}); + triviaSolutions.put("What is the status of Storm?", new String[]{"Elementalist"}); + triviaSolutions.put("What is the status of Necron?", new String[]{"Wither Lord"}); + triviaSolutions.put("How many total Fairy Souls are there?", new String[]{"220 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Spider's Den?", new String[]{"17 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in The End?", new String[]{"12 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in The Barn?", new String[]{"7 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Mushroom Desert?", new String[]{"8 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Blazing Fortress?", new String[]{"19 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in The Park?", new String[]{"11 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Jerry's Workshop?", new String[]{"5 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Hub?", new String[]{"79 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in The Hub?", new String[]{"79 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Deep Caverns?", new String[]{"21 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Gold Mine?", new String[]{"12 Fairy Souls"}); + triviaSolutions.put("How many Fairy Souls are there in Dungeon Hub?", new String[]{"7 Fairy Souls"}); + triviaSolutions.put("Which brother is on the Spider's Den?", new String[]{"Rick"}); + triviaSolutions.put("What is the name of Rick's brother?", new String[]{"Pat"}); + triviaSolutions.put("What is the name of the Painter in the Hub?", new String[]{"Marco"}); + triviaSolutions.put("What is the name of the person that upgrades pets?", new String[]{"Kat"}); + triviaSolutions.put("What is the name of the lady of the Nether?", new String[]{"Elle"}); + triviaSolutions.put("Which villager in the Village gives you a Rogue Sword?", new String[]{"Jamie"}); + triviaSolutions.put("How many unique minions are there?", new String[]{"53 Minions"}); + triviaSolutions.put("Which of these enemies does not spawn in the Spider's Den?", new String[]{"Zombie Spider", "Cave Spider", "Wither Skeleton", + "Dashing Spooder", "Broodfather", "Night Spider"}); + triviaSolutions.put("Which of these monsters only spawns at night?", new String[]{"Zombie Villager", "Ghast"}); + triviaSolutions.put("Which of these is not a dragon in The End?", new String[]{"Zoomer Dragon", "Weak Dragon", "Stonk Dragon", "Holy Dragon", "Boomer Dragon", + "Booger Dragon", "Older Dragon", "Elder Dragon", "Stable Dragon", "Professor Dragon"}); + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onChat(ClientChatReceivedEvent event) { + String message = StringUtils.stripControlCodes(event.message.getUnformattedText()); + + if (!Utils.inDungeons) return; + if (event.type == 2) return; + + if (ToggleCommand.oruoToggled) { + if (message.contains("What SkyBlock year is it?")) { + double currentTime = System.currentTimeMillis() /1000L; + + double diff = Math.floor(currentTime - 1560276000); + + int year = (int) (diff / 446400 + 1); + triviaAnswers = new String[]{"Year " + year}; + } else { + for (String question : triviaSolutions.keySet()) { + if (message.contains(question)) { + triviaAnswers = triviaSolutions.get(question); + break; + } + } + } + + // Set wrong answers to red and remove click events + if (triviaAnswers != null && (message.contains("ⓐ") || message.contains("ⓑ") || message.contains("ⓒ"))) { + boolean isSolution = false; + for (String solution : triviaAnswers) { + if (message.contains(solution)) { + isSolution = true; + break; + } + } + if (!isSolution) { + char letter = message.charAt(5); + String option = message.substring(6); + event.message = new ChatComponentText(" " + EnumChatFormatting.GOLD + letter + TRIVIA_WRONG_ANSWER_COLOUR + option); + } + } + } + } + +} -- cgit From e7237307e71c649b4b7c880259ff1781fcc7c435 Mon Sep 17 00:00:00 2001 From: bowser0000 Date: Thu, 4 Mar 2021 22:00:19 -0500 Subject: Add boulder puzzle solver --- README.md | 15 +- src/main/java/me/Danker/DankersSkyblockMod.java | 6 +- src/main/java/me/Danker/commands/DHelpCommand.java | 3 +- .../java/me/Danker/commands/DankerGuiCommand.java | 4 + .../java/me/Danker/commands/ToggleCommand.java | 19 +- src/main/java/me/Danker/features/AutoDisplay.java | 1 - .../java/me/Danker/features/BlockAbilities.java | 84 +++++++ .../java/me/Danker/features/loot/LootDisplay.java | 1 - .../features/puzzlesolvers/BlockAbilities.java | 84 ------- .../features/puzzlesolvers/BoulderSolver.java | 188 ++++++++++++++ .../features/puzzlesolvers/CreeperSolver.java | 2 +- .../features/puzzlesolvers/ThreeManSolver.java | 2 +- .../features/puzzlesolvers/TriviaSolver.java | 5 +- src/main/java/me/Danker/gui/DisplayGui.java | 1 - src/main/java/me/Danker/gui/PuzzleSolversGui.java | 19 +- .../java/me/Danker/handlers/ConfigHandler.java | 4 +- src/main/java/me/Danker/utils/BoulderUtils.java | 280 +++++++++++++++++++++ src/main/java/me/Danker/utils/Utils.java | 24 +- 18 files changed, 623 insertions(+), 119 deletions(-) create mode 100644 src/main/java/me/Danker/features/BlockAbilities.java delete mode 100644 src/main/java/me/Danker/features/puzzlesolvers/BlockAbilities.java create mode 100644 src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java create mode 100644 src/main/java/me/Danker/utils/BoulderUtils.java (limited to 'src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java') diff --git a/README.md b/README.md index e96ce00..6673b43 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,11 @@ Discord Server: https://discord.gg/QsEkNQS - Click anywhere on-screen to open Maddox - Maddox menu keybind - Block starting other slayer quests +- Slayer slain alert - Fishing, jerry fishing, fishing festival, spooky fishing trackers - Expertise kills in fishing rod lore - Catacombs trackers -- Dungeons puzzle solver (Riddle, trivia, blaze, creeper, water, tic tac toe) +- Dungeons puzzle solver (Riddle, trivia, blaze, creeper, water, tic tac toe, boulder) - Dungeons timer (watcher, boss, deaths, and puzzle fails) - Watcher ready message - Catacombs F7 Stage 3 solvers (Starts with letter, select all colour, ignore arrows on sea lanterns) @@ -52,14 +53,14 @@ Discord Server: https://discord.gg/QsEkNQS ## Commands - /dhelp - Returns this message in-game. - /dsm - Opens the GUI for Danker's Skyblock Mod. -- /toggle - Toggles features. /toggle list returns values of every toggle. +- /toggle - Toggles features. /toggle list returns values of every toggle. - /setkey - Sets API key. - /getkey - Returns key set with /setkey and copies it to your clipboard. -- /loot [winter/spooky/f(1-7)/session] - Returns loot received from slayer quests or fishing stats. /loot fishing winter returns winter sea creatures instead. -- /display [winter/spooky/f(1-7)/session] - Text display for trackers. /display fishing winter displays winter sea creatures instead. /display auto automatically displays the loot for the slayer quest you have active. -- /resetloot - - Resets loot for trackers. /resetloot confirm confirms the reset. -- /move - Moves text display to specified X and Y coordinates. -- /scale - Scales text display to a specified multipler between 0.1x and 10x. +- /loot [winter/festival/spooky/f(1-7)/session] - Returns loot received from slayer quests or fishing stats. /loot fishing winter returns winter sea creatures instead. +- /display [winter/festival/spooky/f(1-7)/session] - Text display for trackers. /display fishing winter displays winter sea creatures instead. /display auto automatically displays the loot for the slayer quest you have active. +- /resetloot - - Resets loot for trackers. /resetloot confirm confirms the reset. +- /move - Moves text display to specified X and Y coordinates. +- /scale - Scales text display to a specified multipler between 0.1x and 10x. - /slayer [player] - Uses API to get slayer xp of a person. If no name is provided, it checks yours. - /skills [player] - Uses API to get skill levels of a person. If no name is provided, it checks yours. - /lobbyskills - Uses API to find the average skills of the lobby, as well the three players with the highest skill average. diff --git a/src/main/java/me/Danker/DankersSkyblockMod.java b/src/main/java/me/Danker/DankersSkyblockMod.java index 38e956f..0920520 100644 --- a/src/main/java/me/Danker/DankersSkyblockMod.java +++ b/src/main/java/me/Danker/DankersSkyblockMod.java @@ -65,8 +65,8 @@ public class DankersSkyblockMod { public static String titleText = ""; public static int tickAmount = 1; public static KeyBinding[] keyBindings = new KeyBinding[3]; - static boolean usingLabymod = false; - static boolean usingOAM = false; + public static boolean usingLabymod = false; + public static boolean usingOAM = false; static boolean OAMWarning = false; public static String guiToOpen = null; public static boolean firstLaunch = false; @@ -92,6 +92,7 @@ public class DankersSkyblockMod { MinecraftForge.EVENT_BUS.register(new BlockWrongSlayer()); MinecraftForge.EVENT_BUS.register(new BlockWrongTerminalClicks()); MinecraftForge.EVENT_BUS.register(new BonzoMaskTimer()); + MinecraftForge.EVENT_BUS.register(new BoulderSolver()); MinecraftForge.EVENT_BUS.register(new CakeTimer()); MinecraftForge.EVENT_BUS.register(new ChronomatronSolver()); MinecraftForge.EVENT_BUS.register(new ClickInOrderSolver()); @@ -130,6 +131,7 @@ public class DankersSkyblockMod { ConfigHandler.reloadConfig(); GoldenEnchants.init(); + TriviaSolver.init(); keyBindings[0] = new KeyBinding("Open Maddox Menu", Keyboard.KEY_M, "Danker's Skyblock Mod"); keyBindings[1] = new KeyBinding("Regular Ability", Keyboard.KEY_NUMPAD4, "Danker's Skyblock Mod"); diff --git a/src/main/java/me/Danker/commands/DHelpCommand.java b/src/main/java/me/Danker/commands/DHelpCommand.java index bcaf8b0..6272a60 100644 --- a/src/main/java/me/Danker/commands/DHelpCommand.java +++ b/src/main/java/me/Danker/commands/DHelpCommand.java @@ -34,7 +34,7 @@ public class DHelpCommand extends CommandBase { EnumChatFormatting.GOLD + " Commands, " + EnumChatFormatting.GREEN + " Keybinds.\n" + EnumChatFormatting.GOLD + " /dhelp" + EnumChatFormatting.AQUA + " - Returns this message.\n" + EnumChatFormatting.GOLD + " /dsm" + EnumChatFormatting.AQUA + " - Opens the GUI for Danker's Skyblock Mod.\n" + - EnumChatFormatting.GOLD + " /toggle " + EnumChatFormatting.AQUA + " - Toggles features. /toggle list returns values of every toggle.\n" + + EnumChatFormatting.GOLD + " /toggle " + EnumChatFormatting.AQUA + " - Toggles features. /toggle list returns values of every toggle.\n" + EnumChatFormatting.GOLD + " /setkey " + EnumChatFormatting.AQUA + " - Sets API key.\n" + EnumChatFormatting.GOLD + " /getkey" + EnumChatFormatting.AQUA + " - Returns key set with /setkey and copies it to your clipboard.\n" + EnumChatFormatting.GOLD + " /loot [winter/festival/spooky/f(1-7)/session]" + EnumChatFormatting.AQUA + " - Returns loot received from slayer quests or fishing stats. /loot fishing winter returns winter sea creatures instead.\n" + @@ -54,6 +54,7 @@ public class DHelpCommand extends CommandBase { EnumChatFormatting.GOLD + " /sbplayers" + EnumChatFormatting.AQUA + " - Uses API to find how many players are on each Skyblock island.\n" + EnumChatFormatting.GOLD + " /onlyslayer <1/2/3/4>" + EnumChatFormatting.AQUA + " - Stops you from starting a slayer quest other than the one specified.\n" + EnumChatFormatting.GOLD + " /skilltracker " + EnumChatFormatting.AQUA + " - Text display for skill xp/hour.\n" + + EnumChatFormatting.GOLD + " /reparty " + EnumChatFormatting.AQUA + " - Disbands and reparties all members in the party.\n" + EnumChatFormatting.GREEN + " Open Maddox Menu" + EnumChatFormatting.AQUA + " - M by default.\n" + EnumChatFormatting.GREEN + " Start/Stop Skill Tracker" + EnumChatFormatting.AQUA + " - Numpad 5 by default.\n")); } diff --git a/src/main/java/me/Danker/commands/DankerGuiCommand.java b/src/main/java/me/Danker/commands/DankerGuiCommand.java index 5ffd754..9ba86da 100644 --- a/src/main/java/me/Danker/commands/DankerGuiCommand.java +++ b/src/main/java/me/Danker/commands/DankerGuiCommand.java @@ -72,6 +72,7 @@ public class DankerGuiCommand extends CommandBase { debug.append("[creeperpuzzle][").append(ToggleCommand.creeperToggled).append("]\n"); debug.append("[waterpuzzle][").append(ToggleCommand.waterToggled).append("]\n"); debug.append("[tictactoepuzzle][").append(ToggleCommand.ticTacToeToggled).append("]\n"); + debug.append("[boulderpuzzle][").append(ToggleCommand.boulderToggled).append("]\n"); debug.append("[watchermessage][").append(ToggleCommand.watcherReadyToggled).append("]\n"); debug.append("[startswithterminal][").append(ToggleCommand.startsWithToggled).append("]\n"); debug.append("[selectallterminal][").append(ToggleCommand.selectAllToggled).append("]\n"); @@ -96,6 +97,9 @@ public class DankerGuiCommand extends CommandBase { debug.append("[Current Display][").append(LootDisplay.display).append("]\n"); debug.append("[Auto Display][").append(LootDisplay.auto).append("]\n"); debug.append("[Skill Tracker Visible][").append(SkillTracker.showSkillTracker).append("]\n"); + debug.append("# Problematic Mods\n"); + debug.append("[LabyMod][").append(DankersSkyblockMod.usingLabymod).append("]\n"); + debug.append("[OAM][").append(DankersSkyblockMod.usingOAM).append("]\n"); debug.append("# Resource Packs\n"); if (Minecraft.getMinecraft().getResourcePackRepository().getRepositoryEntries().size() == 0) { debug.append("\n"); diff --git a/src/main/java/me/Danker/commands/ToggleCommand.java b/src/main/java/me/Danker/commands/ToggleCommand.java index b632abc..77dc82e 100644 --- a/src/main/java/me/Danker/commands/ToggleCommand.java +++ b/src/main/java/me/Danker/commands/ToggleCommand.java @@ -55,6 +55,7 @@ public class ToggleCommand extends CommandBase implements ICommand { public static boolean creeperToggled; public static boolean waterToggled; public static boolean ticTacToeToggled; + public static boolean boulderToggled; // Terminal Helpers public static boolean startsWithToggled; public static boolean selectAllToggled; @@ -76,11 +77,13 @@ public class ToggleCommand extends CommandBase implements ICommand { public String getCommandUsage(ICommandSender arg0) { return "/" + getCommandName() + " "; + "aotd/lividdagger/flowerweapons/sceptremessages/petcolors/dungeontimer/golemalerts/expertiselore/" + + "skill50display/outlinetext/midasstaffmessages/implosionmessages/healmessages/cooldownmessages/" + + "manamessages/caketimer/lowhealthnotify/lividsolver/stopsalvagestarred/notifyslayerslain/" + + "necronnotifications/bonzotimer/threemanpuzzle/oruopuzzle/blazepuzzle/creeperpuzzle/waterpuzzle/" + + "tictactoepuzzle/boulderpuzzle/watchermessage/startswithterminal/selectallterminal/" + + "clickinorderterminal/blockwrongterminalclicks/itemframeonsealanterns/ultrasequencer/" + + "chronomatron/superpairs/hidetooltipsinaddons/pickblock/list>"; } @Override @@ -301,6 +304,11 @@ public class ToggleCommand extends CommandBase implements ICommand { ConfigHandler.writeBooleanConfig("toggles", "TicTacToePuzzle", ticTacToeToggled); player.addChatMessage(new ChatComponentText(DankersSkyblockMod.MAIN_COLOUR + "Tic tac toe puzzle solver has been set to " + DankersSkyblockMod.SECONDARY_COLOUR + ticTacToeToggled + DankersSkyblockMod.MAIN_COLOUR + ".")); break; + case "boulderpuzzle": + boulderToggled = !boulderToggled; + ConfigHandler.writeBooleanConfig("toggles", "BoulderPuzzle", boulderToggled); + player.addChatMessage(new ChatComponentText(DankersSkyblockMod.MAIN_COLOUR + "Boulder puzzle solver has been set to " + DankersSkyblockMod.SECONDARY_COLOUR + boulderToggled + DankersSkyblockMod.MAIN_COLOUR + ".")); + break; case "watchermessage": watcherReadyToggled = !watcherReadyToggled; ConfigHandler.writeBooleanConfig("toggles", "WatcherReadyMessage", watcherReadyToggled); @@ -390,6 +398,7 @@ public class ToggleCommand extends CommandBase implements ICommand { DankersSkyblockMod.TYPE_COLOUR + " Creeper puzzle solver: " + DankersSkyblockMod.VALUE_COLOUR + creeperToggled + "\n" + DankersSkyblockMod.TYPE_COLOUR + " Water puzzle solver: " + DankersSkyblockMod.VALUE_COLOUR + waterToggled + "\n" + DankersSkyblockMod.TYPE_COLOUR + " Tic tac toe puzzle solver: " + DankersSkyblockMod.VALUE_COLOUR + ticTacToeToggled + "\n" + + DankersSkyblockMod.TYPE_COLOUR + " Boulder puzzle solver: " + DankersSkyblockMod.VALUE_COLOUR + boulderToggled + "\n" + DankersSkyblockMod.TYPE_COLOUR + " Watcher ready message: " + DankersSkyblockMod.VALUE_COLOUR + watcherReadyToggled + "\n" + DankersSkyblockMod.TYPE_COLOUR + " Starts with letter terminal solver: " + DankersSkyblockMod.VALUE_COLOUR + startsWithToggled + "\n" + DankersSkyblockMod.TYPE_COLOUR + " Select all color items terminal solver: " + DankersSkyblockMod.VALUE_COLOUR + selectAllToggled + "\n" + diff --git a/src/main/java/me/Danker/features/AutoDisplay.java b/src/main/java/me/Danker/features/AutoDisplay.java index 5411034..876fb6a 100644 --- a/src/main/java/me/Danker/features/AutoDisplay.java +++ b/src/main/java/me/Danker/features/AutoDisplay.java @@ -1,7 +1,6 @@ package me.Danker.features; import me.Danker.DankersSkyblockMod; -import me.Danker.commands.DisplayCommand; import me.Danker.features.loot.LootDisplay; import me.Danker.handlers.ConfigHandler; import me.Danker.handlers.ScoreboardHandler; diff --git a/src/main/java/me/Danker/features/BlockAbilities.java b/src/main/java/me/Danker/features/BlockAbilities.java new file mode 100644 index 0000000..19a887c --- /dev/null +++ b/src/main/java/me/Danker/features/BlockAbilities.java @@ -0,0 +1,84 @@ +package me.Danker.features; + +import me.Danker.commands.ToggleCommand; +import me.Danker.utils.Utils; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.ArrayList; +import java.util.Arrays; + +public class BlockAbilities { + + @SubscribeEvent + public void onInteract(PlayerInteractEvent event) { + if (!Utils.inSkyblock || Minecraft.getMinecraft().thePlayer != event.entityPlayer) return; + ItemStack item = event.entityPlayer.getHeldItem(); + if (item == null) return; + + if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR) { + if (ToggleCommand.aotdToggled && item.getDisplayName().contains("Aspect of the Dragons")) { + event.setCanceled(true); + } + if (ToggleCommand.lividDaggerToggled && item.getDisplayName().contains("Livid Dagger")) { + event.setCanceled(true); + } + } else if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock(); + + ArrayList interactables = new ArrayList<>(Arrays.asList( + Blocks.acacia_door, + Blocks.anvil, + Blocks.beacon, + Blocks.bed, + Blocks.birch_door, + Blocks.brewing_stand, + Blocks.command_block, + Blocks.crafting_table, + Blocks.chest, + Blocks.dark_oak_door, + Blocks.daylight_detector, + Blocks.daylight_detector_inverted, + Blocks.dispenser, + Blocks.dropper, + Blocks.enchanting_table, + Blocks.ender_chest, + Blocks.furnace, + Blocks.hopper, + Blocks.jungle_door, + Blocks.lever, + Blocks.noteblock, + Blocks.powered_comparator, + Blocks.unpowered_comparator, + Blocks.powered_repeater, + Blocks.unpowered_repeater, + Blocks.standing_sign, + Blocks.wall_sign, + Blocks.trapdoor, + Blocks.trapped_chest, + Blocks.wooden_button, + Blocks.stone_button, + Blocks.oak_door, + Blocks.skull + )); + if (Utils.inDungeons) { + interactables.add(Blocks.coal_block); + interactables.add(Blocks.stained_hardened_clay); + } + + if (!interactables.contains(block)) { + if (ToggleCommand.aotdToggled && item.getDisplayName().contains("Aspect of the Dragons")) { + event.setCanceled(true); + } + if (ToggleCommand.lividDaggerToggled && item.getDisplayName().contains("Livid Dagger")) { + event.setCanceled(true); + } + } + } + } + +} diff --git a/src/main/java/me/Danker/features/loot/LootDisplay.java b/src/main/java/me/Danker/features/loot/LootDisplay.java index 4013c0a..363b70c 100644 --- a/src/main/java/me/Danker/features/loot/LootDisplay.java +++ b/src/main/java/me/Danker/features/loot/LootDisplay.java @@ -1,6 +1,5 @@ package me.Danker.features.loot; -import me.Danker.commands.DisplayCommand; import me.Danker.commands.MoveCommand; import me.Danker.commands.ScaleCommand; import me.Danker.commands.ToggleCommand; diff --git a/src/main/java/me/Danker/features/puzzlesolvers/BlockAbilities.java b/src/main/java/me/Danker/features/puzzlesolvers/BlockAbilities.java deleted file mode 100644 index 464b76a..0000000 --- a/src/main/java/me/Danker/features/puzzlesolvers/BlockAbilities.java +++ /dev/null @@ -1,84 +0,0 @@ -package me.Danker.features.puzzlesolvers; - -import me.Danker.commands.ToggleCommand; -import me.Danker.utils.Utils; -import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; -import net.minecraft.init.Blocks; -import net.minecraft.item.ItemStack; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; - -import java.util.ArrayList; -import java.util.Arrays; - -public class BlockAbilities { - - @SubscribeEvent - public void onInteract(PlayerInteractEvent event) { - if (!Utils.inSkyblock || Minecraft.getMinecraft().thePlayer != event.entityPlayer) return; - ItemStack item = event.entityPlayer.getHeldItem(); - if (item == null) return; - - if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR) { - if (ToggleCommand.aotdToggled && item.getDisplayName().contains("Aspect of the Dragons")) { - event.setCanceled(true); - } - if (ToggleCommand.lividDaggerToggled && item.getDisplayName().contains("Livid Dagger")) { - event.setCanceled(true); - } - } else if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { - Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock(); - - ArrayList interactables = new ArrayList<>(Arrays.asList( - Blocks.acacia_door, - Blocks.anvil, - Blocks.beacon, - Blocks.bed, - Blocks.birch_door, - Blocks.brewing_stand, - Blocks.command_block, - Blocks.crafting_table, - Blocks.chest, - Blocks.dark_oak_door, - Blocks.daylight_detector, - Blocks.daylight_detector_inverted, - Blocks.dispenser, - Blocks.dropper, - Blocks.enchanting_table, - Blocks.ender_chest, - Blocks.furnace, - Blocks.hopper, - Blocks.jungle_door, - Blocks.lever, - Blocks.noteblock, - Blocks.powered_comparator, - Blocks.unpowered_comparator, - Blocks.powered_repeater, - Blocks.unpowered_repeater, - Blocks.standing_sign, - Blocks.wall_sign, - Blocks.trapdoor, - Blocks.trapped_chest, - Blocks.wooden_button, - Blocks.stone_button, - Blocks.oak_door, - Blocks.skull - )); - if (Utils.inDungeons) { - interactables.add(Blocks.coal_block); - interactables.add(Blocks.stained_hardened_clay); - } - - if (!interactables.contains(block)) { - if (ToggleCommand.aotdToggled && item.getDisplayName().contains("Aspect of the Dragons")) { - event.setCanceled(true); - } - if (ToggleCommand.lividDaggerToggled && item.getDisplayName().contains("Livid Dagger")) { - event.setCanceled(true); - } - } - } - } - -} diff --git a/src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java new file mode 100644 index 0000000..0089038 --- /dev/null +++ b/src/main/java/me/Danker/features/puzzlesolvers/BoulderSolver.java @@ -0,0 +1,188 @@ +package me.Danker.features.puzzlesolvers; + +import me.Danker.DankersSkyblockMod; +import me.Danker.commands.ToggleCommand; +import me.Danker.utils.BoulderUtils; +import me.Danker.utils.Utils; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.init.Blocks; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.BlockPos; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BoulderSolver { + + static boolean prevInBoulderRoom = false; + static boolean inBoulderRoom = false; + static BlockPos chest = null; + static String boulderRoomDirection = null; + public static List route = new ArrayList<>(); + static int currentStep = 0; + public static int BOULDER_COLOUR; + public static int BOULDER_ARROW_COLOUR; + + @SubscribeEvent + public void onWorldChange(WorldEvent.Load event) { + reset(); + } + + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.START) return; + + Minecraft mc = Minecraft.getMinecraft(); + EntityPlayerSP player = mc.thePlayer; + World world = mc.theWorld; + if (DankersSkyblockMod.tickAmount % 20 == 0) { + if (ToggleCommand.boulderToggled && Utils.inDungeons && world != null && player != null) { + // multi thread block checking + new Thread(() -> { + prevInBoulderRoom = inBoulderRoom; + int quartzBlocksFound = 0; + int barriersFound = 0; + BlockPos plusPlusQuartz = null; + BlockPos minusMinusQuartz = null; + Iterable blocks = BlockPos.getAllInBox(new BlockPos(player.posX - 25, 68, player.posZ - 25), new BlockPos(player.posX + 25, 68, player.posZ + 25)); + // Detect boulder room + for (BlockPos blockPos : blocks) { + if (world.getBlockState(blockPos).getBlock() == Blocks.quartz_block) { + quartzBlocksFound++; + if (plusPlusQuartz == null || (blockPos.getX() >= plusPlusQuartz.getX() && blockPos.getZ() >= plusPlusQuartz.getZ())) { + plusPlusQuartz = blockPos; + } + if (minusMinusQuartz == null || (blockPos.getX() <= minusMinusQuartz.getX() && blockPos.getZ() <= minusMinusQuartz.getZ())) { + minusMinusQuartz = blockPos; + } + if (quartzBlocksFound == 8) { + break; + } + } else if (world.getBlockState(blockPos).getBlock() == Blocks.barrier) { + barriersFound++; + } + } + + if (quartzBlocksFound == 8 && barriersFound >= 350) { + inBoulderRoom = true; + if (!prevInBoulderRoom) { + // Get boulder locations + char[][] board = new char[7][7]; + for (int x = plusPlusQuartz.getX() - 1, iterationX = 0; iterationX < 7; x -= 3, iterationX++) { + for (int z = plusPlusQuartz.getZ() - 1, iterationZ = 0; iterationZ < 7; z -= 3, iterationZ++) { + BlockPos boulderPos = new BlockPos(x, 66, z); + if (world.getBlockState(boulderPos).getBlock() == Blocks.planks) { + board[iterationX][iterationZ] = 'X'; + } + } + } + + // Detect rotation of room + BlockPos northChest = minusMinusQuartz.add(11, -2, -2); + BlockPos eastChest = plusPlusQuartz.add(2, -2, -11); + BlockPos southChest = plusPlusQuartz.add(-11, -2, 2); + BlockPos westChest = minusMinusQuartz.add(-2, -2, 11); + if (world.getBlockState(northChest).getBlock() == Blocks.chest) { + boulderRoomDirection = "north"; + chest = northChest; + board = BoulderUtils.flipVertically(BoulderUtils.rotateClockwise(board)); + } else if (world.getBlockState(eastChest).getBlock() == Blocks.chest) { + boulderRoomDirection = "east"; + chest = eastChest; + board = BoulderUtils.flipHorizontally(board); + } else if (world.getBlockState(southChest).getBlock() == Blocks.chest) { + boulderRoomDirection = "south"; + chest = southChest; + board = BoulderUtils.flipHorizontally(BoulderUtils.rotateClockwise(board)); + } else if (world.getBlockState(westChest).getBlock() == Blocks.chest) { + boulderRoomDirection = "west"; + chest = westChest; + board = BoulderUtils.flipVertically(board); + } else { + player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "Could not determine orientation of boulder room.")); + return; + } + board = BoulderUtils.removeFirstRow(board); + if (BoulderUtils.hasOpenPath(board)) return; + + long startTime = System.currentTimeMillis(); + reset(); + int length = BoulderUtils.findSolution(board, 0, route); + long endTime = System.currentTimeMillis(); + System.out.println("Time elapsed: " + (endTime - startTime) + "ms, " + BoulderUtils.iterations + " iterations."); + if (length == 10) { + player.addChatMessage(new ChatComponentText(DankersSkyblockMod.ERROR_COLOUR + "No solution to puzzle found, most likely puzzle failed.")); + } else { + System.out.println("Solved " + boulderRoomDirection + " facing boulder room in " + length + " steps. Path:"); + for (int[] block : route) { + System.out.println(Arrays.toString(block)); + } + } + } + } else { + chest = null; + boulderRoomDirection = null; + inBoulderRoom = false; + } + }).start(); + } + } + } + + @SubscribeEvent + public void onWorldRender(RenderWorldLastEvent event) { + if (ToggleCommand.boulderToggled && Utils.inDungeons && route.size() > 0 && currentStep < route.size() && chest != null) { + int[] currentBlockArray = route.get(currentStep); + AxisAlignedBB currentBoulder = BoulderUtils.getBoulder(currentBlockArray[0], currentBlockArray[1], chest, boulderRoomDirection); + if (currentBoulder == null) return; + Utils.drawFilled3DBox(currentBoulder, BOULDER_COLOUR, true, false, event.partialTicks); + char direction; + switch (currentBlockArray[2]) { + case 1: + direction = 'u'; + break; + case 2: + direction = 'd'; + break; + case 3: + direction = 'l'; + break; + case 4: + direction = 'r'; + break; + default: + return; + } + BoulderUtils.drawArrow(currentBoulder, boulderRoomDirection, direction, 0xFF000000 + BOULDER_ARROW_COLOUR, event.partialTicks); + } + } + + @SubscribeEvent + public void onInteract(PlayerInteractEvent event) { + if (Minecraft.getMinecraft().thePlayer != event.entityPlayer || !inBoulderRoom || !ToggleCommand.boulderToggled) return; + + if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + Block block = Minecraft.getMinecraft().theWorld.getBlockState(event.pos).getBlock(); + if (block == Blocks.stone_button) currentStep++; + } + } + + static void reset() { + route.clear(); + currentStep = 0; + BoulderUtils.seenBoardStates.clear(); + BoulderUtils.iterations = 0; + BoulderUtils.fastestSolution = 10; + } + +} diff --git a/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java index 8c7132c..7ff7e7a 100644 --- a/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java +++ b/src/main/java/me/Danker/features/puzzlesolvers/CreeperSolver.java @@ -78,7 +78,7 @@ public class CreeperSolver { public void onWorldRender(RenderWorldLastEvent event) { if (ToggleCommand.creeperToggled && drawCreeperLines && !creeperLines.isEmpty()) { for (int i = 0; i < creeperLines.size(); i++) { - Utils.draw3DLine(creeperLines.get(i)[0], creeperLines.get(i)[1], CREEPER_COLOURS[i % 10], event.partialTicks); + Utils.draw3DLine(creeperLines.get(i)[0], creeperLines.get(i)[1], CREEPER_COLOURS[i % 10], 2, true, event.partialTicks); } } } diff --git a/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java index 36721c1..8f7de95 100644 --- a/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java +++ b/src/main/java/me/Danker/features/puzzlesolvers/ThreeManSolver.java @@ -68,7 +68,7 @@ public class ThreeManSolver { @SubscribeEvent public void onWorldRender(RenderWorldLastEvent event) { if (ToggleCommand.threeManToggled && riddleChest != null) { - Utils.drawFilled3DBox(new AxisAlignedBB(riddleChest.getX() - 0.05, riddleChest.getY(), riddleChest.getZ() - 0.05, riddleChest.getX() + 1.05, riddleChest.getY() + 1, riddleChest.getZ() + 1.05), 0x197F19, true, event.partialTicks); + Utils.drawFilled3DBox(new AxisAlignedBB(riddleChest.getX() - 0.05, riddleChest.getY(), riddleChest.getZ() - 0.05, riddleChest.getX() + 1.05, riddleChest.getY() + 1, riddleChest.getZ() + 1.05), 0x197F19, true, true, event.partialTicks); } } diff --git a/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java b/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java index ac2cd0c..b769634 100644 --- a/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java +++ b/src/main/java/me/Danker/features/puzzlesolvers/TriviaSolver.java @@ -6,8 +6,6 @@ import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StringUtils; import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -20,8 +18,7 @@ public class TriviaSolver { static String[] triviaAnswers = null; public static String TRIVIA_WRONG_ANSWER_COLOUR; - @Mod.EventHandler - public void init(FMLInitializationEvent event) { + public static void init() { triviaSolutions.put("What is the status of The Watcher?", new String[]{"Stalker"}); triviaSolutions.put("What is the status of Bonzo?", new String[]{"New Necromancer"}); triviaSolutions.put("What is the status of Scarf?", new String[]{"Apprentice Necromancer"}); diff --git a/src/main/java/me/Danker/gui/DisplayGui.java b/src/main/java/me/Danker/gui/DisplayGui.java index 4e5831d..ceda556 100644 --- a/src/main/java/me/Danker/gui/DisplayGui.java +++ b/src/main/java/me/Danker/gui/DisplayGui.java @@ -1,7 +1,6 @@ package me.Danker.gui; import me.Danker.DankersSkyblockMod; -import me.Danker.commands.DisplayCommand; import me.Danker.features.loot.LootDisplay; import me.Danker.handlers.ConfigHandler; import me.Danker.handlers.TextRenderer; diff --git a/src/main/java/me/Danker/gui/PuzzleSolversGui.java b/src/main/java/me/Danker/gui/PuzzleSolversGui.java index 17eb433..f502df9 100644 --- a/src/main/java/me/Danker/gui/PuzzleSolversGui.java +++ b/src/main/java/me/Danker/gui/PuzzleSolversGui.java @@ -22,6 +22,7 @@ public class PuzzleSolversGui extends GuiScreen { private GuiButton creeper; private GuiButton water; private GuiButton ticTacToe; + private GuiButton boulder; private GuiButton startsWith; private GuiButton selectAll; private GuiButton clickOrder; @@ -56,12 +57,13 @@ public class PuzzleSolversGui extends GuiScreen { creeper = new GuiButton(0, width / 2 - 100, (int) (height * 0.4), "Creeper Solver: " + Utils.getColouredBoolean(ToggleCommand.creeperToggled)); water = new GuiButton(0, width / 2 - 100, (int) (height * 0.5), "Water Solver: " + Utils.getColouredBoolean(ToggleCommand.waterToggled)); ticTacToe = new GuiButton(0, width / 2 - 100, (int) (height * 0.6), "Tic Tac Toe Solver: " + Utils.getColouredBoolean(ToggleCommand.ticTacToeToggled)); - startsWith = new GuiButton(0, width / 2 - 100, (int) (height * 0.7), "Starts With Letter Terminal Solver: " + Utils.getColouredBoolean(ToggleCommand.startsWithToggled)); + boulder = new GuiButton(0, width / 2 - 100, (int) (height * 0.7), "Boulder Solver: " + Utils.getColouredBoolean(ToggleCommand.boulderToggled)); // Page 2 - selectAll = new GuiButton(0, width / 2 - 100, (int) (height * 0.1), "Select All Color Terminal Solver: " + Utils.getColouredBoolean(ToggleCommand.selectAllToggled)); - clickOrder = new GuiButton(0, width / 2 - 100, (int) (height * 0.2), "Click in Order Terminal Helper: " + Utils.getColouredBoolean(ToggleCommand.clickInOrderToggled)); - blockClicks = new GuiButton(0, width / 2 - 100, (int) (height * 0.3), "Block Wrong Clicks on Terminals: " + Utils.getColouredBoolean(ToggleCommand.blockWrongTerminalClicksToggled)); - itemFrameOnSeaLanterns = new GuiButton(0, width / 2 - 100, (int) (height * 0.4), "Ignore Arrows On Sea Lanterns: " + Utils.getColouredBoolean(ToggleCommand.itemFrameOnSeaLanternsToggled)); + startsWith = new GuiButton(0, width / 2 - 100, (int) (height * 0.1), "Starts With Letter Terminal Solver: " + Utils.getColouredBoolean(ToggleCommand.startsWithToggled)); + selectAll = new GuiButton(0, width / 2 - 100, (int) (height * 0.2), "Select All Color Terminal Solver: " + Utils.getColouredBoolean(ToggleCommand.selectAllToggled)); + clickOrder = new GuiButton(0, width / 2 - 100, (int) (height * 0.3), "Click in Order Terminal Helper: " + Utils.getColouredBoolean(ToggleCommand.clickInOrderToggled)); + blockClicks = new GuiButton(0, width / 2 - 100, (int) (height * 0.4), "Block Wrong Clicks on Terminals: " + Utils.getColouredBoolean(ToggleCommand.blockWrongTerminalClicksToggled)); + itemFrameOnSeaLanterns = new GuiButton(0, width / 2 - 100, (int) (height * 0.5), "Ignore Arrows On Sea Lanterns: " + Utils.getColouredBoolean(ToggleCommand.itemFrameOnSeaLanternsToggled)); switch (page) { case 1: @@ -71,10 +73,11 @@ public class PuzzleSolversGui extends GuiScreen { this.buttonList.add(creeper); this.buttonList.add(water); this.buttonList.add(ticTacToe); - this.buttonList.add(startsWith); + this.buttonList.add(boulder); this.buttonList.add(nextPage); break; case 2: + this.buttonList.add(startsWith); this.buttonList.add(selectAll); this.buttonList.add(clickOrder); this.buttonList.add(blockClicks); @@ -123,6 +126,10 @@ public class PuzzleSolversGui extends GuiScreen { ToggleCommand.ticTacToeToggled = !ToggleCommand.ticTacToeToggled; ConfigHandler.writeBooleanConfig("toggles", "TicTacToePuzzle", ToggleCommand.ticTacToeToggled); ticTacToe.displayString = "Tic Tac Toe Solver: " + Utils.getColouredBoolean(ToggleCommand.ticTacToeToggled); + } else if (button == boulder) { + ToggleCommand.boulderToggled = !ToggleCommand.boulderToggled; + ConfigHandler.writeBooleanConfig("toggles", "BoulderPuzzle", ToggleCommand.boulderToggled); + boulder.displayString = "Boulder Solver: " + Utils.getColouredBoolean(ToggleCommand.boulderToggled); } else if (button == startsWith) { ToggleCommand.startsWithToggled = !ToggleCommand.startsWithToggled; ConfigHandler.writeBooleanConfig("toggles", "StartsWithTerminal", ToggleCommand.startsWithToggled); diff --git a/src/main/java/me/Danker/handlers/ConfigHandler.java b/src/main/java/me/Danker/handlers/ConfigHandler.java index 53f499b..30778e7 100644 --- a/src/main/java/me/Danker/handlers/ConfigHandler.java +++ b/src/main/java/me/Danker/handlers/ConfigHandler.java @@ -1,7 +1,6 @@ package me.Danker.handlers; import me.Danker.DankersSkyblockMod; -import me.Danker.commands.DisplayCommand; import me.Danker.commands.MoveCommand; import me.Danker.commands.ScaleCommand; import me.Danker.commands.ToggleCommand; @@ -252,6 +251,7 @@ public class ConfigHandler { ToggleCommand.creeperToggled = initBoolean("toggles", "CreeperPuzzle", false); ToggleCommand.waterToggled = initBoolean("toggles", "WaterPuzzle", false); ToggleCommand.ticTacToeToggled = initBoolean("toggles", "TicTacToePuzzle", false); + ToggleCommand.boulderToggled = initBoolean("toggles", "BoulderPuzzle", false); ToggleCommand.startsWithToggled = initBoolean("toggles", "StartsWithTerminal", false); ToggleCommand.selectAllToggled = initBoolean("toggles", "SelectAllTerminal", false); ToggleCommand.clickInOrderToggled = initBoolean("toggles", "ClickInOrderTerminal", false); @@ -508,6 +508,8 @@ public class ConfigHandler { ChronomatronSolver.CHRONOMATRON_NEXT_TO_NEXT = initInt("colors", "chronomatronNextToNext", 0x40DAE6); ClickInOrderSolver.CLICK_IN_ORDER_NEXT = initInt("colors", "clickInOrderNext", 0xFF00DD); ClickInOrderSolver.CLICK_IN_ORDER_NEXT_TO_NEXT = initInt("colors", "clickInOrderNextToNext", 0x0BEFE7); + BoulderSolver.BOULDER_COLOUR = initInt("colors", "boulder", 0x197F19); + BoulderSolver.BOULDER_ARROW_COLOUR = initInt("colors", "boulderArrow", 0x006000); // Commands if (!hasKey("commands", "reparty")) writeBooleanConfig("commands", "reparty", false); diff --git a/src/main/java/me/Danker/utils/BoulderUtils.java b/src/main/java/me/Danker/utils/BoulderUtils.java new file mode 100644 index 0000000..2d437d0 --- /dev/null +++ b/src/main/java/me/Danker/utils/BoulderUtils.java @@ -0,0 +1,280 @@ +package me.Danker.utils; + +import me.Danker.features.puzzlesolvers.BoulderSolver; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.BlockPos; +import net.minecraft.util.Vec3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +public class BoulderUtils { + + public static HashSet seenBoardStates = new HashSet<>(); + public static long iterations = 0; + public static int fastestSolution = 10; + + /* + CC BY-SA 4.0 + Unmodified + Question: https://stackoverflow.com/questions/5617016/ + Answer: https://stackoverflow.com/a/53397359 + Author: https://stackoverflow.com/users/3647002/gayan-weerakutti + */ + public static char[][] copy(char[][] array) { + return Arrays.stream(array).map(char[]::clone).toArray(char[][]::new); + } + + public static char[][] flipVertically(char[][] board) { + char[][] newBoard = new char[7][7]; + + for (int row = 0; row < 7; row++) { + System.arraycopy(board[6 - row], 0, newBoard[row], 0, 7); + } + + return newBoard; + } + + public static char[][] flipHorizontally(char[][] board) { + char[][] newBoard = new char[7][7]; + + for (int row = 0; row < 7; row++) { + for (int column = 0; column < 7; column++) { + newBoard[row][column] = board[row][6 - column]; + } + } + + return newBoard; + } + + public static char[][] rotateClockwise(char[][] board) { + char[][] newBoard = new char[7][7]; + + for (int row = 0; row < 7; row++) { + for (int column = 0; column < 7; column++) { + newBoard[column][6 - row] = board[row][column]; + } + } + + return newBoard; + } + + public static char[][] removeFirstRow(char[][] board) { + List list = new ArrayList<>(Arrays.asList(board)); + list.remove(0); + return list.toArray(new char[][]{}); + } + + public static String toString(char[][] board) { + StringBuilder sb = new StringBuilder(); + for (char[] row : board) { + for (char column : row) { + sb.append(column); + } + } + return sb.toString(); + } + + public static int findSolution(char[][] board, int depth, List route) { + if (depth > 9) return 10; + String boardString = toString(board); + if (seenBoardStates.contains(boardString)) return 10; // this line turns 600 million iterations to 700 thousand + seenBoardStates.add(boardString); + if (hasOpenPath(board)) return depth; + + char[][] floodFilledBoard = floodFillBottom(board); + List newRoute = new ArrayList<>(route); + int solutionLength = 10; + int bestRow = -1; + int bestColumn = -1; + int bestDirection = -1; + for (int row = 0; row < 6; row++) { + for (int column = 0; column < 7; column++) { + iterations++; + if (floodFilledBoard[row][column] == 'X' && isTouchingOpenSpace(floodFilledBoard, row, column)) { + if (canBePushed(floodFilledBoard, row, column, 'u')) { + int solution = findSolution(push(board, row, column, 'u'), depth + 1, add(newRoute, new int[]{row, column, 1})); + if (solution < solutionLength) { + solutionLength = solution; + bestRow = row; + bestColumn = column; + bestDirection = 1; + } + } + if (canBePushed(floodFilledBoard, row, column, 'd')) { + int solution = findSolution(push(board, row, column, 'd'), depth + 1, add(newRoute, new int[]{row, column, 2})); + if (solution < solutionLength) { + solutionLength = solution; + bestRow = row; + bestColumn = column; + bestDirection = 2; + } + } + if (canBePushed(floodFilledBoard, row, column, 'l')) { + int solution = findSolution(push(board, row, column, 'l'), depth + 1, add(newRoute, new int[]{row, column, 3})); + if (solution < solutionLength) { + solutionLength = solution; + bestRow = row; + bestColumn = column; + bestDirection = 3; + } + } + if (canBePushed(floodFilledBoard, row, column, 'r')) { + int solution = findSolution(push(board, row, column, 'r'), depth + 1, add(newRoute, new int[]{row, column, 4})); + if (solution < solutionLength) { + solutionLength = solution; + bestRow = row; + bestColumn = column; + bestDirection = 4; + } + } + } + } + } + + if (bestRow != -1) { + newRoute.add(0, new int[]{bestRow, bestColumn, bestDirection}); + } + if (solutionLength < fastestSolution) { + fastestSolution = solutionLength; + newRoute.add(newRoute.remove(0)); // dont know why the last one goes first but this fixes it + BoulderSolver.route = new ArrayList<>(newRoute); + } + return solutionLength; + } + + public static boolean canBePushed(char[][] floodFilledBoard, int row, int column, char direction) { + switch (direction) { + case 'u': + if (row > 0 && row < 5 && floodFilledBoard[row - 1][column] != 'X' && floodFilledBoard[row + 1][column] == 'O') return true; + break; + case 'd': + if (row > 0 && row < 5 && floodFilledBoard[row - 1][column] == 'O' && floodFilledBoard[row + 1][column] != 'X') return true; + break; + case 'l': + if (column > 0 && column < 6 && floodFilledBoard[row][column - 1] != 'X' && floodFilledBoard[row][column + 1] == 'O') return true; + break; + case 'r': + if (column > 0 && column < 6 && floodFilledBoard[row][column - 1] == 'O' && floodFilledBoard[row][column + 1] != 'X') return true; + break; + } + return false; + } + + public static char[][] push(char[][] board, int row, int column, char direction) { + char[][] newBoard = copy(board); + switch (direction) { + case 'u': + newBoard[row - 1][column] = 'X'; + break; + case 'd': + newBoard[row + 1][column] = 'X'; + break; + case 'l': + newBoard[row][column - 1] = 'X'; + break; + case 'r': + newBoard[row][column + 1] = 'X'; + } + newBoard[row][column] = '\0'; + return newBoard; + } + + public static boolean isTouchingOpenSpace(char[][] floodFilledBoard, int row, int column) { + return (row > 0 && floodFilledBoard[row - 1][column] == 'O') || + (row < 5 && floodFilledBoard[row + 1][column] == 'O') || + (column > 0 && floodFilledBoard[row][column - 1] == 'O') || + (column < 6 && floodFilledBoard[row][column + 1] == 'O'); + } + + public static boolean hasOpenPath(char[][] board) { + char[][] newBoard = floodFillBottom(copy(board)); + // Check if flood fill reached top + for (int column = 0; column < 7; column++) { + if (newBoard[0][column] == 'O') return true; + } + return false; + } + + public static char[][] floodFillBottom(char[][] board) { + char[][] newBoard = copy(board); + for (int column = 0; column < 7; column++) { + if (newBoard[5][column] == '\0') { + newBoard = floodFill(newBoard, 5, column); + } + } + return newBoard; + } + + public static char[][] floodFill(char[][] board, int row, int column) { + if (row < 0 || row > 5 || column < 0 || column > 6) return board; + if (board[row][column] == '\0') { + board[row][column] = 'O'; + floodFill(board, row - 1, column); + floodFill(board, row + 1, column); + floodFill(board, row, column - 1); + floodFill(board, row, column + 1); + return board; + } + return board; + } + + public static List add(List list, int[] arrayToAdd) { + List newList = new ArrayList<>(list); + newList.add(arrayToAdd); + return newList; + } + + public static AxisAlignedBB getBoulder(int row, int column, BlockPos chestLocation, String boulderRoomDirection) { + BlockPos boulderPosition; + switch (boulderRoomDirection) { + case "north": + boulderPosition = chestLocation.add(3 * column - 10, -2, 3 * row + 4); + break; + case "east": + boulderPosition = chestLocation.add(-3 * row - 6, -2, 3 * column - 10); + break; + case "south": + boulderPosition = chestLocation.add(-3 * column + 8, -2, -3 * row - 6); + break; + case "west": + boulderPosition = chestLocation.add(3 * row + 4, -2, -3 * column + 8); + break; + default: + return null; + } + return new AxisAlignedBB(boulderPosition.getX() - 0.01, boulderPosition.getY() - 0.01, boulderPosition.getZ() - 0.01, boulderPosition.getX() + 3.01, boulderPosition.getY() + 3.01, boulderPosition.getZ() + 3.01); + } + + public static void drawArrow(AxisAlignedBB aabb, String boulderRoomDirection, char direction, int colourInt, float partialTicks) { + double averageX = (aabb.minX + aabb.maxX) / 2; + double thirtyPercent = (aabb.maxX - aabb.minX) * 0.3; + double averageZ = (aabb.minZ + aabb.maxZ) / 2; + if (((boulderRoomDirection.equals("north") || boulderRoomDirection.equals("south")) && (direction == 'u' || direction == 'd')) || + ((boulderRoomDirection.equals("east") || boulderRoomDirection.equals("west")) && (direction == 'l' || direction == 'r'))) { + Utils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.minZ), new Vec3(averageX, aabb.minY, aabb.maxZ), colourInt, 10, false, partialTicks); + } else { + Utils.draw3DLine(new Vec3(aabb.minX, aabb.minY, averageZ), new Vec3(aabb.maxX, aabb.minY, averageZ), colourInt, 10, false, partialTicks); + } + + if ((boulderRoomDirection.equals("north") && direction == 'u') || (boulderRoomDirection.equals("south") && direction == 'd') || + (boulderRoomDirection.equals("east") && direction == 'l') || (boulderRoomDirection.equals("west") && direction == 'r')) { + Utils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.minZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks); + Utils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.minZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks); + } else if ((boulderRoomDirection.equals("north") && direction == 'd') || (boulderRoomDirection.equals("south") && direction == 'u') || + (boulderRoomDirection.equals("east") && direction == 'r') || (boulderRoomDirection.equals("west") && direction == 'l')) { + Utils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.maxZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks); + Utils.draw3DLine(new Vec3(averageX, aabb.minY, aabb.maxZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks); + } else if ((boulderRoomDirection.equals("north") && direction == 'l') || (boulderRoomDirection.equals("south") && direction == 'r') || + (boulderRoomDirection.equals("east") && direction == 'd') || (boulderRoomDirection.equals("west") && direction == 'u')) { + Utils.draw3DLine(new Vec3(aabb.minX, aabb.minY, averageZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks); + Utils.draw3DLine(new Vec3(aabb.minX, aabb.minY, averageZ), new Vec3(aabb.minX + thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks); + } else { + Utils.draw3DLine(new Vec3(aabb.maxX, aabb.minY, averageZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.minZ + thirtyPercent), colourInt, 10, false, partialTicks); + Utils.draw3DLine(new Vec3(aabb.maxX, aabb.minY, averageZ), new Vec3(aabb.maxX - thirtyPercent, aabb.minY, aabb.maxZ - thirtyPercent), colourInt, 10, false, partialTicks); + } + } + +} diff --git a/src/main/java/me/Danker/utils/Utils.java b/src/main/java/me/Danker/utils/Utils.java index 911704f..1a24c69 100644 --- a/src/main/java/me/Danker/utils/Utils.java +++ b/src/main/java/me/Danker/utils/Utils.java @@ -305,7 +305,7 @@ public class Utils { }); } - public static void draw3DLine(Vec3 pos1, Vec3 pos2, int colourInt, float partialTicks) { + public static void draw3DLine(Vec3 pos1, Vec3 pos2, int colourInt, int lineWidth, boolean depth, float partialTicks) { Entity render = Minecraft.getMinecraft().getRenderViewEntity(); WorldRenderer worldRenderer = Tessellator.getInstance().getWorldRenderer(); Color colour = new Color(colourInt); @@ -320,7 +320,11 @@ public class Utils { GlStateManager.enableBlend(); GlStateManager.disableAlpha(); GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); - GL11.glLineWidth(2); + GL11.glLineWidth(lineWidth); + if (!depth) { + GL11.glDisable(GL11.GL_DEPTH_TEST); + GlStateManager.depthMask(false); + } GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, colour.getAlpha() / 255f); worldRenderer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION); @@ -329,6 +333,10 @@ public class Utils { Tessellator.getInstance().draw(); GlStateManager.translate(realX, realY, realZ); + if (!depth) { + GL11.glEnable(GL11.GL_DEPTH_TEST); + GlStateManager.depthMask(true); + } GlStateManager.disableBlend(); GlStateManager.enableAlpha(); GlStateManager.enableTexture2D(); @@ -386,7 +394,7 @@ public class Utils { GlStateManager.popMatrix(); } - public static void drawFilled3DBox(AxisAlignedBB aabb, int colourInt, boolean translucent, float partialTicks) { + public static void drawFilled3DBox(AxisAlignedBB aabb, int colourInt, boolean translucent, boolean depth, float partialTicks) { Entity render = Minecraft.getMinecraft().getRenderViewEntity(); WorldRenderer worldRenderer = Tessellator.getInstance().getWorldRenderer(); Color colour = new Color(colourInt); @@ -401,8 +409,12 @@ public class Utils { GlStateManager.disableTexture2D(); GlStateManager.enableAlpha(); GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate(770, translucent ? 1 : 771, 1, 0); GlStateManager.disableCull(); + GlStateManager.tryBlendFuncSeparate(770, translucent ? 1 : 771, 1, 0); + if (!depth) { + GL11.glDisable(GL11.GL_DEPTH_TEST); + GlStateManager.depthMask(false); + } GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, colour.getAlpha() / 255f); worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); // Bottom @@ -438,6 +450,10 @@ public class Utils { Tessellator.getInstance().draw(); GlStateManager.translate(realX, realY, realZ); + if (!depth) { + GL11.glEnable(GL11.GL_DEPTH_TEST); + GlStateManager.depthMask(true); + } GlStateManager.enableCull(); GlStateManager.disableAlpha(); GlStateManager.disableBlend(); -- cgit