aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java391
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnderNodes.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java37
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java29
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java26
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java60
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeHistory.java74
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/TitleUtil.java92
23 files changed, 866 insertions, 38 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index af190244..71aa10b6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -34,6 +34,7 @@ import io.github.moulberry.notenoughupdates.recipes.CraftingOverlay;
import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe;
import io.github.moulberry.notenoughupdates.recipes.Ingredient;
import io.github.moulberry.notenoughupdates.recipes.NeuRecipe;
+import io.github.moulberry.notenoughupdates.recipes.RecipeHistory;
import io.github.moulberry.notenoughupdates.util.ApiUtil;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.HotmInformation;
@@ -113,12 +114,16 @@ public class NEUManager {
new KeyBinding("Show usages for item", Keyboard.KEY_U, "NotEnoughUpdates");
public final KeyBinding keybindViewRecipe =
new KeyBinding("Show recipe for item", Keyboard.KEY_R, "NotEnoughUpdates");
+ public final KeyBinding keybindPreviousRecipe =
+ new KeyBinding("Show previous recipe", Keyboard.KEY_LBRACKET, "NotEnoughUpdates");
+ public final KeyBinding keybindNextRecipe =
+ new KeyBinding("Show next recipe", Keyboard.KEY_RBRACKET, "NotEnoughUpdates");
public final KeyBinding keybindToggleDisplay = new KeyBinding("Toggle NEU overlay", 0, "NotEnoughUpdates");
public final KeyBinding keybindClosePanes = new KeyBinding("Close NEU panes", 0, "NotEnoughUpdates");
public final KeyBinding keybindItemSelect = new KeyBinding("Select Item", -98 /*middle*/, "NotEnoughUpdates");
public final KeyBinding[] keybinds = new KeyBinding[]{
- keybindGive, keybindFavourite, keybindViewUsages, keybindViewRecipe,
- keybindToggleDisplay, keybindClosePanes, keybindItemSelect
+ keybindGive, keybindFavourite, keybindViewUsages, keybindViewRecipe, keybindPreviousRecipe,
+ keybindNextRecipe, keybindToggleDisplay, keybindClosePanes, keybindItemSelect
};
public String viewItemAttemptID = null;
@@ -884,7 +889,6 @@ public class NEUManager {
case "viewpotion":
neu.sendChatMessage("/viewpotion " + internalName.split(";")[0].toLowerCase(Locale.ROOT));
}
- displayGuiItemRecipe(internalName);
}
public void showRecipe(String internalName) {
@@ -988,6 +992,7 @@ public class NEUManager {
List<NeuRecipe> usages = getAvailableUsagesFor(internalName);
if (usages.isEmpty()) return false;
NotEnoughUpdates.INSTANCE.openGui = (new GuiItemRecipe(usages, this));
+ RecipeHistory.add(NotEnoughUpdates.INSTANCE.openGui);
return true;
}
@@ -996,6 +1001,7 @@ public class NEUManager {
List<NeuRecipe> recipes = getAvailableRecipesFor(internalName);
if (recipes.isEmpty()) return false;
NotEnoughUpdates.INSTANCE.openGui = (new GuiItemRecipe(recipes, this));
+ RecipeHistory.add(NotEnoughUpdates.INSTANCE.openGui);
return true;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index 2f55c338..87ce915b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -1219,8 +1219,8 @@ public class NEUOverlay extends Gui {
String internal1 = o1.get("internalname").getAsString();
String internal2 = o2.get("internalname").getAsString();
- double cost1 = manager.auctionManager.getBazaarOrBin(internal1);
- double cost2 = manager.auctionManager.getBazaarOrBin(internal2);
+ double cost1 = manager.auctionManager.getBazaarOrBin(internal1, false);
+ double cost2 = manager.auctionManager.getBazaarOrBin(internal2, false);
if (cost1 < cost2) return mult;
if (cost1 > cost2) return -mult;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index 143033b7..b514e419 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -45,6 +45,7 @@ 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.CustomSkulls;
+import io.github.moulberry.notenoughupdates.miscfeatures.DungeonNpcProfitOverlay;
import io.github.moulberry.notenoughupdates.miscfeatures.DwarvenMinesWaypoints;
import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
import io.github.moulberry.notenoughupdates.miscfeatures.FairySouls;
@@ -78,6 +79,7 @@ import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.recipes.RecipeGenerator;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.TitleUtil;
import io.github.moulberry.notenoughupdates.util.Utils;
import io.github.moulberry.notenoughupdates.util.XPInformation;
import net.minecraft.client.Minecraft;
@@ -295,6 +297,7 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(new DwarvenMinesWaypoints());
MinecraftForge.EVENT_BUS.register(new FuelBar());
MinecraftForge.EVENT_BUS.register(new AuctionProfit());
+ MinecraftForge.EVENT_BUS.register(new DungeonNpcProfitOverlay());
MinecraftForge.EVENT_BUS.register(XPInformation.getInstance());
MinecraftForge.EVENT_BUS.register(OverlayManager.petInfoOverlay);
MinecraftForge.EVENT_BUS.register(OverlayManager.timersOverlay);
@@ -322,6 +325,7 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(MinionHelperManager.getInstance());
MinecraftForge.EVENT_BUS.register(navigation);
MinecraftForge.EVENT_BUS.register(new WorldListener(this));
+ MinecraftForge.EVENT_BUS.register(TitleUtil.getInstance());
if (Minecraft.getMinecraft().getResourceManager() instanceof IReloadableResourceManager) {
IReloadableResourceManager manager = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
index 1b6896db..755e53f5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
@@ -822,10 +822,11 @@ public class APIManager {
return keys;
}
- public double getBazaarOrBin(String internalName) {
+ public double getBazaarOrBin(String internalName, boolean useSellingPrice) {
+ String curr = (useSellingPrice ? "curr_sell" : "curr_buy");
JsonObject bazaarInfo = manager.auctionManager.getBazaarInfo(internalName);
- if (bazaarInfo != null && bazaarInfo.get("curr_buy") != null) {
- return bazaarInfo.get("curr_buy").getAsFloat();
+ if (bazaarInfo != null && bazaarInfo.get(curr) != null) {
+ return bazaarInfo.get(curr).getAsFloat();
} else {
return manager.auctionManager.getLowestBin(internalName);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java
index e7ce29c3..d7bd097a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java
@@ -378,14 +378,18 @@ public class RenderUtils {
}
public static void renderWayPoint(List<String> str, Vec3i loc, float partialTicks) {
- renderWayPoint(str, new Vector3f(loc.getX(), loc.getY(), loc.getZ()), partialTicks);
+ renderWayPoint(str, new Vector3f(loc.getX(), loc.getY(), loc.getZ()), partialTicks, false);
}
public static void renderWayPoint(String str, Vector3f loc, float partialTicks) {
- renderWayPoint(Arrays.asList(str), loc, partialTicks);
+ renderWayPoint(Arrays.asList(str), loc, partialTicks, false);
+ }
+
+ public static void renderWayPoint(Vec3i loc, float partialTicks) {
+ renderWayPoint(Arrays.asList(""), new Vector3f(loc.getX(), loc.getY(), loc.getZ()), partialTicks, true);
}
- public static void renderWayPoint(List<String> lines, Vector3f loc, float partialTicks) {
+ public static void renderWayPoint(List<String> lines, Vector3f loc, float partialTicks, boolean onlyShowDistance) {
GlStateManager.alphaFunc(516, 0.1F);
GlStateManager.pushMatrix();
@@ -409,7 +413,7 @@ public class RenderUtils {
GlStateManager.translate(x, y, z);
GlStateManager.translate(0, viewer.getEyeHeight(), 0);
- lines = new ArrayList<>(lines);
+ lines = onlyShowDistance ? new ArrayList<>() : new ArrayList<>(lines);
lines.add(EnumChatFormatting.YELLOW.toString() + Math.round(dist) + "m");
renderNametag(lines);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java
index a5acd5b4..6a94c0b3 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java
@@ -23,6 +23,7 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.dungeons.DungeonWin;
import io.github.moulberry.notenoughupdates.miscfeatures.CookieWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.EnderNodes;
import io.github.moulberry.notenoughupdates.miscfeatures.StreamerMode;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
import io.github.moulberry.notenoughupdates.overlays.SlayerOverlay;
@@ -306,5 +307,9 @@ public class ChatListener {
unformatted.equals("You have successfully picked the lock on this chest!")
|| (unformatted.startsWith("You received +") && unformatted.endsWith(" Powder")))
OverlayManager.powderGrindingOverlay.message(unformatted);
+
+ if (unformatted.equals("ENDER NODE! You found Endermite Nest!")) {
+ EnderNodes.dispalyEndermiteNotif();
+ }
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java
index fdae53ea..2b7a9bef 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java
@@ -139,7 +139,7 @@ public class ItemTooltipRngListener {
private String getFormatCoinsPer(ItemStack stack, int needed, int multiplier, String label) {
String internalName = neu.manager.createItemResolutionQuery().withItemStack(stack).resolveInternalName();
- double profit = neu.manager.auctionManager.getBazaarOrBin(internalName);
+ double profit = neu.manager.auctionManager.getBazaarOrBin(internalName, false);
if (profit <= 0) return null;
//ask hypixel nicely to release a 'chest price api' with 4 dimensions for us. the 4 dimensions needed are: item name, floor, normal/mm, s/s+
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java
index 43a1daf9..5b388dea 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java
@@ -34,11 +34,13 @@ import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
import io.github.moulberry.notenoughupdates.miscfeatures.NPCRetexturing;
import io.github.moulberry.notenoughupdates.miscgui.AccessoryBagOverlay;
import io.github.moulberry.notenoughupdates.miscgui.GuiCustomEnchant;
+import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
import io.github.moulberry.notenoughupdates.miscgui.hex.GuiCustomHex;
import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
import io.github.moulberry.notenoughupdates.overlays.TextOverlay;
import io.github.moulberry.notenoughupdates.overlays.TextTabOverlay;
+import io.github.moulberry.notenoughupdates.recipes.RecipeHistory;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.NotificationHandler;
import io.github.moulberry.notenoughupdates.util.ProfileApiSyncer;
@@ -162,6 +164,11 @@ public class NEUEventListener {
if (longUpdate) {
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiItemRecipe)) {
+ RecipeHistory.clear();
+ }
+
CrystalOverlay.tick();
FairySouls.getInstance().tick();
XPInformation.getInstance().tick();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
index 2eb4c23a..949358ad 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
@@ -40,6 +40,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.AuctionBINWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.AuctionProfit;
import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.DungeonNpcProfitOverlay;
import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
import io.github.moulberry.notenoughupdates.miscgui.AccessoryBagOverlay;
@@ -136,6 +137,8 @@ public class RenderListener {
public static long lastGuiClosed = 0;
public static boolean inventoryLoaded = false;
private final NotEnoughUpdates neu;
+ private final NumberFormat format = new DecimalFormat("#,##0.#", new DecimalFormatSymbols(Locale.US));
+ private final Pattern ESSENCE_PATTERN = Pattern.compile("§d(.+) Essence §8x([\\d,]+)");
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
JsonObject essenceJson = new JsonObject();
private boolean hoverInv = false;
@@ -150,9 +153,6 @@ public class RenderListener {
private boolean typing;
private HashMap<String, String> cachedDefinitions;
private boolean inDungeonPage = false;
- private final NumberFormat format = new DecimalFormat("#,##0.#", new DecimalFormatSymbols(Locale.US));
-
- private final Pattern ESSENCE_PATTERN = Pattern.compile("§d(.+) Essence §8x([\\d,]+)");
public RenderListener(NotEnoughUpdates neu) {
this.neu = neu;
@@ -458,7 +458,6 @@ public class RenderListener {
return;
}
-
boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
boolean customAhActive =
@@ -559,7 +558,7 @@ public class RenderListener {
x -= 25;
}
}
- if (inDungeonPage) {
+ if (inDungeonPage || DungeonNpcProfitOverlay.isRendering()) {
if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
y < guiTop + 100) {
x += 185;
@@ -694,7 +693,7 @@ public class RenderListener {
}
}
- if (inDungeonPage) {
+ if (inDungeonPage || DungeonNpcProfitOverlay.isRendering()) {
if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
y < guiTop + 100) {
x += 185;
@@ -812,7 +811,7 @@ public class RenderListener {
if (bazaarPrice < 5000000 && internal.equals("RECOMBOBULATOR_3000")) bazaarPrice = 5000000;
double worth = -1;
- boolean isOnBz = false;
+ boolean isOnBz = false;
if (bazaarPrice >= 0) {
worth = bazaarPrice;
isOnBz = true;
@@ -1086,7 +1085,6 @@ public class RenderListener {
return;
}
-
boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
boolean customAhActive =
@@ -1176,7 +1174,7 @@ public class RenderListener {
x -= 25;
}
}
- if (inDungeonPage) {
+ if (inDungeonPage || DungeonNpcProfitOverlay.isRendering()) {
if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
y < guiTop + 100) {
x += 185;
@@ -1564,7 +1562,6 @@ public class RenderListener {
return;
}
-
boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
boolean customAhActive =
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java
new file mode 100644
index 00000000..7caa4d6b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.init.Items;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.opengl.GL11;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DungeonNpcProfitOverlay {
+
+ private static final ResourceLocation dungeonProfitResource =
+ new ResourceLocation("notenoughupdates:dungeon_chest_worth.png");
+
+ private static final Pattern chestNamePattern = Pattern.compile(".+ Catacombs - Floor .+");
+ private static final Pattern essencePattern = Pattern.compile(
+ "^§.(?<essenceType>\\w+) Essence §.x(?<essenceAmount>\\d+)$");
+ private static final Pattern enchantedBookPattern = Pattern.compile("^§.Enchanted Book \\((?<enchantName>.*)\\)");
+ private static List<DungeonChest> chestProfits;
+ private static List<Slot> previousSlots;
+
+ /**
+ * Check the current status for the overlay
+ *
+ * @return if the overlay is rendering right now
+ */
+ public static boolean isRendering() {
+ return NotEnoughUpdates.INSTANCE.config.dungeons.croesusProfitOverlay && chestProfits != null;
+ }
+
+ /**
+ * Highlight the slot that is being drawn if applicable. Called by MixinGuiContainer
+ *
+ * @param slot the slot to be checked
+ * @see io.github.moulberry.notenoughupdates.mixins.MixinGuiContainer#drawSlotRet(Slot, CallbackInfo)
+ */
+ public static void onDrawSlot(Slot slot) {
+ if (isRendering() && NotEnoughUpdates.INSTANCE.config.dungeons.croesusHighlightHighestProfit) {
+ for (DungeonChest chestProfit : chestProfits) {
+ if (chestProfit.shouldHighlight) {
+ if (slot.slotNumber == chestProfit.slot) {
+ Gui.drawRect(
+ slot.xDisplayPosition,
+ slot.yDisplayPosition,
+ slot.xDisplayPosition + 16,
+ slot.yDisplayPosition + 16,
+ Color.GREEN.getRGB()
+ );
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.dungeons.croesusProfitOverlay || !(event.gui instanceof GuiChest)) {
+ chestProfits = null;
+ previousSlots = null;
+ return;
+ }
+
+ String lastOpenChestName = SBInfo.getInstance().lastOpenChestName;
+ Matcher matcher = chestNamePattern.matcher(lastOpenChestName);
+ if (!matcher.matches()) {
+ chestProfits = null;
+ previousSlots = null;
+ return;
+ }
+ GuiChest guiChest = (GuiChest) event.gui;
+ List<Slot> slots = guiChest.inventorySlots.inventorySlots;
+
+ if (chestProfits == null || chestProfits.isEmpty() || !slots.equals(previousSlots)) {
+ updateDungeonChests(slots);
+ }
+ previousSlots = guiChest.inventorySlots.inventorySlots;
+
+ render(guiChest);
+ }
+
+ /**
+ * Update the profit applicable for the chests currently visible
+ *
+ * @param inventorySlots list of Slots from the GUI containing the dungeon chest previews
+ */
+ private void updateDungeonChests(List<Slot> inventorySlots) {
+ chestProfits = new ArrayList<>();
+ //loop through the upper chest
+ for (int i = 0; i < 27; i++) {
+ Slot inventorySlot = inventorySlots.get(i);
+ if (inventorySlot == null) {
+ continue;
+ }
+
+ ItemStack stack = inventorySlot.getStack();
+ if (stack != null && stack.getItem() != null && stack.getItem() == Items.skull) {
+ //each item is a DungeonChest
+ DungeonChest dungeonChest = new DungeonChest();
+ dungeonChest.slot = i;
+
+ List<String> lore = ItemUtils.getLore(stack);
+ if ("§7Contents".equals(lore.get(0))) {
+ dungeonChest.name = stack.getDisplayName();
+ List<SkyblockItem> items = new ArrayList<>();
+ for (String s : lore) {
+ //check if this line is showing the cost of opening the Chest
+ if (s.endsWith(" Coins")) {
+ String coinString = StringUtils.cleanColour(s);
+ int whitespace = coinString.indexOf(' ');
+ if (whitespace != -1) {
+ String amountString = coinString.substring(0, whitespace).replace(",", "");
+ dungeonChest.costToOpen = Integer.parseInt(amountString);
+ continue;
+ }
+ } else if (s.equals("§aFREE")) {
+ dungeonChest.costToOpen = 0;
+ }
+
+ //check if the line can be converted to a SkyblockItem
+ SkyblockItem skyblockItem = SkyblockItem.createFromLoreEntry(s);
+ if (skyblockItem != null) {
+ items.add(skyblockItem);
+ }
+ }
+ dungeonChest.items = items;
+ if (dungeonChest.costToOpen != -1) {
+ dungeonChest.calculateProfitAndBuildLore();
+ chestProfits.add(dungeonChest);
+ }
+ }
+ }
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.dungeons.croesusSortByProfit) {
+ chestProfits.sort(Comparator.comparing(DungeonChest::getProfit).reversed());
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.dungeons.croesusHighlightHighestProfit && chestProfits.size() >= 1) {
+ List<DungeonChest> copiedList = new ArrayList<>(chestProfits);
+ copiedList.sort(Comparator.comparing(DungeonChest::getProfit).reversed());
+
+ copiedList.get(0).shouldHighlight = true;
+ }
+ }
+
+ public void render(GuiChest guiChest) {
+ int xSize = ((AccessorGuiContainer) guiChest).getXSize();
+ int guiLeft = ((AccessorGuiContainer) guiChest).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) guiChest).getGuiTop();
+ Minecraft.getMinecraft().getTextureManager().bindTexture(dungeonProfitResource);
+ GL11.glColor4f(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+ Utils.drawTexturedRect(guiLeft + xSize + 4, guiTop, 180, 101, 0, 180 / 256f, 0, 101 / 256f, GL11.GL_NEAREST);
+
+ for (int i = 0; i < chestProfits.size(); i++) {
+ DungeonChest chestProfit = chestProfits.get(i);
+ int x = guiLeft + xSize + 14;
+ int y = guiTop + 6 + (i * 10);
+ Utils.renderAlignedString(
+ chestProfit.name,
+ (chestProfit.profit > 0
+ ? EnumChatFormatting.GREEN.toString()
+ : EnumChatFormatting.RED) + Utils.shortNumberFormat(chestProfit.profit, 0),
+ x,
+ y,
+ 160
+ );
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+
+ int mouseX = Utils.getMouseX();
+ int mouseY = Utils.getMouseY();
+
+ if (Utils.isWithinRect(mouseX, mouseY, x, y, 160, 10))
+ Utils.drawHoveringText(
+ chestProfit.lore,
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+
+ }
+
+ /**
+ * Dataclass holding info on a single Dungeon Chest Preview
+ * <p>
+ * This includes:
+ * <ul>
+ * <li>The items, represented as a SkyblockItem</li>
+ * <li>The cost to open the chest</li>
+ * </ul>
+ *
+ * @see SkyblockItem
+ */
+ private static class DungeonChest {
+ private List<SkyblockItem> items = new ArrayList<>();
+ private List<String> lore;
+ private int costToOpen = -1;
+ private String name;
+ private int slot;
+ private boolean shouldHighlight;
+ private double profit;
+
+ public double getProfit() {
+ return profit;
+ }
+
+ public void calculateProfitAndBuildLore() {
+ profit = 0d;
+ lore = new ArrayList<>();
+ lore.add(name);
+ for (SkyblockItem item : items) {
+ double cost = item.calculateCost();
+ profit += cost;
+ lore.add(
+ EnumChatFormatting.AQUA + " - " + item.getDisplayName() + EnumChatFormatting.RESET + " " +
+ EnumChatFormatting.GREEN +
+ Utils.shortNumberFormat(cost, 0));
+ }
+ lore.add("");
+ profit -= costToOpen;
+ lore.add(
+ EnumChatFormatting.AQUA + "Cost to open: " + EnumChatFormatting.RED + Utils.shortNumberFormat(costToOpen, 0));
+ lore.add(
+ EnumChatFormatting.AQUA + "Total profit: " + (profit > 0 ? EnumChatFormatting.GREEN : EnumChatFormatting.RED) +
+ Utils.shortNumberFormat(profit, 0));
+ }
+ }
+
+ /**
+ * Dataclass holding info on a single skyblock item which is part of a DungeonChest
+ * <p>
+ * This includes:
+ * <ul>
+ * <li>The internal name of the item</li>
+ * <li>The amount</li>
+ * </ul>
+ *
+ * @see DungeonChest
+ */
+ private static class SkyblockItem {
+ private final String internalName;
+ private final int amount;
+
+ private SkyblockItem(String internalName, int amount) {
+ this.internalName = internalName;
+ this.amount = amount;
+ }
+
+ /**
+ * Try to create a SkyblockItem from the given lore line.
+ * <p>
+ * This involves checking for:
+ * <ul>
+ * <li>Enchanted books</li>
+ * <li>Dungeon essence</li>
+ * <li>Normal items that can appear in dungeon chests</li>
+ * </ul>
+ *
+ * @param line the line to be parsed
+ * @return a new SkyblockItem if possible, otherwise null
+ */
+ public static @Nullable SkyblockItem createFromLoreEntry(String line) {
+ Matcher essenceMatcher = essencePattern.matcher(line);
+ Matcher enchantedBookMatcher = enchantedBookPattern.matcher(line);
+
+ if (enchantedBookMatcher.matches()) {
+ String enchant = StringUtils.cleanColour(enchantedBookMatcher.group("enchantName"));
+
+ for (Map.Entry<String, JsonObject> entry : NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .entrySet()) {
+ String displayName = StringUtils.cleanColour(entry.getValue().get("displayname").getAsString());
+ if (displayName.equals("Enchanted Book")) {
+ JsonArray lore = entry.getValue().get("lore").getAsJsonArray();
+ String enchantName = StringUtils.cleanColour(lore.get(0).getAsString());
+ if (enchant.equals(enchantName)) {
+ return new SkyblockItem(entry.getKey(), 1);
+ }
+ }
+ }
+ } else if (essenceMatcher.matches()) {
+ String essenceType = essenceMatcher.group("essenceType");
+ String essenceAmount = essenceMatcher.group("essenceAmount");
+ if (essenceType == null || essenceAmount == null) {
+ return null;
+ }
+
+ String internalName = "ESSENCE_" + essenceType.toUpperCase(Locale.ROOT);
+ if (!NotEnoughUpdates.INSTANCE.manager.isValidInternalName(internalName)) {
+ return null;
+ }
+
+ //this can only be an integer if the regex matches
+ int amount = Integer.parseInt(essenceAmount);
+ return new SkyblockItem(internalName, amount);
+ } else {
+ String s = StringUtils.cleanColour(line.trim());
+ for (Map.Entry<String, JsonObject> entries : NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .entrySet()) {
+ String displayName = entries.getValue().get("displayname").getAsString();
+ String cleanDisplayName = StringUtils.cleanColour(displayName);
+ if (s.equals(cleanDisplayName)) {
+ return new SkyblockItem(entries.getKey(), 1);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Calculate the price of this item, factoring in the amount
+ *
+ * @return total price
+ */
+ public double calculateCost() {
+ double price = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarOrBin(internalName, true);
+ if (price != -1) {
+ return price * amount;
+ }
+ return 0d;
+ }
+
+ public String getDisplayName() {
+ JsonObject entry = NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery().withKnownInternalName(
+ internalName).resolveToItemListJson();
+ if (entry != null) {
+ String displayName = entry.get("displayname").getAsString();
+ String cleanedDisplayName = StringUtils.cleanColour(displayName);
+ if ("Enchanted Book".equals(cleanedDisplayName)) {
+ return entry.get("lore").getAsJsonArray().get(0).getAsString();
+ } else {
+ return entry.get("displayname").getAsString();
+ }
+ }
+ return "ERROR";
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnderNodes.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnderNodes.java
new file mode 100644
index 00000000..b0823a7d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnderNodes.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.SpecialColour;
+import io.github.moulberry.notenoughupdates.util.TitleUtil;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.ChatComponentText;
+
+public class EnderNodes {
+ // TODO Add ender node highliter
+ // TODO Add ender node counter ( maybe money estimation )
+
+ public static void dispalyEndermiteNotif() {
+ if (NotEnoughUpdates.INSTANCE.config.notifications.endermiteAlert && SBInfo.getInstance().getLocation() != null &&
+ SBInfo.getInstance().getLocation().equals("combat_3")) {
+ TitleUtil.getInstance().createTitle("Nested Endermite",
+ NotEnoughUpdates.INSTANCE.config.notifications.endermiteAlertTicks,
+ SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.notifications.endermiteAlertColor));
+ Minecraft.getMinecraft().thePlayer.playSound("random.orb", 1, 1);
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java
index 4cdb1557..5fa68fc2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java
@@ -177,6 +177,7 @@ public class FairySouls {
double factor = normalize(currentDistSq, 0.0, farSoulDistSq);
int rgb = interpolateColors(closeColor, farColor, Math.min(0.40, factor));
RenderUtils.renderBeaconBeamOrBoundingBox(currentSoul, rgb, 1.0f, event.partialTicks);
+ if (NotEnoughUpdates.INSTANCE.config.misc.fairySoulWaypointDistance) RenderUtils.renderWayPoint(currentSoul, event.partialTicks);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
index 88d2c6a0..dfdbba03 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
@@ -21,8 +21,10 @@ package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.collect.ImmutableList;
import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.ArrowPagesUtils;
import io.github.moulberry.notenoughupdates.recipes.NeuRecipe;
+import io.github.moulberry.notenoughupdates.recipes.RecipeHistory;
import io.github.moulberry.notenoughupdates.recipes.RecipeSlot;
import io.github.moulberry.notenoughupdates.recipes.RecipeType;
import io.github.moulberry.notenoughupdates.util.Utils;
@@ -259,6 +261,12 @@ public class GuiItemRecipe extends GuiScreen {
}
}
}
+
+ if (keyPressed == manager.keybindPreviousRecipe.getKeyCode()) {
+ NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getPrevious();
+ } else if (keyPressed == manager.keybindNextRecipe.getKeyCode()) {
+ NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getNext();
+ }
}
public void changeRecipe(int tabIndex, int recipeIndex) {
@@ -278,6 +286,13 @@ public class GuiItemRecipe extends GuiScreen {
super.mouseClicked(mouseX, mouseY, mouseButton);
NeuRecipe currentRecipe = getCurrentRecipe();
int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner();
+
+ if (mouseButton == 3) {
+ NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getPrevious();
+ } else if (mouseButton == 4) {
+ NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getNext();
+ }
+
if (ArrowPagesUtils.onPageSwitchMouse(
guiLeft,
guiTop,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
index 81918939..cb4cfa6c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
@@ -27,6 +27,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.AbiphoneWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.AuctionBINWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.AuctionSortModeWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
+import io.github.moulberry.notenoughupdates.miscfeatures.DungeonNpcProfitOverlay;
import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
import io.github.moulberry.notenoughupdates.miscgui.GuiCustomEnchant;
@@ -72,6 +73,7 @@ public abstract class MixinGuiContainer extends GuiScreen {
@Inject(method = "drawSlot", at = @At("RETURN"))
public void drawSlotRet(Slot slotIn, CallbackInfo ci) {
SlotLocking.getInstance().drawSlot(slotIn);
+ DungeonNpcProfitOverlay.onDrawSlot(slotIn);
}
@Inject(method = "drawSlot", at = @At("HEAD"), cancellable = true)
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java
index cf5635ec..9179c6ea 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java
@@ -130,7 +130,7 @@ public class Dungeons {
)
@ConfigEditorBoolean
@ConfigAccordionId(id = 1)
- public boolean shouldWarningDerpy = true;
+ public boolean shouldWarningDerpy = true;
@ConfigOption(
name = "Dungeon Win Overlay",
@@ -168,6 +168,7 @@ public class Dungeons {
@ConfigEditorAccordion(id = 2)
public boolean dungeonBlocksAccordion = false;
+
@ConfigOption(
name = "\u00A7cWarning",
desc = "You need Fast Render and Antialiasing off for these settings to work\n" +
@@ -281,4 +282,38 @@ public class Dungeons {
@ConfigAccordionId(id = 2)
public String dungBatColour = "0:255:12:255:0";
+ @ConfigOption(
+ name = "Croesus Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 4)
+ public boolean croesusAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Croesus Overlay",
+ desc = "Shows a profit overlay next to your inventory when viewing chest previews at the Croesus NPC"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean croesusProfitOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Sort by profit",
+ desc = "Lists the chest by profit (descending)"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean croesusSortByProfit = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Highlight highest profit",
+ desc = "Highlight the chest which has the most profit"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean croesusHighlightHighestProfit = true;
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
index afeec514..78bb0f95 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
@@ -83,6 +83,15 @@ public class Misc {
@Expose
@ConfigOption(
+ name = "Show Waypoint Distance",
+ desc = "Show the distance to each fairy soul waypoint"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean fairySoulWaypointDistance = false;
+
+ @Expose
+ @ConfigOption(
name = "Mark All As Found",
desc = "Mark all fairy souls in current location as found"
)
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java
index 85ad2093..3541860d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java
@@ -20,7 +20,10 @@
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
@@ -86,4 +89,43 @@ public class Notifications {
minStep = 25
)
public int boosterCookieWarningMins = 1440;
+
+ @Expose
+ @ConfigOption(
+ name = "Ender Nodes",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean enderNodeAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Nested Endermite Alert",
+ desc = "It will alert the user if a nested endermite gets spawned"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean endermiteAlert = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Nested Endermite Alert Color",
+ desc = "The color the alert will be shown"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 1)
+ public String endermiteAlertColor = "0:255:194:0:174";
+
+ @Expose
+ @ConfigOption(
+ name = "Nested Endermite Alert Display Time",
+ desc = "How long the display would stay for in ticks"
+ )
+ @ConfigEditorSlider(
+ minValue = 1,
+ maxValue = 200,
+ minStep = 20
+ )
+ @ConfigAccordionId(id = 1)
+ public int endermiteAlertTicks = 20;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
index 9ef9e474..e5c17a1a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
@@ -284,7 +284,8 @@ public class BasicPage extends GuiProfileViewerPage {
.get("avg_buy")
.getAsDouble()
);
- String networthIRLMoney = GuiProfileViewer.numberFormat.format(Math.round(((networthInCookies * 325) / 675) * 4.99));
+ String networthIRLMoney = GuiProfileViewer.numberFormat.format(Math.round(
+ ((networthInCookies * 325) / 675) * 4.99));
if (
mouseX > guiLeft + 8 &&
mouseX < guiLeft + 8 + fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth))
@@ -302,6 +303,17 @@ public class BasicPage extends GuiProfileViewerPage {
);
getInstance().tooltipToDisplay.add("");
+ if (NotEnoughUpdates.INSTANCE.config.profileViewer.useSoopyNetworth
+ && profile.getSoopyNetworthLeaderboardPosition() >= 0
+ && profile.isProfileMaxSoopyNetworth(profileId)) {
+
+ String lbPosStr =
+ EnumChatFormatting.DARK_GREEN + "#" + EnumChatFormatting.GOLD + GuiProfileViewer.numberFormat.format(
+ profile.getSoopyNetworthLeaderboardPosition());
+ getInstance().tooltipToDisplay.add(lbPosStr + EnumChatFormatting.GREEN + " on the networth leaderboard!");
+ getInstance().tooltipToDisplay.add("");
+ }
+
if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
getInstance().tooltipToDisplay.addAll(nwCategoryHover);
getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "This is calculated using the current");
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
index 6d59db27..cbebb6f4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
@@ -223,6 +223,7 @@ public class DungeonPage extends GuiProfileViewerPage {
getInstance().tooltipToDisplay =
Lists.newArrayList(
+ EnumChatFormatting.YELLOW + "Remaining XP: " + EnumChatFormatting.GRAY + String.format("%,d", floorLevelToXP),
String.format("# F5 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF5), runsF5),
String.format("# F6 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF6), runsF6),
String.format("# F7 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF7), runsF7),
@@ -370,6 +371,7 @@ public class DungeonPage extends GuiProfileViewerPage {
getInstance().tooltipToDisplay =
Lists.newArrayList(
+ EnumChatFormatting.YELLOW + "Remaining XP: " + EnumChatFormatting.GRAY + String.format("%,d", floorLevelToXP),
String.format("# M3 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM3), runsM3),
String.format("# M4 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM4), runsM4),
String.format("# M5 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM5), runsM5),
@@ -668,6 +670,8 @@ public class DungeonPage extends GuiProfileViewerPage {
activeClass = activeClassElement.getAsString();
}
+ ProfileViewer.Level classAverage = new ProfileViewer.Level();
+
for (int i = 0; i < dungSkillsName.length; i++) {
String skillName = dungSkillsName[i];
@@ -683,9 +687,19 @@ public class DungeonPage extends GuiProfileViewerPage {
50,
false
);
+
+ if (levelObj.level == 50) {
+ levelObj.level = 50 + (cataXp - 569809640) / 200000000;
+ }
+
levelObjClasses.put(skillName, levelObj);
}
+ classAverage.level = (float) (levelObjClasses.values().stream().mapToDouble(l -> l.level).sum() / 5);
+ if (classAverage.level >= 50) {
+ classAverage.maxed = true;
+ }
+
String colour = EnumChatFormatting.WHITE.toString();
if (skillName.toLowerCase().equals(activeClass)) {
colour = EnumChatFormatting.GREEN.toString();
@@ -694,8 +708,17 @@ public class DungeonPage extends GuiProfileViewerPage {
ProfileViewer.Level levelObj = levelObjClasses.get(skillName);
getInstance()
- .renderXpBar(colour + skillName, dungSkillsStack[i], x, y + 20 + 29 * i, sectionWidth, levelObj, mouseX, mouseY);
+ .renderXpBar(colour + skillName, dungSkillsStack[i], x, y + 20 + 24 * i, sectionWidth, levelObj, mouseX, mouseY);
}
+
+ getInstance().renderXpBar(
+ EnumChatFormatting.WHITE + "Class Average",
+ new ItemStack(Items.nether_star),
+ x,
+ y + 20 + 24 * 5,
+ sectionWidth,
+ classAverage,
+ mouseX, mouseY);
}
drawSideButtons();
@@ -707,7 +730,7 @@ public class DungeonPage extends GuiProfileViewerPage {
int guiLeft = GuiProfileViewer.getGuiLeft();
int guiTop = GuiProfileViewer.getGuiTop();
- if (mouseX >= guiLeft + 50 && mouseX <= guiLeft + 70 && mouseY >= guiTop + 54 && mouseY <= guiTop + 64) {
+ if (mouseX >= guiLeft + 45 && mouseX <= guiLeft + 65 && mouseY >= guiTop + 54 && mouseY <= guiTop + 64) {
dungeonLevelTextField.mouseClicked(mouseX, mouseY, mouseButton);
} else {
dungeonLevelTextField.otherComponentClick();
@@ -829,7 +852,7 @@ public class DungeonPage extends GuiProfileViewerPage {
if (level < Math.floor(levelObjCata.level)) {
continue;
}
- remaining += levelingArray.get(level).getAsFloat();
+ remaining += levelingArray.get(level).getAsFloat();
}
if (remaining < 0) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
index f327dae5..37605595 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -1039,15 +1039,27 @@ public class GuiProfileViewer extends GuiScreen {
numberFormat.format(levelObj.totalXp) + EnumChatFormatting.DARK_GRAY + " (" +
DECIMAL_FORMAT.format(getPercentage(skillName.toLowerCase(), levelObj)) + "% to 50)";
}
+ // Adds overflow level to each level object that is maxed, avoids hotm level as there is no overflow xp for it
if (levelObj.maxed) {
- levelStr = EnumChatFormatting.GOLD + "MAXED!";
+ levelStr = levelObj.maxLevel != 7 ?
+ EnumChatFormatting.GOLD + "MAXED!" + EnumChatFormatting.GRAY + " (Overflow level: " + String.format("%.2f", levelObj.level) + ")" :
+ EnumChatFormatting.GOLD + "MAXED!";
} else {
- int maxXp = (int) levelObj.maxXpForLevel;
- levelStr =
- EnumChatFormatting.DARK_PURPLE +
- StringUtils.shortNumberFormat(Math.round((level % 1) * maxXp)) +
- "/" +
- StringUtils.shortNumberFormat(maxXp);
+ if (skillName.contains("Class Average")) {
+ levelStr = "Progress: " + EnumChatFormatting.DARK_PURPLE + String.format("%.1f", (level % 1 * 100)) + "%";
+ totalXpStr = "Exact Class Average: " + EnumChatFormatting.WHITE + String.format("%.2f", levelObj.level);
+ } else {
+ int maxXp = (int) levelObj.maxXpForLevel;
+ levelStr =
+ EnumChatFormatting.DARK_PURPLE +
+ StringUtils.shortNumberFormat(Math.round((level % 1) * maxXp)) +
+ "/" +
+ StringUtils.shortNumberFormat(maxXp) +
+ // Since catacombs isn't considered 'maxed' at level 50 (since the cap is '99'), we can add
+ // a conditional here to add the overflow level rather than above
+ ((skillName.contains("Catacombs") && levelObj.level >= 50) ?
+ EnumChatFormatting.GRAY + " (Overflow level: " + String.format("%.2f", levelObj.level) + ")" : "");
+ }
}
if (totalXpStr != null) {
tooltipToDisplay = Utils.createList(levelStr, totalXpStr);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
index b32d3648..347ee660 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
@@ -654,6 +654,7 @@ public class ProfileViewer {
private final AtomicBoolean updatingSoopyNetworth = new AtomicBoolean(false);
private final AtomicBoolean updatingBingoInfo = new AtomicBoolean(false);
private final Pattern COLL_TIER_PATTERN = Pattern.compile("_(-?\\d+)");
+ private long soopyNetworthLeaderboardPosition = -1; //-1 = default, -2 = loading, -3 = error
private String latestProfile = null;
private JsonArray skyblockProfiles = null;
private JsonObject guildInformation = null;
@@ -748,7 +749,11 @@ public class ProfileViewer {
}
//Sort keys based on category value
- keys = categoryWorth.keySet().stream().sorted(Comparator.comparingLong(k->getCategory((String) k)).reversed()).toArray(String[]::new);
+ keys = categoryWorth
+ .keySet()
+ .stream()
+ .sorted(Comparator.comparingLong(k -> getCategory((String) k)).reversed())
+ .toArray(String[]::new);
}
private SoopyNetworthData setLoading() {
@@ -771,6 +776,32 @@ public class ProfileViewer {
}
/**
+ * -1 = default, -2 = loading, -3 = error
+ * >= 0 = actual position
+ */
+ public long getSoopyNetworthLeaderboardPosition() {
+ if ("d0e05de76067454dbeaec6d19d886191".equals(uuid)) return 1;
+ return soopyNetworthLeaderboardPosition;
+ }
+
+ public boolean isProfileMaxSoopyNetworth(String profileName) {
+ String highestProfileName = "";
+ long largestProfileNetworth = 0;
+
+ for (String pName : soopyNetworth.keySet()) {
+ if (soopyNetworth.get(pName) == null) continue;
+
+ long pNet = soopyNetworth.get(pName).totalWorth;
+ if (pNet < largestProfileNetworth) continue;
+
+ highestProfileName = pName;
+ largestProfileNetworth = pNet;
+ }
+
+ return highestProfileName.equals(profileName);
+ }
+
+ /**
* Returns SoopyNetworthData with total = -1 if error
* Returns null if still loading
*/
@@ -782,10 +813,33 @@ public class ProfileViewer {
}
JsonArray playerInfo = getSkyblockProfiles(() -> {});
- if (playerInfo == null) return null; //Not sure how to support the callback in these cases
- if (updatingSoopyNetworth.get()) return new SoopyNetworthData(null).setLoading(); //It shouldent really matter tho as these should never occur in /peek
+ if (playerInfo == null)
+ return null; //Not sure how to support the callback in these cases
+ if (updatingSoopyNetworth.get())
+ return new SoopyNetworthData(null).setLoading(); //It shouldent really matter tho as these should never occur in /peek
updatingSoopyNetworth.set(true);
+ soopyNetworthLeaderboardPosition = -2; //loading
+ manager.apiUtils
+ .request()
+ .url("https://soopy.dev/api/v2/leaderboard/networth/user/" + this.uuid)
+ .requestJson()
+ .handle((jsonObject, throwable) -> {
+ if (throwable != null) throwable.printStackTrace();
+ if (throwable != null || !jsonObject.has("success") || !jsonObject.get("success").getAsBoolean()
+ || !jsonObject.has("data")
+ || !jsonObject.get("data").getAsJsonObject().has("data")
+ || !jsonObject.get("data").getAsJsonObject().get("data").getAsJsonObject().has("position")) {
+ //Something went wrong
+ //Set profile lb position to -3 to indicate that
+ soopyNetworthLeaderboardPosition = -3; //error
+ return null;
+ }
+ soopyNetworthLeaderboardPosition = jsonObject.get("data").getAsJsonObject().get("data").getAsJsonObject().get(
+ "position").getAsLong();
+ return null;
+ });
+
manager.apiUtils
.request()
.url("https://soopy.dev/api/v2/player_networth/" + this.uuid)
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeHistory.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeHistory.java
new file mode 100644
index 00000000..c4a0f6e4
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeHistory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.recipes;
+
+import net.minecraft.client.gui.GuiScreen;
+
+import java.util.ArrayList;
+
+public class RecipeHistory {
+
+ private static final int MAX_HISTORY_SIZE = 50;
+
+ private static ArrayList<GuiScreen> history = new ArrayList<>();
+ private static int historyIndex = 0;
+
+ public static void add(GuiScreen recipe) {
+ if (history.size() == MAX_HISTORY_SIZE) {
+ history.remove(0);
+ historyIndex--;
+ } else {
+ if (history.size() == 0) {
+ history.add(recipe);
+ } else {
+ if (historyIndex < history.size() - 1) {
+ history = new ArrayList<>(history.subList(0, historyIndex + 1));
+ }
+ history.add(recipe);
+ historyIndex++;
+ }
+ }
+ }
+
+ public static GuiScreen getPrevious() {
+ if (history.size() > 0) {
+ if (historyIndex - 1 < 0) {
+ return null;
+ }
+ historyIndex--;
+ return history.get(historyIndex);
+ }
+ return null;
+ }
+
+ public static GuiScreen getNext() {
+ if (historyIndex < history.size() - 1) {
+ historyIndex++;
+ return history.get(historyIndex);
+ }
+ return null;
+ }
+
+ public static void clear() {
+ history = new ArrayList<>();
+ historyIndex = 0;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/TitleUtil.java b/src/main/java/io/github/moulberry/notenoughupdates/util/TitleUtil.java
new file mode 100644
index 00000000..59db7cac
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/TitleUtil.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraftforge.client.event.RenderGameOverlayEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class TitleUtil {
+
+ private static final TitleUtil INSTANCE = new TitleUtil();
+
+ public static TitleUtil getInstance() {
+ return INSTANCE;
+ }
+
+ private String title = null;
+ private long titleLifetime = 0;
+ private int color = 0xFF0000;
+
+ public void createTitle(String title, int ticks, int color) {
+ this.title = title;
+ this.titleLifetime = System.nanoTime() + (ticks * 50000000L);
+ this.color = color;
+ }
+ /**
+ * Adapted from SkyblockAddons under MIT license
+ * @link https://github.com/BiscuitDevelopment/SkyblockAddons/blob/master/LICENSE
+ * @author BiscuitDevelopment
+ */
+ private void renderTitles (ScaledResolution scaledResolution) {
+ Minecraft mc = Minecraft.getMinecraft();
+ if (mc.theWorld == null || mc.thePlayer == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return;
+
+ int scaledWidth = scaledResolution.getScaledWidth();
+ int scaledHeight = scaledResolution.getScaledHeight();
+
+ if (this.title != null) {
+ int stringWidth = mc.fontRendererObj.getStringWidth(this.title);
+ float scale = 4f; // Scale is normally 4, but if it's larger than the screen, scale it down...
+ if (stringWidth * scale > scaledWidth * 0.9f) {
+ scale = scaledWidth * 0.9f / (float) stringWidth;
+ }
+ GlStateManager.pushMatrix();
+ GlStateManager.translate((float)(scaledWidth / 2),(float)(scaledHeight / 2), 0.0f);
+ GlStateManager.enableBlend();
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+ GlStateManager.pushMatrix();
+ GlStateManager.scale(scale, scale, scale);
+ mc.fontRendererObj.drawString(
+ this.title,
+ ((float)-mc.fontRendererObj.getStringWidth(this.title) / 2),
+ -20.0f,
+ color,
+ true
+ );
+ GlStateManager.popMatrix();
+ GlStateManager.popMatrix();
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
+ public void onRenderHUD(RenderGameOverlayEvent event) {
+ if (event.type != RenderGameOverlayEvent.ElementType.HOTBAR) return;
+ if (System.nanoTime() >= titleLifetime) {
+ titleLifetime = 0;
+ title = null;
+ }
+ renderTitles(event.resolution);
+ }
+}