From 5e7a8a02fe836c1e635faf067fbe8913549bc0e0 Mon Sep 17 00:00:00 2001 From: Walker Selby Date: Sun, 27 Mar 2022 12:13:08 -0500 Subject: Add NBT Data to Profile Viewer Tabs and XP Bars (#94) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed what hypxiel broke in dungeons * Added Longswords to Tools Tab (Itemlist) * Set max cata level to 70 * ups * why is it now E * YEP the cap is 99 not 70 * long cata xp BatChest + remove crash check because hypixel profile is null and i havent fixed that yet * Added checks for chat messages for dungeon win overlay - i think ive got them all but 4Shrug * Added an option to alert you if you put something for too much onto ah (default 50%) + Lowest bin alert triggers if lowest bin isnt found * IMPORTANT * fix dungeon page in /pv * show minions from coop in /pv * (BREAKING CHANGE) remove whitespace in changelog * fix crash with minion check * initial draft * tooltip * important changes * progress related things progress bar for community goals total collected points and personal goals display * only show bingo tab on Bingo profiles * make goals display gold when completed * Added MM7 button to dungeon preset * wart go not stonks * fix percents and added stack size * use code nopo in fortnite shop — Today at 17:29 The capitalisation * config option for always showing bingo page * 🙂 * movble pv tabs * 2.1.md 🙂 * oops * der Kabel * import * Added powder amount to level up perk * Made it only show if the perk isnt maxed / level 0 * fix /pv crash when pet is not in repo * 2.1.md 🙂 * web editor my beloved * Add NBT Data to Profile Viewer Tabs and XP Bars Add NBT Data Support for Resources in Tabs Add NBT Data Support for Resources in XP Bars Optimize renderTabs function Optimize mouseClicked Function Optimize ProfileViewerPage Enum * Update Style Co-authored-by: NopoTheGamer <40329022+NopoTheGamer@users.noreply.github.com> * Update GuiProfileViewer Rebased on pvbingo Updated formatting with IntelliJ reformatting tool (hopefully that matches now, let me know if you want me to try again but I think I did it right) * dungeons and pv bingo tab (#93) * add custom skull loading back (#96) * Refactor Hollows solvers, add tests, add Vec3Comparable, fix bugs (#95) * Rebase on master * Fix conflicts and rebase on master Add changes to change log * Oops Co-authored-by: nopo Co-authored-by: jani270 Co-authored-by: Lulonaut Co-authored-by: NopoTheGamer <40329022+NopoTheGamer@users.noreply.github.com> Co-authored-by: Lulonaut <67191924+Lulonaut@users.noreply.github.com> Co-authored-by: CraftyOldMiner <85420839+CraftyOldMiner@users.noreply.github.com> --- .../notenoughupdates/NotEnoughUpdates.java | 148 ++-- .../notenoughupdates/commands/dev/DiagCommand.java | 27 +- .../annotations/ConfigEditorDraggableList.java | 2 +- .../config/gui/GuiOptionEditorDraggableList.java | 16 +- .../core/config/struct/ConfigProcessor.java | 2 +- .../notenoughupdates/core/util/Vec3Comparable.java | 129 --- .../miscfeatures/AuctionBINWarning.java | 30 +- .../miscfeatures/CrystalMetalDetectorSolver.java | 450 ++++------ .../miscfeatures/CrystalWishingCompassSolver.java | 942 ++++----------------- .../options/seperateSections/Mining.java | 54 +- .../options/seperateSections/Misc.java | 1 + .../options/seperateSections/ProfileViewer.java | 2 +- .../notenoughupdates/profileviewer/BingoPage.java | 16 +- .../profileviewer/GuiProfileViewer.java | 82 +- .../notenoughupdates/util/NEUDebugLogger.java | 10 +- .../moulberry/notenoughupdates/util/SBInfo.java | 14 +- 16 files changed, 522 insertions(+), 1403 deletions(-) delete mode 100644 src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java (limited to 'src/main/java') diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index 951e7335..0ed68e06 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -1,5 +1,17 @@ package io.github.moulberry.notenoughupdates; +import java.awt.Color; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Set; + import com.google.common.collect.Sets; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -12,9 +24,22 @@ import io.github.moulberry.notenoughupdates.listener.ChatListener; import io.github.moulberry.notenoughupdates.listener.ItemTooltipListener; import io.github.moulberry.notenoughupdates.listener.NEUEventListener; import io.github.moulberry.notenoughupdates.listener.RenderListener; -import io.github.moulberry.notenoughupdates.miscfeatures.*; +import io.github.moulberry.notenoughupdates.miscfeatures.CrystalOverlay; +import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver; +import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects; +import io.github.moulberry.notenoughupdates.miscfeatures.DwarvenMinesWaypoints; +import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers; +import io.github.moulberry.notenoughupdates.miscfeatures.FairySouls; +import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper; +import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns; +import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager; +import io.github.moulberry.notenoughupdates.miscfeatures.MiningStuff; +import io.github.moulberry.notenoughupdates.miscfeatures.NullzeeSphere; +import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay; +import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking; +import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager; +import io.github.moulberry.notenoughupdates.miscfeatures.SunTzu; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes; -import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBlockSounds; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures; import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay; import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector; @@ -28,14 +53,17 @@ import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.util.XPInformation; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraft.client.settings.KeyBinding; import net.minecraft.event.ClickEvent; import net.minecraft.scoreboard.ScoreObjective; import net.minecraft.scoreboard.Scoreboard; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; -import net.minecraft.world.biome.*; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.biome.BiomeGenHell; +import net.minecraft.world.biome.BiomeGenJungle; +import net.minecraft.world.biome.BiomeGenMesa; +import net.minecraft.world.biome.BiomeGenSnow; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.Mod; @@ -44,12 +72,6 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; -import java.awt.*; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Set; - @Mod(modid = NotEnoughUpdates.MODID, version = NotEnoughUpdates.VERSION, clientSideOnly = true) public class NotEnoughUpdates { public static final String MODID = "notenoughupdates"; @@ -57,6 +79,60 @@ public class NotEnoughUpdates { public static final String PRE_VERSION = "0.0"; public static final int VERSION_ID = 20100; public static final int PRE_VERSION_ID = 0; + + public static NotEnoughUpdates INSTANCE = null; + + public NEUManager manager; + public NEUOverlay overlay; + public NEUConfig config; + + private File configFile; + + public File getConfigFile() { + return this.configFile; + } + + public void newConfigFile() { + this.configFile = new File(NotEnoughUpdates.INSTANCE.getNeuDir(), "configNew.json"); + } + + private static final long CHAT_MSG_COOLDOWN = 200; + private long lastChatMessage = 0; + private long secondLastChatMessage = 0; + private String currChatMessage = null; + + //Stolen from Biscut and used for detecting whether in skyblock + private static final Set SKYBLOCK_IN_ALL_LANGUAGES = + Sets.newHashSet("SKYBLOCK", "\u7A7A\u5C9B\u751F\u5B58", "\u7A7A\u5CF6\u751F\u5B58"); + + public GuiScreen openGui = null; + public long lastOpenedGui = 0; + + public Commands commands; + + public static HashMap petRarityToColourMap = new HashMap() {{ + put("UNKNOWN", EnumChatFormatting.RED.toString()); + put("COMMON", EnumChatFormatting.WHITE.toString()); + put("UNCOMMON", EnumChatFormatting.GREEN.toString()); + put("RARE", EnumChatFormatting.BLUE.toString()); + put("EPIC", EnumChatFormatting.DARK_PURPLE.toString()); + put("LEGENDARY", EnumChatFormatting.GOLD.toString()); + put("MYTHIC", EnumChatFormatting.LIGHT_PURPLE.toString()); + }}; + + public static ProfileViewer profileViewer; + + public boolean packDevEnabled = false; + + private final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); + private File neuDir; + + public File getNeuDir() { + return this.neuDir; + } + + public Color[][] colourMap = null; + /** * Registers the biomes for the crystal hollows here so optifine knows they exists */ @@ -90,48 +166,6 @@ public class NotEnoughUpdates { .setBiomeName("NeuCrystalHollowsCrystalNucleus") .setFillerBlockMetadata(5470985) .setTemperatureRainfall(0.95F, 0.9F); - private static final long CHAT_MSG_COOLDOWN = 200; - //Stolen from Biscut and used for detecting whether in skyblock - private static final Set SKYBLOCK_IN_ALL_LANGUAGES = - Sets.newHashSet("SKYBLOCK", "\u7A7A\u5C9B\u751F\u5B58", "\u7A7A\u5CF6\u751F\u5B58"); - public static NotEnoughUpdates INSTANCE = null; - public static HashMap petRarityToColourMap = new HashMap() {{ - put("UNKNOWN", EnumChatFormatting.RED.toString()); - put("COMMON", EnumChatFormatting.WHITE.toString()); - put("UNCOMMON", EnumChatFormatting.GREEN.toString()); - put("RARE", EnumChatFormatting.BLUE.toString()); - put("EPIC", EnumChatFormatting.DARK_PURPLE.toString()); - put("LEGENDARY", EnumChatFormatting.GOLD.toString()); - put("MYTHIC", EnumChatFormatting.LIGHT_PURPLE.toString()); - }}; - public static ProfileViewer profileViewer; - private final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); - public NEUManager manager; - public NEUOverlay overlay; - public NEUConfig config; - public GuiScreen openGui = null; - public long lastOpenedGui = 0; - public Commands commands; - public boolean packDevEnabled = false; - public Color[][] colourMap = null; - private File configFile; - private long lastChatMessage = 0; - private long secondLastChatMessage = 0; - private String currChatMessage = null; - private File neuDir; - private boolean hasSkyblockScoreboard; - - public File getConfigFile() { - return this.configFile; - } - - public void newConfigFile() { - this.configFile = new File(NotEnoughUpdates.INSTANCE.getNeuDir(), "configNew.json"); - } - - public File getNeuDir() { - return this.neuDir; - } /** * Instantiates NEUIo, NEUManager and NEUOverlay instances. Registers keybinds and adds a shutdown hook to clear tmp folder. @@ -215,14 +249,6 @@ public class NotEnoughUpdates { MinecraftForge.EVENT_BUS.register(new CrystalOverlay()); MinecraftForge.EVENT_BUS.register(new ItemCooldowns()); - if (Minecraft.getMinecraft().getResourceManager() instanceof IReloadableResourceManager) { - IReloadableResourceManager manager = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager(); - manager.registerReloadListener(CustomSkulls.getInstance()); - manager.registerReloadListener(NPCRetexturing.getInstance()); - manager.registerReloadListener(new ItemCustomizeManager.ReloadListener()); - manager.registerReloadListener(new CustomBlockSounds.ReloaderListener()); - } - this.commands = new Commands(); BackgroundBlur.registerListener(); @@ -384,6 +410,8 @@ public class NotEnoughUpdates { return hasSkyblockScoreboard(); } + private boolean hasSkyblockScoreboard; + public boolean hasSkyblockScoreboard() { return hasSkyblockScoreboard; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java index dab99698..88264538 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java @@ -17,10 +17,8 @@ public class DiagCommand extends ClientCommandBase { private static final String USAGE_TEXT = EnumChatFormatting.WHITE + "Usage: /neudiag \n\n" + - "/neudiag metal Metal Detector Solver diagnostics\n" + - " Show current solution diags\n" + - " center= Disable / enable using center\n" + - "/neudiag wishing Wishing Compass Solver diagnostics\n" + + "/neudiag metal Metal Detector Solver diagnostics\n" + + "/neudiag wishing Wishing Compass Solver diagnostics\n" + "/neudiag debug\n" + " Show current flags\n" + " Enable/disable flag\n"; @@ -39,26 +37,7 @@ public class DiagCommand extends ClientCommandBase { String command = args[0].toLowerCase(); switch (command) { case "metal": - if (args.length == 1) { - CrystalMetalDetectorSolver.logDiagnosticData(true); - return; - } - - String subCommand = args[1].toLowerCase(); - if (subCommand.equals("center=off")) { - CrystalMetalDetectorSolver.setDebugDoNotUseCenter(true); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "Center coordinates-based solutions disabled")); - } - else if (subCommand.equals("center=on")) { - CrystalMetalDetectorSolver.setDebugDoNotUseCenter(false); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "Center coordinates-based solutions enabled")); - } else { - showUsage(sender); - return; - } - + CrystalMetalDetectorSolver.logDiagnosticData(true); break; case "wishing": CrystalWishingCompassSolver.getInstance().logDiagnosticData(true); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java index 5063d543..61e923f5 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java @@ -9,5 +9,5 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) public @interface ConfigEditorDraggableList { String[] exampleText(); - boolean allowRemovingElements() default true; + boolean allowDeleting() default true; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java index df373dbf..4dbde24b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java @@ -24,7 +24,7 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor { private static final ResourceLocation DELETE = new ResourceLocation("notenoughupdates:core/delete.png"); private final String[] exampleText; - private final boolean allowRemovingElements; + private final boolean enableDeleting; private final List activeText; private int currentDragging = -1; private int dragStartIndex = -1; @@ -39,11 +39,11 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor { public GuiOptionEditorDraggableList( ConfigProcessor.ProcessedOption option, String[] exampleText, - boolean allowRemovingElements + boolean disableDeleting ) { super(option); - this.allowRemovingElements = allowRemovingElements; + this.enableDeleting = disableDeleting; this.exampleText = exampleText; this.activeText = (List) option.get(); } @@ -84,7 +84,7 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor { GlStateManager.color(1, greenBlue, greenBlue, 1); } - if (allowRemovingElements) { + if (enableDeleting) { Minecraft.getMinecraft().getTextureManager().bindTexture(DELETE); Utils.drawTexturedRect(x + width / 6 + 27, y + 45 - 7 - 13, 11, 14, GL11.GL_NEAREST); } @@ -215,7 +215,7 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor { dragStartIndex >= 0 && Mouse.getEventButton() == 0 && mouseX >= x + width / 6 + 27 - 3 && mouseX <= x + width / 6 + 27 + 11 + 3 && mouseY >= y + 45 - 7 - 13 - 3 && mouseY <= y + 45 - 7 - 13 + 14 + 3) { - if (allowRemovingElements) { + if (enableDeleting) { activeText.remove(dragStartIndex); } currentDragging = -1; @@ -226,13 +226,13 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor { if (!Mouse.isButtonDown(0) || dropdownOpen) { currentDragging = -1; dragStartIndex = -1; - if (trashHoverTime > 0 && allowRemovingElements) trashHoverTime = -System.currentTimeMillis(); + if (trashHoverTime > 0 && enableDeleting) trashHoverTime = -System.currentTimeMillis(); } else if (currentDragging >= 0 && mouseX >= x + width / 6 + 27 - 3 && mouseX <= x + width / 6 + 27 + 11 + 3 && mouseY >= y + 45 - 7 - 13 - 3 && mouseY <= y + 45 - 7 - 13 + 14 + 3) { - if (trashHoverTime < 0 && allowRemovingElements) trashHoverTime = System.currentTimeMillis(); + if (trashHoverTime < 0 && enableDeleting) trashHoverTime = System.currentTimeMillis(); } else { - if (trashHoverTime > 0 && allowRemovingElements) trashHoverTime = -System.currentTimeMillis(); + if (trashHoverTime > 0 && enableDeleting) trashHoverTime = -System.currentTimeMillis(); } if (Mouse.getEventButtonState()) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java index 3eb8a2d1..0d06980a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java @@ -147,7 +147,7 @@ public class ConfigProcessor { if (optionField.isAnnotationPresent(ConfigEditorDraggableList.class)) { ConfigEditorDraggableList configEditorAnnotation = optionField.getAnnotation(ConfigEditorDraggableList.class); - editor = new GuiOptionEditorDraggableList(option, configEditorAnnotation.exampleText(), configEditorAnnotation.allowRemovingElements()); + editor = new GuiOptionEditorDraggableList(option, configEditorAnnotation.exampleText(), configEditorAnnotation.allowDeleting()); } } if (optionType.isAssignableFrom(String.class)) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java deleted file mode 100644 index cd144c21..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java +++ /dev/null @@ -1,129 +0,0 @@ -package io.github.moulberry.notenoughupdates.core.util; - -import net.minecraft.util.BlockPos; -import net.minecraft.util.Vec3; -import net.minecraft.util.Vec3i; - -public class Vec3Comparable extends Vec3 implements Comparable { - public static final Vec3Comparable NULL_VECTOR = new Vec3Comparable(0.0, 0.0, 0.0); - - public Vec3Comparable(double x, double y, double z) { - super(x, y, z); - } - - public Vec3Comparable(Vec3i sourceVec) { - super(sourceVec); - } - - public Vec3Comparable(Vec3 source) { - super(source.xCoord, source.yCoord, source.zCoord); - } - - public Vec3Comparable(BlockPos source) { - - super(source.getX(), source.getY(), source.getZ()); - } - - public Vec3Comparable(Vec3Comparable source) { - super(source.xCoord, source.yCoord, source.zCoord); - } - - @Override - public Vec3Comparable subtractReverse(Vec3 vec) { - return new Vec3Comparable(super.subtractReverse(vec)); - } - - @Override - public Vec3Comparable normalize() { - return new Vec3Comparable(super.normalize()); - } - - @Override - public Vec3Comparable crossProduct(Vec3 vec) { - return new Vec3Comparable(super.crossProduct(vec)); - } - - @Override - public Vec3Comparable subtract(Vec3 vec) { - return new Vec3Comparable(super.subtract(vec)); - } - - @Override - public Vec3Comparable subtract(double x, double y, double z) { - return new Vec3Comparable(super.subtract(x, y, z)); - } - - @Override - public Vec3Comparable add(Vec3 other) { - return new Vec3Comparable(super.add(other)); - } - - @Override - public Vec3Comparable addVector(double x, double y, double z) { - return new Vec3Comparable(super.addVector(x, y, z)); - } - - @Override - public Vec3Comparable getIntermediateWithXValue(Vec3 vec, double x) { - return new Vec3Comparable(super.getIntermediateWithXValue(vec, x)); - } - - @Override - public Vec3Comparable getIntermediateWithYValue(Vec3 vec, double y) { - return new Vec3Comparable(super.getIntermediateWithYValue(vec, y)); - } - - @Override - public Vec3Comparable getIntermediateWithZValue(Vec3 vec, double z) { - return new Vec3Comparable(super.getIntermediateWithZValue(vec, z)); - } - - @Override - public Vec3Comparable rotatePitch(float pitch) { - return new Vec3Comparable(super.rotatePitch(pitch)); - } - - @Override - public Vec3Comparable rotateYaw(float yaw) { - return new Vec3Comparable(super.rotateYaw(yaw)); - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } else if (!(other instanceof Vec3Comparable)) { - return false; - } else { - Vec3Comparable vec3c = (Vec3Comparable) other; - return this.xCoord == vec3c.xCoord && this.yCoord == vec3c.yCoord && this.zCoord == vec3c.zCoord; - } - } - - @Override - public int hashCode() { - long bits = 1L; - bits = 31L * bits + doubleToLongBits(xCoord); - bits = 31L * bits + doubleToLongBits(yCoord); - bits = 31L * bits + doubleToLongBits(zCoord); - return (int) (bits ^ (bits >> 32)); - } - - public int compareTo(Vec3Comparable other) { - return this.yCoord == other.yCoord ? - (this.zCoord == other.zCoord ? - (int)(this.xCoord - other.xCoord) - : (int)(this.zCoord - other.zCoord)) - : (int)(this.yCoord - other.yCoord); - } - - public boolean signumEquals(Vec3 other) { - return Math.signum(xCoord) == Math.signum(other.xCoord) && - Math.signum(yCoord) == Math.signum(other.yCoord) && - Math.signum(zCoord) == Math.signum(other.zCoord); - } - - private static long doubleToLongBits(double d) { - return d == 0.0 ? 0L : Double.doubleToLongBits(d); - } -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java index c7bcc0e1..a787ca99 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java @@ -37,7 +37,9 @@ public class AuctionBINWarning extends GuiElement { private String sellingName; private int sellingPrice; private int lowestPrice; + private int buyPercentage; private int sellStackAmount; + private boolean isALoss = true; private boolean shouldPerformCheck() { if (!NotEnoughUpdates.INSTANCE.config.ahTweaks.enableBINWarning || @@ -110,14 +112,13 @@ public class AuctionBINWarning extends GuiElement { float undercutFactor = 1 - NotEnoughUpdates.INSTANCE.config.ahTweaks.warningThreshold / 100; if (undercutFactor < 0) undercutFactor = 0; if (undercutFactor > 1) undercutFactor = 1; - float overcutFactor = 1 + NotEnoughUpdates.INSTANCE.config.ahTweaks.overcutWarningThreshold / 100; + float overcutFactor = 1 - NotEnoughUpdates.INSTANCE.config.ahTweaks.overcutWarningThreshold / 100; if (overcutFactor < 0) overcutFactor = 0; + if (overcutFactor > 1) overcutFactor = 1; - if ( - (sellingPrice > 0 && lowestPrice > 0 && - ((sellingPrice > sellStackAmount * lowestPrice * overcutFactor) || - sellingPrice < sellStackAmount * lowestPrice * undercutFactor)) - || lowestPrice == -1) { + if ((sellingPrice > 0 && lowestPrice > 0 && sellingPrice < sellStackAmount * lowestPrice * undercutFactor) + || (sellingPrice > 0 && lowestPrice > 0 && sellingPrice > sellStackAmount * lowestPrice * (overcutFactor + 1)) + || lowestPrice == -1) { showWarning = true; return true; } else { @@ -180,9 +181,7 @@ public class AuctionBINWarning extends GuiElement { width / 2, height / 2 - 45 + 25, false, 170, 0xffffffff ); TextRenderUtils.drawStringCenteredScaledMaxWidth( - (lowestPrice > 0 - ? "has a lowest BIN of \u00a76" + lowestPriceStr + "\u00a7r coins" - : "\u00a7cWarning: No lowest BIN found!"), + (lowestPrice > 0 ? "has a lowest BIN of \u00a76" + lowestPriceStr + "\u00a7r coins" : "\u00a7cWarning: No lowest BIN found!"), Minecraft.getMinecraft().fontRendererObj, width / 2, height / 2 - 45 + 34, @@ -191,16 +190,16 @@ public class AuctionBINWarning extends GuiElement { 0xffa0a0a0 ); - boolean isALoss = false; - int buyPercentage = 0; if (sellingPrice > lowestPrice * sellStackAmount) { - buyPercentage = sellingPrice * 100 / (lowestPrice * sellStackAmount) - 100; + buyPercentage = sellingPrice * 100 / (lowestPrice * sellStackAmount); isALoss = false; } else if (sellingPrice < lowestPrice * sellStackAmount) { - buyPercentage = 100 - sellingPrice * 100 / (lowestPrice * sellStackAmount); + buyPercentage = 100 - sellingPrice * 100 / (lowestPrice * sellStackAmount); + if (buyPercentage <= 0) buyPercentage = 1; isALoss = true; } + TextRenderUtils.drawStringCenteredScaledMaxWidth( "Continue selling it for", Minecraft.getMinecraft().fontRendererObj, @@ -211,10 +210,7 @@ public class AuctionBINWarning extends GuiElement { 0xffa0a0a0 ); TextRenderUtils.drawStringCenteredScaledMaxWidth( - "\u00a76" + sellingPriceStr + "\u00a7r coins?" + - ((lowestPrice > 0 && buyPercentage > 0) - ? "(\u00a7" + (isALoss ? "c-" : "a+") + buyPercentage + "%\u00a7r)" - : ""), + "\u00a76" + sellingPriceStr + "\u00a7r coins?" + (lowestPrice > 0 ? "(\u00a7" + (isALoss ? "c-" : "a+") + buyPercentage + "%\u00a7r)" : ""), Minecraft.getMinecraft().fontRendererObj, width / 2, height / 2 - 45 + 59, diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java index f43ebda2..27c334ad 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java @@ -1,7 +1,6 @@ package io.github.moulberry.notenoughupdates.miscfeatures; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; -import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable; import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils; import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag; import io.github.moulberry.notenoughupdates.util.NEUDebugLogger; @@ -12,6 +11,7 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; +import net.minecraft.util.Vec3; import net.minecraft.util.Vec3i; import java.util.Arrays; @@ -22,35 +22,25 @@ import java.util.List; import java.util.stream.Collectors; public class CrystalMetalDetectorSolver { - enum SolutionState { - NOT_STARTED, - MULTIPLE, - MULTIPLE_KNOWN, - FOUND, - FOUND_KNOWN, - FAILED, - INVALID, - } - private static final Minecraft mc = Minecraft.getMinecraft(); - private static Vec3Comparable prevPlayerPos; - private static double prevDistToTreasure; + private static BlockPos prevPlayerPos; + private static double prevDistToTreasure = 0; private static HashSet possibleBlocks = new HashSet<>(); - private static final HashMap evaluatedPlayerPositions = new HashMap<>(); - private static boolean chestRecentlyFound; - private static long chestLastFoundMillis; + private static final HashMap evaluatedPlayerPositions = new HashMap<>(); + private static BlockPos blockPosIfLastSolutionInvalid; + private static Boolean chestRecentlyFound = false; + private static long chestLastFoundMillis = 0; private static final HashSet openedChestPositions = new HashSet<>(); // Keeper and Mines of Divan center location info private static Vec3i minesCenter; - private static boolean debugDoNotUseCenter = false; - private static boolean visitKeeperMessagePrinted; - private static final String KEEPER_OF_STRING = "Keeper of "; - private static final String DIAMOND_STRING = "diamond"; - private static final String LAPIS_STRING = "lapis"; - private static final String EMERALD_STRING = "emerald"; - private static final String GOLD_STRING = "gold"; + private static boolean visitKeeperMessagePrinted = false; + private static String KEEPER_OF_STRING = "Keeper of "; + private static String DIAMOND_STRING = "diamond"; + private static String LAPIS_STRING = "lapis"; + private static String EMERALD_STRING = "emerald"; + private static String GOLD_STRING = "gold"; private static final HashMap keeperOffsets = new HashMap() {{ put(DIAMOND_STRING, new Vec3i(33,0,3)); put(LAPIS_STRING, new Vec3i(-33,0,-3)); @@ -104,14 +94,6 @@ public class CrystalMetalDetectorSolver { -9896946827286L // x=-37, y=-21, z=-22 )); - static Predicate treasureAllowedPredicate = CrystalMetalDetectorSolver::treasureAllowed; - static SolutionState currentState = SolutionState.NOT_STARTED; - static SolutionState previousState = SolutionState.NOT_STARTED; - - public interface Predicate { - boolean check(BlockPos blockPos); - } - public static void process(IChatComponent message) { if (SBInfo.getInstance().getLocation() == null || !NotEnoughUpdates.INSTANCE.config.mining.metalDetectorEnabled || @@ -120,7 +102,7 @@ public class CrystalMetalDetectorSolver { return; } - boolean centerNewlyDiscovered = locateMinesCenterIfNeeded(); + locateMinesCenterIfNeeded(); double distToTreasure = Double.parseDouble(message .getUnformattedText() @@ -140,64 +122,20 @@ public class CrystalMetalDetectorSolver { chestRecentlyFound = false; } - SolutionState originalState = currentState; - int originalCount = possibleBlocks.size(); - Vec3Comparable adjustedPlayerPos = getPlayerPosAdjustedForEyeHeight(); - findPossibleSolutions(distToTreasure, adjustedPlayerPos, centerNewlyDiscovered); - if (currentState != originalState || originalCount != possibleBlocks.size()) { - switch (currentState) { - case FOUND_KNOWN: - NEUDebugLogger.log(NEUDebugFlag.METAL, "Known location identified."); - // falls through - case FOUND: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU] Found solution.")); - if (NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.contains(NEUDebugFlag.METAL) && - (previousState == SolutionState.INVALID || previousState == SolutionState.FAILED)) { - NEUDebugLogger.log(NEUDebugFlag.METAL, - EnumChatFormatting.AQUA + "Solution coordinates: " + - EnumChatFormatting.WHITE + possibleBlocks.iterator().next().toString()); - } - break; - case INVALID: - mc.thePlayer.addChatMessage(new ChatComponentText( - EnumChatFormatting.RED + "[NEU] Previous solution is invalid.")); - logDiagnosticData(false); - resetSolution(false); - break; - case FAILED: - mc.thePlayer.addChatMessage(new ChatComponentText( - EnumChatFormatting.RED + "[NEU] Failed to find a solution.")); - logDiagnosticData(false); - resetSolution(false); - break; - case MULTIPLE_KNOWN: - NEUDebugLogger.log(NEUDebugFlag.METAL, "Multiple known locations identified:"); - // falls through - case MULTIPLE: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "[NEU] Need another position to find solution. Possible blocks: " + possibleBlocks.size())); - break; - default: - throw new IllegalStateException("Metal detector is in invalid state"); - } - } - } - - static void findPossibleSolutions(double distToTreasure, Vec3Comparable playerPos, boolean centerNewlyDiscovered) { - if (prevDistToTreasure == distToTreasure && prevPlayerPos.equals(playerPos) && - !evaluatedPlayerPositions.containsKey(playerPos)) { - evaluatedPlayerPositions.put(playerPos, distToTreasure); + if (prevDistToTreasure == distToTreasure && + prevPlayerPos.equals(mc.thePlayer.getPosition()) && + !evaluatedPlayerPositions.keySet().contains(mc.thePlayer.getPosition())) { if (possibleBlocks.size() == 0) { + evaluatedPlayerPositions.put(mc.thePlayer.getPosition(), distToTreasure); for (int zOffset = (int) Math.floor(-distToTreasure); zOffset <= Math.ceil(distToTreasure); zOffset++) { for (int y = 65; y <= 75; y++) { double calculatedDist = 0; int xOffset = 0; while (calculatedDist < distToTreasure) { - BlockPos pos = new BlockPos(Math.floor(playerPos.xCoord) + xOffset, - y, Math.floor(playerPos.zCoord) + zOffset - ); - calculatedDist = playerPos.distanceTo(new Vec3Comparable(pos).addVector(0D, 1D, 0D)); - if (round(calculatedDist, 1) == distToTreasure && treasureAllowedPredicate.check(pos)) { + BlockPos pos = new BlockPos(Math.floor(mc.thePlayer.posX) + xOffset, + y, Math.floor(mc.thePlayer.posZ) + zOffset); + calculatedDist = getPlayerPos().distanceTo(new Vec3(pos).addVector(0D, 1D, 0D)); + if (round(calculatedDist, 1) == distToTreasure && treasureAllowed(pos)) { possibleBlocks.add(pos); } xOffset++; @@ -205,11 +143,10 @@ public class CrystalMetalDetectorSolver { xOffset = 0; calculatedDist = 0; while (calculatedDist < distToTreasure) { - BlockPos pos = new BlockPos(Math.floor(playerPos.xCoord) - xOffset, - y, Math.floor(playerPos.zCoord) + zOffset - ); - calculatedDist = playerPos.distanceTo(new Vec3Comparable(pos).addVector(0D, 1D, 0D)); - if (round(calculatedDist, 1) == distToTreasure && treasureAllowedPredicate.check(pos)) { + BlockPos pos = new BlockPos(Math.floor(mc.thePlayer.posX) - xOffset, + y, Math.floor(mc.thePlayer.posZ) + zOffset); + calculatedDist = getPlayerPos().distanceTo(new Vec3(pos).addVector(0D, 1D, 0D)); + if (round(calculatedDist, 1) == distToTreasure && treasureAllowed(pos)) { possibleBlocks.add(pos); } xOffset++; @@ -217,33 +154,48 @@ public class CrystalMetalDetectorSolver { } } - updateSolutionState(); + checkAndDisplaySolutionState(); } else if (possibleBlocks.size() != 1) { + evaluatedPlayerPositions.put(mc.thePlayer.getPosition().getImmutable(), distToTreasure); HashSet temp = new HashSet<>(); for (BlockPos pos : possibleBlocks) { - if (round(playerPos.distanceTo(new Vec3Comparable(pos).addVector(0D, 1D, 0D)), 1) == distToTreasure) { + if (round(getPlayerPos().distanceTo(new Vec3(pos).addVector(0D, 1D, 0D)), 1) == distToTreasure) { temp.add(pos); } } possibleBlocks = temp; - updateSolutionState(); + checkAndDisplaySolutionState(); } else { BlockPos pos = possibleBlocks.iterator().next(); - if (Math.abs(distToTreasure - (playerPos.distanceTo(new Vec3Comparable(pos)))) > 5) { - currentState = SolutionState.INVALID; + if (Math.abs(distToTreasure - (getPlayerPos().distanceTo(new Vec3(pos)))) > 5) { + mc.thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.RED + "[NEU] Previous solution is invalid.")); + blockPosIfLastSolutionInvalid = pos.getImmutable(); + logDiagnosticData(false); + resetSolution(false); } } - } else if (centerNewlyDiscovered && possibleBlocks.size() > 1) { - updateSolutionState(); } - prevPlayerPos = playerPos; + prevPlayerPos = mc.thePlayer.getPosition().getImmutable(); prevDistToTreasure = distToTreasure; } - public static void setDebugDoNotUseCenter(boolean val) { - debugDoNotUseCenter = val; + private static void checkForSingleKnownLocationMatch() { + if (minesCenter == BlockPos.NULL_VECTOR || possibleBlocks.size() < 2) { + return; + } + + HashSet temp = possibleBlocks.stream() + .filter(block -> knownChestOffsets.contains(block.subtract(minesCenter).toLong())) + .collect(Collectors.toCollection(HashSet::new)); + if (temp.size() == 1) { + possibleBlocks = temp; + NEUDebugLogger.log(NEUDebugFlag.METAL, "Known location identified."); + } else if (temp.size() > 1) { + NEUDebugLogger.log(NEUDebugFlag.METAL, temp.size() + " known locations identified:"); + } } private static String getFriendlyBlockPositions(Collection positions) { @@ -254,13 +206,10 @@ public class CrystalMetalDetectorSolver { StringBuilder sb = new StringBuilder(); sb.append("\n"); for (BlockPos blockPos : positions) { - sb.append("Absolute: "); - sb.append(blockPos.toString()); + sb.append("Absolute: " + blockPos.toString()); if (minesCenter != Vec3i.NULL_VECTOR) { BlockPos relativeOffset = blockPos.subtract(minesCenter); - sb.append(", Relative: "); - sb.append(relativeOffset.toString() ); - sb.append(" (" + relativeOffset.toLong() + ")"); + sb.append(", Relative: " + relativeOffset.toString() + " (" + relativeOffset.toLong() + ")"); } sb.append("\n"); } @@ -268,23 +217,22 @@ public class CrystalMetalDetectorSolver { return sb.toString(); } - private static String getFriendlyEvaluatedPositions() { - if (!NEUDebugLogger.isFlagEnabled(NEUDebugFlag.METAL) || evaluatedPlayerPositions.size() == 0) { + private static String getFriendlyEvaluatedPositions(HashMap positions) { + if (!NEUDebugLogger.isFlagEnabled(NEUDebugFlag.METAL) || positions.size() == 0) { return ""; } StringBuilder sb = new StringBuilder(); sb.append("\n"); - for (Vec3Comparable vec : evaluatedPlayerPositions.keySet()) { - sb.append("Absolute: " + vec.toString()); + for (BlockPos blockPos : positions.keySet()) { + sb.append("Absolute: " + blockPos.toString()); if (minesCenter != Vec3i.NULL_VECTOR) { - BlockPos positionBlockPos = new BlockPos(vec); - BlockPos relativeOffset = positionBlockPos.subtract(minesCenter); + BlockPos relativeOffset = blockPos.subtract(minesCenter); sb.append(", Relative: " + relativeOffset.toString() + " (" + relativeOffset.toLong() + ")"); } sb.append(" Distance: "); - sb.append(evaluatedPlayerPositions.get(vec)); + sb.append(positions.get(blockPos)); sb.append("\n"); } @@ -292,8 +240,101 @@ public class CrystalMetalDetectorSolver { return sb.toString(); } + public static void logDiagnosticData(boolean outputAlways) { + if (SBInfo.getInstance().getLocation() == null) { + mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "[NEU] This command is not available outside SkyBlock")); + return; + } + + if (!NotEnoughUpdates.INSTANCE.config.mining.metalDetectorEnabled) + { + mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + + "[NEU] Metal Detector Solver is not enabled.")); + return; + } + + if (!outputAlways && !NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.contains(NEUDebugFlag.METAL)) { + return; + } + + boolean originalDebugFlag = !NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.add(NEUDebugFlag.METAL); + + StringBuilder diagsMessage = new StringBuilder(); + + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Mines Center: "); + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append((minesCenter == Vec3i.NULL_VECTOR) ? "" : minesCenter.toString()); + diagsMessage.append("\n"); + + diagsMessage.append("\n"); + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Previous Player Position: "); + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append((prevPlayerPos == null) ? "" : prevPlayerPos.toString()); + diagsMessage.append("\n"); + + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Previous Distance To Treasure: "); + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append((prevDistToTreasure == 0) ? "" : prevDistToTreasure); + diagsMessage.append("\n"); + + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Last Solution Invalid Position: "); + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append((blockPosIfLastSolutionInvalid == null) ? "" : blockPosIfLastSolutionInvalid.toString()); + diagsMessage.append("\n"); + + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Current Possible Blocks: "); + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append(possibleBlocks.size()); + diagsMessage.append(getFriendlyBlockPositions(possibleBlocks)); + diagsMessage.append("\n"); + + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Evaluated player positions: "); + diagsMessage.append(EnumChatFormatting.WHITE); + diagsMessage.append(evaluatedPlayerPositions.size()); + diagsMessage.append(getFriendlyEvaluatedPositions(evaluatedPlayerPositions)); + diagsMessage.append("\n"); + + diagsMessage.append(EnumChatFormatting.AQUA); + diagsMessage.append("Chest locations not on known list:\n"); + diagsMessage.append(EnumChatFormatting.WHITE); + if (minesCenter != Vec3i.NULL_VECTOR) { + HashSet locationsNotOnKnownList = openedChestPositions + .stream() + .filter(block -> !knownChestOffsets.contains(block.subtract(minesCenter).toLong())) + .map(block -> block.subtract(minesCenter)) + .collect(Collectors.toCollection(HashSet::new)); + if (locationsNotOnKnownList.size() > 0) { + for (BlockPos blockPos : locationsNotOnKnownList) { + diagsMessage.append(String.format( + "%dL,\t\t// x=%d, y=%d, z=%d", + blockPos.toLong(), + blockPos.getX(), + blockPos.getY(), + blockPos.getZ() + )); + } + } + } else { + diagsMessage.append(""); + } + + NEUDebugLogger.log(NEUDebugFlag.METAL, diagsMessage.toString()); + + if (!originalDebugFlag) { + NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.remove(NEUDebugFlag.METAL); + } + } + public static void resetSolution(Boolean chestFound) { if (chestFound) { + blockPosIfLastSolutionInvalid = null; prevPlayerPos = null; prevDistToTreasure = 0; if (possibleBlocks.size() == 1) { @@ -304,18 +345,15 @@ public class CrystalMetalDetectorSolver { chestRecentlyFound = chestFound; possibleBlocks.clear(); evaluatedPlayerPositions.clear(); - previousState = currentState; - currentState = SolutionState.NOT_STARTED; } public static void initWorld() { minesCenter = Vec3i.NULL_VECTOR; visitKeeperMessagePrinted = false; + blockPosIfLastSolutionInvalid = null; openedChestPositions.clear(); - chestLastFoundMillis = 0; prevDistToTreasure = 0; prevPlayerPos = null; - currentState = SolutionState.NOT_STARTED; resetSolution(false); } @@ -339,14 +377,15 @@ public class CrystalMetalDetectorSolver { } } - private static boolean locateMinesCenterIfNeeded() { + private static void locateMinesCenterIfNeeded() { if (minesCenter != Vec3i.NULL_VECTOR) { - return false; + return; } List keeperEntities = mc.theWorld.getEntities(EntityArmorStand.class, (entity) -> { if (!entity.hasCustomName()) return false; - return entity.getCustomNameTag().contains(KEEPER_OF_STRING); + if (entity.getCustomNameTag().contains(KEEPER_OF_STRING)) return true; + return false; }); if (keeperEntities.size() == 0) { @@ -355,7 +394,7 @@ public class CrystalMetalDetectorSolver { "[NEU] Approach a Keeper while holding the metal detector to enable faster treasure hunting.")); visitKeeperMessagePrinted = true; } - return false; + return; } EntityArmorStand keeperEntity = keeperEntities.get(0); @@ -368,11 +407,6 @@ public class CrystalMetalDetectorSolver { EnumChatFormatting.WHITE + minesCenter.toString()); mc.thePlayer.addChatMessage(new ChatComponentText( EnumChatFormatting.YELLOW + "[NEU] Faster treasure hunting is now enabled based on Keeper location.")); - return true; - } - - public static void setMinesCenter(BlockPos center) { - minesCenter = center; } private static double round(double value, int precision) { @@ -380,174 +414,42 @@ public class CrystalMetalDetectorSolver { return (double) Math.round(value * scale) / scale; } - private static void updateSolutionState() { - previousState = currentState; - + private static void checkAndDisplaySolutionState() { if (possibleBlocks.size() == 0) { - currentState = SolutionState.FAILED; - return; - } - - if (possibleBlocks.size() == 1) { - currentState = SolutionState.FOUND; + mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Failed to find a solution.")); + logDiagnosticData(false); + resetSolution(false); return; } - // Narrow solutions using known locations if the mines center is known - if (minesCenter.equals(BlockPos.NULL_VECTOR) || debugDoNotUseCenter) { - currentState = SolutionState.MULTIPLE; - return; - } - - HashSet temp = - possibleBlocks.stream() - .filter(block -> knownChestOffsets.contains(block.subtract(minesCenter).toLong())) - .collect(Collectors.toCollection(HashSet::new)); - if (temp.size() == 0) { - currentState = SolutionState.MULTIPLE; - return; - } - - if (temp.size() == 1) { - possibleBlocks = temp; - currentState = SolutionState.FOUND_KNOWN; - return; - - } - - currentState = SolutionState.MULTIPLE_KNOWN; - } - - public static BlockPos getSolution() { - if (CrystalMetalDetectorSolver.possibleBlocks.size() != 1) { - return BlockPos.ORIGIN; + checkForSingleKnownLocationMatch(); + if (possibleBlocks.size() > 1) { + mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + + "[NEU] Need another position to find solution. Possible blocks: " + possibleBlocks.size())); + } else { + mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU] Found solution.")); } - - return CrystalMetalDetectorSolver.possibleBlocks.stream().iterator().next(); } - private static Vec3Comparable getPlayerPosAdjustedForEyeHeight() { - return new Vec3Comparable( + private static Vec3 getPlayerPos() { + return new Vec3( mc.thePlayer.posX, mc.thePlayer.posY + (mc.thePlayer.getEyeHeight() - mc.thePlayer.getDefaultEyeHeight()), mc.thePlayer.posZ ); } - static boolean isKnownOffset(BlockPos pos) { - return knownChestOffsets.contains(pos.subtract(minesCenter).toLong()); - } - - static boolean isAllowedBlockType(BlockPos pos) { - return mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:gold_block") || + private static boolean treasureAllowed(BlockPos pos) { + boolean airAbove = mc.theWorld. + getBlockState(pos.add(0, 1, 0)).getBlock().getRegistryName().equals("minecraft:air"); + boolean allowedBlockType = mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:gold_block") || mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:prismarine") || mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:chest") || mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:stained_glass") || mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:stained_glass_pane") || mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:wool") || mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:stained_hardened_clay"); - } - - static boolean isAirAbove(BlockPos pos) { - return mc.theWorld. - getBlockState(pos.add(0, 1, 0)).getBlock().getRegistryName().equals("minecraft:air"); - } - - private static boolean treasureAllowed(BlockPos pos) { - boolean airAbove = isAirAbove(pos); - boolean allowedBlockType = isAllowedBlockType(pos); - return isKnownOffset(pos) || (airAbove && allowedBlockType); - } - - static private String getDiagnosticMessage() { - StringBuilder diagsMessage = new StringBuilder(); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Mines Center: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append((minesCenter.equals(Vec3i.NULL_VECTOR)) ? "" : minesCenter.toString()); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Current Solution State: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append(currentState.name()); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Previous Solution State: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append(previousState.name()); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Previous Player Position: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append((prevPlayerPos == null) ? "" : prevPlayerPos.toString()); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Previous Distance To Treasure: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append((prevDistToTreasure == 0) ? "" : prevDistToTreasure); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Current Possible Blocks: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append(possibleBlocks.size()); - diagsMessage.append(getFriendlyBlockPositions(possibleBlocks)); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Evaluated player positions: "); - diagsMessage.append(EnumChatFormatting.WHITE); - diagsMessage.append(evaluatedPlayerPositions.size()); - diagsMessage.append(getFriendlyEvaluatedPositions()); - diagsMessage.append("\n"); - - diagsMessage.append(EnumChatFormatting.AQUA); - diagsMessage.append("Chest locations not on known list:\n"); - diagsMessage.append(EnumChatFormatting.WHITE); - if (minesCenter != Vec3i.NULL_VECTOR) { - HashSet locationsNotOnKnownList = openedChestPositions - .stream() - .filter(block -> !knownChestOffsets.contains(block.subtract(minesCenter).toLong())) - .map(block -> block.subtract(minesCenter)) - .collect(Collectors.toCollection(HashSet::new)); - if (locationsNotOnKnownList.size() > 0) { - for (BlockPos blockPos : locationsNotOnKnownList) { - diagsMessage.append(String.format( - "%dL,\t\t// x=%d, y=%d, z=%d", - blockPos.toLong(), - blockPos.getX(), - blockPos.getY(), - blockPos.getZ() - )); - } - } - } else { - diagsMessage.append(""); - } - - return diagsMessage.toString(); - } - - public static void logDiagnosticData(boolean outputAlways) { - if (!SBInfo.getInstance().checkForSkyblockLocation()) { - return; - } - - if (!NotEnoughUpdates.INSTANCE.config.mining.metalDetectorEnabled) - { - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + - "[NEU] Metal Detector Solver is not enabled.")); - return; - } - - boolean metalDebugFlagSet = NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.contains(NEUDebugFlag.METAL); - if (outputAlways || metalDebugFlagSet) { - NEUDebugLogger.logAlways(getDiagnosticMessage()); - } + boolean knownOffset = knownChestOffsets.contains(pos.subtract(minesCenter).toLong()); + return airAbove & (knownOffset | allowedBlockType); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java index 9a950e7f..25f39c3a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java @@ -2,67 +2,27 @@ package io.github.moulberry.notenoughupdates.miscfeatures; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.core.util.Line; -import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable; -import io.github.moulberry.notenoughupdates.options.NEUConfig; import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag; import io.github.moulberry.notenoughupdates.util.NEUDebugLogger; import io.github.moulberry.notenoughupdates.util.SBInfo; -import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.event.ClickEvent; +import net.minecraft.event.HoverEvent; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatStyle; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.Vec3i; -import net.minecraftforge.client.ClientCommandHandler; +import net.minecraft.util.Vec3; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.function.BooleanSupplier; -import java.util.function.LongSupplier; - public class CrystalWishingCompassSolver { - enum SolverState { - NOT_STARTED, - PROCESSING_FIRST_USE, - NEED_SECOND_COMPASS, - PROCESSING_SECOND_USE, - SOLVED, - FAILED_EXCEPTION, - FAILED_TIMEOUT_NO_REPEATING, - FAILED_TIMEOUT_NO_PARTICLES, - FAILED_INTERSECTION_CALCULATION, - FAILED_INVALID_SOLUTION, - } - - enum CompassTarget { - GOBLIN_QUEEN, - GOBLIN_KING, - BAL, - JUNGLE_TEMPLE, - ODAWA, - PRECURSOR_CITY, - MINES_OF_DIVAN, - CRYSTAL_NUCLEUS, - } - - enum Crystal { - AMBER, - AMETHYST, - JADE, - SAPPHIRE, - TOPAZ, - } - private static final CrystalWishingCompassSolver INSTANCE = new CrystalWishingCompassSolver(); public static CrystalWishingCompassSolver getInstance() { return INSTANCE; @@ -71,72 +31,40 @@ public class CrystalWishingCompassSolver { private static final Minecraft mc = Minecraft.getMinecraft(); private static boolean isSkytilsPresent = false; - // NOTE: There is a small set of breakable blocks above the nucleus at Y > 181. While this zone is reported - // as the Crystal Nucleus by Hypixel, for wishing compass purposes it is in the appropriate quadrant. - private static final AxisAlignedBB NUCLEUS_BB = new AxisAlignedBB(462, 63, 461, 564, 181, 565); - private static final AxisAlignedBB HOLLOWS_BB = new AxisAlignedBB(201, 30, 201, 824, 189, 824); - private static final AxisAlignedBB PRECURSOR_REMNANTS_BB = new AxisAlignedBB(513, 64, 513, 824, 189, 824); - private static final AxisAlignedBB MITHRIL_DEPOSITS_BB = new AxisAlignedBB(513, 64, 201, 824, 189, 512); - private static final AxisAlignedBB GOBLIN_HOLDOUT_BB = new AxisAlignedBB(201, 64, 513, 512, 189, 824); - private static final AxisAlignedBB JUNGLE_BB = new AxisAlignedBB(201, 64, 201, 512, 189, 512); - private static final AxisAlignedBB MAGMA_FIELDS_BB = new AxisAlignedBB(201, 30, 201, 824, 63, 824); - private static final double MAX_DISTANCE_BETWEEN_PARTICLES = 0.6; - private static final double MAX_DISTANCE_FROM_USE_TO_FIRST_PARTICLE = 9.0; - - // 64.0 is an arbitrary value but seems to work well - private static final double MINIMUM_DISTANCE_SQ_BETWEEN_COMPASSES = 64.0; - - // All particles typically arrive in < 3500, so 5000 should be enough buffer - public static final long ALL_PARTICLES_MAX_MILLIS = 5000L; - - public LongSupplier currentTimeMillis = System::currentTimeMillis; - public BooleanSupplier kingsScentPresent = this::isKingsScentPresent; - public BooleanSupplier keyInInventory = this::isKeyInInventory; - public interface CrystalEnumSetSupplier { - EnumSet getAsCrystalEnumSet(); - } - public CrystalEnumSetSupplier foundCrystals = this::getFoundCrystals; - - private SolverState solverState; - private Compass firstCompass; - private Compass secondCompass; - private Line solutionIntersectionLine; - private EnumSet possibleTargets; - private Vec3Comparable solution; - private Vec3Comparable originalSolution; - private EnumSet solutionPossibleTargets; - - public SolverState getSolverState() { - return solverState; - } - - public Vec3i getSolutionCoords() { - return new Vec3i(solution.xCoord, solution.yCoord, solution.zCoord); - } - - public EnumSet getPossibleTargets() { - return possibleTargets; + // Crystal Nucleus unbreakable blocks, area coordinates reported by Hypixel server are slightly different + private static final AxisAlignedBB NUCLEUS_BB = new AxisAlignedBB(463, 63, 460, 563, 181, 564); + private static final double MAX_COMPASS_PARTICLE_SPREAD = 16; + + private static BlockPos prevPlayerPos; + private long compassUsedMillis = 0; + private Vec3 firstParticle = null; + private Vec3 lastParticle = null; + private double lastParticleDistanceFromFirst = 0; + private Line firstCompassLine = null; + private Line secondCompassLine = null; + private Vec3 solution = null; + private Line solutionIntersectionLine = null; + + private void resetForNewCompass() { + compassUsedMillis = 0; + firstParticle = null; + lastParticle = null; + lastParticleDistanceFromFirst = 0; } private void resetForNewTarget() { NEUDebugLogger.log(NEUDebugFlag.WISHING,"Resetting for new target"); - solverState = SolverState.NOT_STARTED; - firstCompass = null; - secondCompass = null; + resetForNewCompass(); + firstCompassLine = null; + secondCompassLine = null; solutionIntersectionLine = null; - possibleTargets = null; + prevPlayerPos = null; solution = null; - originalSolution = null; - solutionPossibleTargets = null; - } - - public void initWorld() { - resetForNewTarget(); } @SubscribeEvent public void onWorldLoad(WorldEvent.Unload event) { - initWorld(); + resetForNewTarget(); isSkytilsPresent = Loader.isModLoaded("skytils"); } @@ -162,101 +90,28 @@ public class CrystalWishingCompassSolver { return; } - BlockPos playerPos = mc.thePlayer.getPosition().getImmutable(); - try { - HandleCompassResult result = handleCompassUse(playerPos); - switch (result) { - case SUCCESS: - return; - case STILL_PROCESSING_PRIOR_USE: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "[NEU] Wait a little longer before using the wishing compass again.")); - event.setCanceled(true); - break; - case LOCATION_TOO_CLOSE: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "[NEU] Move a little further before using the wishing compass again.")); - event.setCanceled(true); - break; - case POSSIBLE_TARGETS_CHANGED: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "[NEU] Possible wishing compass targets have changed. Solver has been reset.")); - event.setCanceled(true); - break; - case NO_PARTICLES_FOR_PREVIOUS_COMPASS: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "[NEU] No particles detected for prior compass use. Need another position to solve.")); - break; - case PLAYER_IN_NUCLEUS: - mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + - "[NEU] Wishing compass must be used outside the nucleus for accurate results.")); - event.setCanceled(true); - break; - default: - throw new IllegalStateException("Unexpected wishing compass solver state: \n" + getDiagnosticMessage()); + if (isSolved()) { + resetForNewTarget(); + } + + // 64.0 is an arbitrary value but seems to work well + if (prevPlayerPos != null && prevPlayerPos.distanceSq(mc.thePlayer.getPosition()) < 64.0) { + mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + + "[NEU] Move a little further before using the wishing compass again.")); + event.setCanceled(true); + return; } + + prevPlayerPos = mc.thePlayer.getPosition().getImmutable(); + compassUsedMillis = System.currentTimeMillis(); } catch (Exception e) { mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Error processing wishing compass action - see log for details")); e.printStackTrace(); - event.setCanceled(true); - solverState = SolverState.FAILED_EXCEPTION; } } - public HandleCompassResult handleCompassUse(BlockPos playerPos) { - long lastCompassUsedMillis = 0; - switch (solverState) { - case PROCESSING_SECOND_USE: - if (secondCompass != null) { - lastCompassUsedMillis = secondCompass.whenUsedMillis; - } - case PROCESSING_FIRST_USE: - if (lastCompassUsedMillis == 0 && firstCompass != null) { - lastCompassUsedMillis = firstCompass.whenUsedMillis; - } - if (lastCompassUsedMillis != 0 && - (currentTimeMillis.getAsLong() > lastCompassUsedMillis + ALL_PARTICLES_MAX_MILLIS)) { - return HandleCompassResult.NO_PARTICLES_FOR_PREVIOUS_COMPASS; - } - - return HandleCompassResult.STILL_PROCESSING_PRIOR_USE; - case SOLVED: - case FAILED_EXCEPTION: - case FAILED_TIMEOUT_NO_REPEATING: - case FAILED_TIMEOUT_NO_PARTICLES: - case FAILED_INTERSECTION_CALCULATION: - case FAILED_INVALID_SOLUTION: - resetForNewTarget(); - // falls through, NOT_STARTED is the state when resetForNewTarget returns - case NOT_STARTED: - if (NUCLEUS_BB.isVecInside(new Vec3Comparable(playerPos.getX(), playerPos.getY(), playerPos.getZ()))) { - return HandleCompassResult.PLAYER_IN_NUCLEUS; - } - - firstCompass = new Compass(playerPos, currentTimeMillis.getAsLong()); - solverState = SolverState.PROCESSING_FIRST_USE; - possibleTargets = calculatePossibleTargets(playerPos); - return HandleCompassResult.SUCCESS; - case NEED_SECOND_COMPASS: - if (firstCompass.whereUsed.distanceSq(playerPos) < MINIMUM_DISTANCE_SQ_BETWEEN_COMPASSES) { - return HandleCompassResult.LOCATION_TOO_CLOSE; - } - - if (!possibleTargets.equals(calculatePossibleTargets(playerPos))) { - resetForNewTarget(); - return HandleCompassResult.POSSIBLE_TARGETS_CHANGED; - } - - secondCompass = new Compass(playerPos, currentTimeMillis.getAsLong()); - solverState = SolverState.PROCESSING_