diff options
author | Roman / Linnea Gräf <roman.graef@gmail.com> | 2022-08-26 19:02:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-26 19:02:27 +0200 |
commit | de15a18edab8d6e6b9e56090cbf3b82134e5c0a4 (patch) | |
tree | 15681f641c494ffe32b76f056952332ee7e1922b | |
parent | edbb004ce82d6595b2f4fcc5a7090c359f371003 (diff) | |
parent | 5c53801209c25c9bc8ea0263a0aa579b1c2980a9 (diff) | |
download | NotEnoughUpdates-de15a18edab8d6e6b9e56090cbf3b82134e5c0a4.tar.gz NotEnoughUpdates-de15a18edab8d6e6b9e56090cbf3b82134e5c0a4.tar.bz2 NotEnoughUpdates-de15a18edab8d6e6b9e56090cbf3b82134e5c0a4.zip |
Merge branch 'master' into warnerwarner
35 files changed, 1136 insertions, 208 deletions
diff --git a/Update Notes/2.1.md b/Update Notes/2.1.md index 774ce075..90ebbf87 100644 --- a/Update Notes/2.1.md +++ b/Update Notes/2.1.md @@ -16,7 +16,7 @@ - Added wishing compass solver that shows target coordinates, structure, and integrates with Skytils waypoints - CraftyOldMiner - Improved metal detector logic to solve using a single position in most cases using known locations based on Keeper coordinates - CraftyOldMiner - Added support for official Hypixel wiki, can be toggled in /neu misc - DeDiamondPro -- Added a calculator (/neucalc help), that also works in the auction house / bazaar - nea89o +- Added a calculator (/neucalc help), that also works in the auction house / bazaar - nea89 - Added and fixed various things in the profile viewer: - [Added hotm tab](https://media.discordapp.net/attachments/659613194066722833/991115131507441724/unknown.png) - nopo - Big thanks to kwev1n for some math and jani for the texture @@ -27,7 +27,7 @@ - Added equipment - nopo - Added blaze slayer level and kills - nopo - Added social level - nopo - - Added various new collections and minions - nopo + - Added various new collections and minions - nopo & CrypticPlasma & hannibal2 - Added mastermode catacombs xp to level calculator - nopo - Added profile viewer settings to /neu - nopo - Added an unknown icon if neu doesn't recognize your profile type - nopo @@ -35,7 +35,8 @@ - Fixed minion tiers crafted by coop members not showing up in /pv - Lulonaut - Fixed crash in /pv when the player had a pet that is not saved in the repo - Lulonaut - Added senither and lily weight - CrypticPlasma - - Added info about the Quiver when hovering over the arrow in the inventory tab of /pv - Lulonaut + - Added the Quiver Info when hovering in inventory tab over Arrows display - Lulonaut + - Added the Magical Power Info when hovering in inventory tab over Accessory Bag display - Lulonaut ### **Minor Changes:** @@ -102,10 +103,12 @@ - Added Fishing Timer over bobber - nea89 - Added [Auction Profit Viewer Overlay](https://cdn.discordapp.com/attachments/848901833119629332/993191851400101918/176946124-28ddf336-1ec7-460b-b22a-5fe2733b46a3.png) - efefury - Added Trophy Reward Overlay - hannibal2 -- Add Auto-Updater (linux and scu only) - nea89 +- Add Auto-Updater (linux only) - nea89 - Added power stone feature - hannibal2 - Added abiphone warning - hannibal2 -- Added blur limit at 100 - nopo +- Added blur limit to map at 100 - nopo +- Added bazaar sacks profit feature - hannibal2 +- Added an option to disable etherwarp overlay when TP is denied - hannibal2 ### **Bug Fixes:** @@ -132,6 +135,7 @@ - Fixed some vanilla Minecraft keybinds not working in NEU GUIs - nopo - Fixed crash with spamming remove enchant in /neuec - nopo - Fixed missing enchants not working with shiny items - nopo +- Fixed golden dragon not working in pet overlay - CrypticPlasma ### **Other:** diff --git a/build.gradle.kts b/build.gradle.kts index bffe9f6d..409a8d51 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,6 +22,8 @@ import net.fabricmc.loom.task.RemapJarTask import java.io.ByteArrayOutputStream import java.nio.file.FileSystems import java.nio.file.Files +import java.nio.charset.StandardCharsets +import java.util.* plugins { idea @@ -173,7 +175,22 @@ tasks.shadowJar { tasks.assemble.get().dependsOn(remapJar) +val generateBuildFlags by tasks.creating { + outputs.upToDateWhen { false } + val t = layout.buildDirectory.file("buildflags.properties") + outputs.file(t) + val props = project.properties.filter { (name, value) -> name.startsWith("neu.buildflags.") } + doLast { + val p = Properties() + p.putAll(props) + t.get().asFile.writer(StandardCharsets.UTF_8).use { + p.store(it, "Store build time configuration for NEU") + } + } +} + tasks.processResources { + from(generateBuildFlags) filesMatching("mcmod.info") { expand( "version" to project.version, "mcversion" to "1.8.9" diff --git a/gradle.properties b/gradle.properties index 87c0a7c6..f596b2d7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,6 @@ org.gradle.jvmargs=-Xmx2G loom.platform=forge +# NEU Buildflags. Please keep these flags in a commented out form while checked into version control. +# See BuildFlags.java for usages of these values. +# Build with Pronouns in PV by default +# neu.buildflags.pronouns=true diff --git a/src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java b/src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java new file mode 100644 index 00000000..d997d980 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java @@ -0,0 +1,72 @@ +/* + * 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; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * For storage of compile-time configuration flags + */ +public class BuildFlags { + + private static final Properties properties = new Properties(); + + static { + try { + properties.load(BuildFlags.class.getResourceAsStream("/buildflags.properties")); + } catch (IOException | NullPointerException e) { + System.out.println("Failed to load build properties: " + e); + } + } + + private static boolean getBuildFlag(String flag) { + return Boolean.parseBoolean(properties.getProperty("neu.buildflags." + flag)); + } + + public static Map<String, Boolean> getAllFlags() { + return Holder.ALL_FLAGS; + } + + public static final boolean ENABLE_PRONOUNS_IN_PV_BY_DEFAULT = getBuildFlag("pronouns"); + + private static class Holder { + static Map<String, Boolean> ALL_FLAGS = new HashMap<>(); + + static { + for (Field declaredField : BuildFlags.class.getDeclaredFields()) { + if (Boolean.TYPE.equals(declaredField.getType()) + && (declaredField.getModifiers() & Modifier.STATIC) != 0) { + try { + declaredField.setAccessible(true); + ALL_FLAGS.put(declaredField.getName(), (Boolean) declaredField.get(null)); + } catch (IllegalAccessException | ClassCastException | SecurityException e) { + System.err.println("Failed to access BuildFlag: " + e); + } + } + } + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index d22b93f5..dd4c01af 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -112,8 +112,8 @@ import java.util.Set; public class NotEnoughUpdates { public static final String MODID = "notenoughupdates"; public static final String VERSION = "2.1.0-REL"; - public static final int VERSION_ID = 20000; - public static final int PRE_VERSION_ID = 1; + public static final int VERSION_ID = 20100; + public static final int PRE_VERSION_ID = 0; public static final int HOTFIX_VERSION_ID = 0; /** * Registers the biomes for the crystal hollows here so optifine knows they exists 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 3fc34d10..c3999fb6 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java @@ -59,6 +59,8 @@ import java.util.TreeMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class APIManager { private final NEUManager manager; @@ -702,6 +704,16 @@ public class APIManager { ); } + private static final Pattern BAZAAR_ENCHANTMENT_PATTERN = Pattern.compile("ENCHANTMENT_(\\D*)_(\\d+)"); + + public String transformHypixelBazaarToNEUItemId(String hypixelId) { + Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(hypixelId); + if (matcher.matches()) { + return matcher.group(1) + ";" + matcher.group(2); + } + return hypixelId.replace(":", "-"); + } + public void updateBazaar() { manager.hypixelApi.getHypixelApiAsync( NotEnoughUpdates.INSTANCE.config.apiData.apiKey, @@ -738,7 +750,7 @@ public class APIManager { } } - bazaarJson.add(entry.getKey().replace(":", "-"), productInfo); + bazaarJson.add(transformHypixelBazaarToNEUItemId(entry.getKey()), productInfo); } } GuiPriceGraph.addToCache(bazaarJson, true); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java index f0ef1ec6..7b4542d0 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java @@ -133,6 +133,8 @@ public class CustomAH extends Gui { public int guiLeft = -1; public int guiTop = -1; + private String lastSearch = ""; + private final Category CATEGORY_SWORD = new Category("sword", "Swords", "diamond_sword"); private final Category CATEGORY_ARMOR = new Category("armor", "Armor", "diamond_chestplate"); private final Category CATEGORY_BOWS = new Category("bow", "Bows", "bow"); @@ -275,7 +277,11 @@ public class CustomAH extends Gui { } public void setSearch(String search) { - searchField.setText(search); + if (search == null) { + searchField.setText(lastSearch); + } else { + searchField.setText(search); + } updateSearch(); } @@ -1487,8 +1493,15 @@ public class CustomAH extends Gui { auctionIdsNew.add(entry.getKey()); } } + if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.saveLastSearch) { + lastSearch = ""; + } } else { String query = searchField.getText(); + + if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.saveLastSearch) { + lastSearch = query; + } Set<String> dontMatch = new HashSet<>(); HashSet<String> allMatch = new HashSet<>(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java index 917185ab..fcb2aaf9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java @@ -42,6 +42,7 @@ import io.github.moulberry.notenoughupdates.commands.misc.CalculatorCommand; import io.github.moulberry.notenoughupdates.commands.misc.CalendarCommand; import io.github.moulberry.notenoughupdates.commands.misc.CosmeticsCommand; import io.github.moulberry.notenoughupdates.commands.misc.CustomizeCommand; +import io.github.moulberry.notenoughupdates.commands.misc.PronounsCommand; import io.github.moulberry.notenoughupdates.commands.misc.UpdateCommand; import io.github.moulberry.notenoughupdates.commands.profile.CataCommand; import io.github.moulberry.notenoughupdates.commands.profile.PeekCommand; @@ -97,6 +98,7 @@ public class Commands { ClientCommandHandler.instance.registerCommand(new CalculatorCommand()); ClientCommandHandler.instance.registerCommand(new CalendarCommand()); ClientCommandHandler.instance.registerCommand(new UpdateCommand(NotEnoughUpdates.INSTANCE)); + ClientCommandHandler.instance.registerCommand(new PronounsCommand()); // Fairy Soul Commands ClientCommandHandler.instance.registerCommand(new FairySouls.FairySoulsCommand()); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java index 7cca9d3b..fdf59bb0 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java @@ -19,6 +19,7 @@ package io.github.moulberry.notenoughupdates.commands.dev; +import io.github.moulberry.notenoughupdates.BuildFlags; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.commands.ClientCommandBase; import io.github.moulberry.notenoughupdates.core.config.GuiPositionEditor; @@ -27,6 +28,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.Custom import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.SpecialBlockZone; import io.github.moulberry.notenoughupdates.miscgui.GuiPriceGraph; +import io.github.moulberry.notenoughupdates.util.PronounDB; import io.github.moulberry.notenoughupdates.util.SBInfo; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; @@ -40,6 +42,7 @@ import net.minecraftforge.common.MinecraftForge; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; public class DevTestCommand extends ClientCommandBase { @@ -118,6 +121,14 @@ public class DevTestCommand extends ClientCommandBase { " with the mode " + gamemode)); } + if (args.length >= 1 && args[0].equalsIgnoreCase("buildflags")) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + "BuildFlags: \n" + + BuildFlags.getAllFlags().entrySet().stream() + .map(it -> " + " + it.getKey() + " - " + it.getValue()) + .collect(Collectors.joining("\n")))); + return; + } if (args.length >= 1 && args[0].equalsIgnoreCase("pricetest")) { if (args.length == 1) { NotEnoughUpdates.INSTANCE.manager.auctionManager.updateBazaar(); @@ -163,6 +174,10 @@ public class DevTestCommand extends ClientCommandBase { "I would never search")); return; } + if (args.length == 1 && args[0].equalsIgnoreCase("bluehair")) { + PronounDB.test(); + return; + } if (args.length == 2 && args[0].equalsIgnoreCase("openGui")) { try { NotEnoughUpdates.INSTANCE.openGui = (GuiScreen) Class.forName(args[1]).newInstance(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java index 1cd6bcce..bd8abf1d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java @@ -50,8 +50,13 @@ public class AhCommand extends ClientCommandBase { NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.clearSearch(); NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.updateSearch(); - if (args.length > 0) + if (args.length > 0) { NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.setSearch(StringUtils.join(args, " ")); + } else { + if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.saveLastSearch) { + NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.setSearch(null); + } + } } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java new file mode 100644 index 00000000..6d0ee88d --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java @@ -0,0 +1,94 @@ +/* + * 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.commands.misc; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.commands.ClientCommandBase; +import io.github.moulberry.notenoughupdates.util.MinecraftExecutor; +import io.github.moulberry.notenoughupdates.util.PronounDB; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.GuiNewChat; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; + +import java.util.Optional; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class PronounsCommand extends ClientCommandBase { + public PronounsCommand() { + super("neupronouns"); + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/neupronouns <username> [platform]"; + } + + @Override + public void processCommand(ICommandSender sender, String[] args) throws CommandException { + switch (args.length) { + case 1: + fetchPronouns("minecraft", args[0]); + break; + case 2: + fetchPronouns(args[1], args[0]); + break; + default: + sender.addChatMessage(new ChatComponentText("§4" + getCommandUsage(sender))); + } + } + + private void fetchPronouns(String platform, String user) { + GuiNewChat nc = Minecraft.getMinecraft().ingameGUI.getChatGUI(); + int id = new Random().nextInt(); + nc.printChatMessageWithOptionalDeletion(new ChatComponentText("§e[NEU] Fetching Pronouns..."), id); + + CompletableFuture<Optional<PronounDB.PronounChoice>> pronouns; + if ("minecraft".equals(platform)) { + CompletableFuture<UUID> c = new CompletableFuture<>(); + NotEnoughUpdates.profileViewer.getPlayerUUID(user, uuidString -> { + if (uuidString == null) { + c.completeExceptionally(new NullPointerException()); + } else { + c.complete(Utils.parseDashlessUUID(uuidString)); + } + }); + pronouns = c.thenApplyAsync(PronounDB::getPronounsFor); + } else { + pronouns = CompletableFuture.supplyAsync(() -> PronounDB.getPronounsFor(platform, user)); + } + pronouns.handleAsync((pronounChoice, throwable) -> { + if (throwable != null || !pronounChoice.isPresent()) { + nc.printChatMessageWithOptionalDeletion(new ChatComponentText("§e[NEU] §4Failed to fetch pronouns."), id); + return null; + } + PronounDB.PronounChoice betterPronounChoice = pronounChoice.get(); + nc.printChatMessageWithOptionalDeletion(new ChatComponentText("§e[NEU] Pronouns for §b" + user + " §eon §b" + platform + "§e:"), id); + betterPronounChoice.render().forEach(it -> nc.printChatMessage(new ChatComponentText("§e[NEU] §a" + it))); + return null; + }, MinecraftExecutor.INSTANCE); + + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java index d52f9ba1..ecb4cd8b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java @@ -23,6 +23,9 @@ import com.google.common.collect.Sets; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.Set; public class StringUtils { @@ -63,4 +66,12 @@ public class StringUtils { str = str.replace(",", ""); return Integer.parseInt(str); } + + public static String urlEncode(String something) { + try { + return URLEncoder.encode(something, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // UTF 8 should always be present + } + } } 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 31480016..3aeee590 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java @@ -23,6 +23,7 @@ import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; @@ -140,6 +141,7 @@ public class RenderListener { private String correctingItem; private boolean typing; private HashMap<String, String> cachedDefinitions; + private boolean inDungeonPage = false; public RenderListener(NotEnoughUpdates neu) { this.neu = neu; @@ -528,6 +530,12 @@ public class RenderListener { x -= 25; } } + if (inDungeonPage) { + if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 && + y < guiTop + 100) { + x += 185; + } + } GlStateManager.color(1, 1, 1, 1f); @@ -650,6 +658,13 @@ public class RenderListener { } } + if (inDungeonPage) { + if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 && + y < guiTop + 100) { + x += 185; + } + } + if (x - guiLeft >= 85 && x - guiLeft <= 115 && y - guiTop >= 4 && y - guiTop <= 25) { disableCraftingText = true; } @@ -697,7 +712,6 @@ public class RenderListener { private void renderDungeonChestOverlay(GuiScreen gui) { if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 3) return; - if (gui instanceof GuiChest && NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc != 2) { try { int xSize = ((AccessorGuiContainer) gui).getXSize(); @@ -709,8 +723,9 @@ public class RenderListener { IInventory lower = cc.getLowerChestInventory(); ItemStack rewardChest = lower.getStackInSlot(31); - if (rewardChest != null && rewardChest.getDisplayName().endsWith( - EnumChatFormatting.GREEN + "Open Reward Chest")) { + this.inDungeonPage = rewardChest != null && rewardChest.getDisplayName().endsWith( + EnumChatFormatting.GREEN + "Open Reward Chest"); + if (inDungeonPage) { int chestCost = 0; try { String line6 = Utils.cleanColour(neu.manager.getLoreFromNBT(rewardChest.getTagCompound())[6]); @@ -906,6 +921,21 @@ public class RenderListener { 160 ); } + JsonObject mayorJson = SBInfo.getInstance().getMayorJson(); + JsonElement mayor = mayorJson.get("mayor"); + if (mayorJson.has("mayor") && mayor != null && mayor.getAsJsonObject().has("name") && + mayor.getAsJsonObject().get("name").getAsString().equals("Derpy") + && NotEnoughUpdates.INSTANCE.config.dungeons.shouldWarningDerpy) { + Utils.drawStringScaled( + EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "shMayor Derpy active!", + Minecraft.getMinecraft().fontRendererObj, + guiLeft + xSize + 4 + 10, + guiTop + 85, + true, + 0, + 1.3f + ); + } } } catch (Exception e) { e.printStackTrace(); @@ -1070,6 +1100,12 @@ public class RenderListener { x -= 25; } } + if (inDungeonPage) { + if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 && + y < guiTop + 100) { + x += 185; + } + } if (mouseX >= x && mouseX <= x + 18 && mouseY >= y && mouseY <= y + 18) { if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java index 9cc872b7..541a76e8 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java @@ -390,7 +390,7 @@ public class Navigation { && NotEnoughUpdates.INSTANCE.config.misc.untrackCloseWaypoints && island.equals(SBInfo.getInstance().mode)) { EntityPlayerSP thePlayer = Minecraft.getMinecraft().thePlayer; - if (thePlayer.getDistanceSq(position) < 16) + if (thePlayer != null && thePlayer.getDistanceSq(position) < 16) untrackWaypoint(); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java new file mode 100644 index 00000000..6036d93b --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java @@ -0,0 +1,43 @@ +/* + * 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 net.minecraft.client.Minecraft; +import net.minecraft.network.play.client.C01PacketChatMessage; +import net.minecraft.util.ChatComponentText; + +public class NewApiKeyHelper { + private static final NewApiKeyHelper INSTANCE = new NewApiKeyHelper(); + + public static NewApiKeyHelper getInstance() { + return INSTANCE; + } + + public void hookPacketChatMessage(C01PacketChatMessage packet) { + String message = packet.getMessage().toLowerCase(); + if (message.equals("/api new")) return; + + if (message.replace(" ", "").startsWith("/apinew")) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + "§e[NotEnoughUpdates] §7You just executed §c" + packet.getMessage() + + "§7. Did you mean to execute §e/api new§7?")); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java index 7869225d..e7ada16f 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java @@ -179,8 +179,8 @@ public class AutoUpdater { public void displayUpdateMessageIfOutOfDate() { File repo = neu.manager.repoLocation; - if (repo.exists()) { - File updateJson = new File(repo, "update.json"); + File updateJson = new File(repo, "update.json"); + if (updateJson.exists()) { try { JsonObject o = neu.manager.getJsonFromFile(updateJson); 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 69343e99..e06c271f 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java @@ -89,13 +89,13 @@ public class GuiItemRecipe extends GuiScreen { if (!tabs.contains(recipe.getType())) tabs.add(recipe.getType()); } + changeRecipe(0, 0); } @Override public void initGui() { this.guiLeft = (width - this.xSize) / 2; this.guiTop = (height - this.ySize) / 2; - changeRecipe(0, 0); } public NeuRecipe getCurrentRecipe() { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java index abc8c2a2..0b33609d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java @@ -25,12 +25,14 @@ import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers; import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper; import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns; import io.github.moulberry.notenoughupdates.miscfeatures.MiningStuff; +import io.github.moulberry.notenoughupdates.miscfeatures.NewApiKeyHelper; import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager; import io.github.moulberry.notenoughupdates.util.SBInfo; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.Packet; +import net.minecraft.network.play.client.C01PacketChatMessage; import net.minecraft.network.play.client.C0EPacketClickWindow; import net.minecraft.network.play.server.S23PacketBlockChange; import net.minecraft.network.play.server.S2DPacketOpenWindow; @@ -124,11 +126,14 @@ public class MixinNetHandlerPlayClient { ItemCooldowns.processBlockChangePacket(packetIn); } - @Inject(method = "addToSendQueue", at = @At("HEAD")) + @Inject(method = "addToSendQueue", at = @At("HEAD"), cancellable = true) public void addToSendQueue(Packet packet, CallbackInfo ci) { if (packet instanceof C0EPacketClickWindow) { StorageManager.getInstance().clientSendWindowClick((C0EPacketClickWindow) packet); } + if (packet instanceof C01PacketChatMessage) { + NewApiKeyHelper.getInstance().hookPacketChatMessage((C01PacketChatMessage) packet); + } } @Inject(method = "handlePlayerListHeaderFooter", at = @At("HEAD")) 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 fead6780..e080db7d 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 @@ -114,6 +114,15 @@ public class Dungeons { @ConfigAccordionId(id = 1) public boolean useKismetOnDungeonProfit = true; + @Expose + @ConfigOption( + name = "Warning if Derpy active", + desc = "Shows a warning if the mayor Derpy is active" + ) + @ConfigEditorBoolean + @ConfigAccordionId(id = 1) + public boolean shouldWarningDerpy = true; + @ConfigOption( name = "Dungeon Win Overlay", desc = "" diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java index 44f3454a..6c55fd09 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java @@ -24,7 +24,8 @@ import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditor import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption; -public class NeuAuctionHouse { +public class +NeuAuctionHouse { @Expose @ConfigOption( name = "Enable NeuAH", @@ -61,4 +62,12 @@ public class NeuAuctionHouse { ) @ConfigEditorBoolean public boolean priceFiltering = false; + + @Expose + @ConfigOption( + name = "Save Last Search", + desc = "Saving the last query when closing the neuah" + ) + @ConfigEditorBoolean + public boolean saveLastSearch = true; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java index ee1abf46..673e1015 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java @@ -20,7 +20,12 @@ package io.github.moulberry.notenoughupdates.options.seperateSections; import com.google.gson.annotations.Expose; -import io.github.moulberry.notenoughupdates.core.config.annotations.*; +import io.github.moulberry.notenoughupdates.BuildFlags; +import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean; +import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton; +import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList; +import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR; +import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption; import java.util.ArrayList; import java.util.Arrays; @@ -81,4 +86,12 @@ public class ProfileViewer { ) @ConfigEditorBoolean public boolean alwaysShowBingoTab = false; + + @Expose + @ConfigOption( + name = "Show Pronouns in /pv", + desc = "Shows the pronouns of a player in /pv. Data sourced from pronoundb.org" + ) + @ConfigEditorBoolean + public boolean showPronounsInPv = BuildFlags.ENABLE_PRONOUNS_IN_PV_BY_DEFAULT; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java index 54e17fcf..8b7002f9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java @@ -75,7 +75,7 @@ public class SkillOverlays { exampleText = { "\u00a7bCounter: \u00a7e37,547,860", "\u00a7bCrops/m: \u00a7e38.29", - "\u00a7bFarm: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", + "\u00a7bFarming: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", "\u00a7bCurrent XP: \u00a7e6,734", "\u00a7bRemaining XP: \u00a7e3,265", "\u00a7bXP/h: \u00a7e238,129", @@ -145,7 +145,7 @@ public class SkillOverlays { exampleText = { "\u00a7bCompact: \u00a7e547,860", "\u00a7bBlocks/m: \u00a7e38.29", - "\u00a7bMine: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", + "\u00a7bMining: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", "\u00a7bCurrent XP: \u00a7e6,734", "\u00a7bRemaining XP: \u00a7e3,265", "\u00a7bXP/h: \u00a7e238,129", diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java index d73c71dc..fef11a45 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java @@ -100,7 +100,7 @@ public class OverlayManager { List<String> farmingDummy = Lists.newArrayList( "\u00a7bCounter: \u00a7e37,547,860", "\u00a7bCrops/m: \u00a7e38.29", - "\u00a7bFarm: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", + "\u00a7bFarming: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", "\u00a7bCurrent XP: \u00a7e6,734", "\u00a7bRemaining XP: \u00a7e3,265", "\u00a7bXP/h: \u00a7e238,129", @@ -122,7 +122,7 @@ public class OverlayManager { List<String> miningSkillDummy = Lists.newArrayList( "\u00a7bCompact: \u00a7e547,860", "\u00a7bBlocks/m: \u00a7e38.29", - "\u00a7bMine: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", + "\u00a7bMining: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", "\u00a7bCurrent XP: \u00a7e6,734", "\u00a7bRemaining XP: \u00a7e3,265", "\u00a7bXP/h: \u00a7e238,129", 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 30ffcdd9..dcbcb9e4 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java @@ -19,8 +19,6 @@ package io.github.moulberry.notenoughupdates.profileviewer; -import static io.github.moulberry.notenoughupdates.util.Utils.roundToNearestInt; - import com.google.common.base.Splitter; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -30,17 +28,9 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.profileviewer.weight.lily.LilyWeight; import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight; import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.PronounDB; import io.github.moulberry.notenoughupdates.util.SBInfo; import io.github.moulberry.notenoughupdates.util.Utils; -import java.awt.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityOtherPlayerMP; import net.minecraft.client.gui.FontRenderer; @@ -63,6 +53,19 @@ import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL14; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import static io.github.moulberry.notenoughupdates.util.Utils.roundToNearestInt; + public class BasicPage extends GuiProfileViewerPage { private static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png"); @@ -117,7 +120,8 @@ public class BasicPage extends GuiProfileViewerPage { String panoramaIdentifier = "day"; if (SBInfo.getInstance().currentTimeDate != null) { - if (SBInfo.getInstance().currentTimeDate.getHours() <= 6 || SBInfo.getInstance().currentTimeDate.getHours() >= 20) { + if (SBInfo.getInstance().currentTimeDate.getHours() <= 6 || + SBInfo.getInstance().currentTimeDate.getHours() >= 20) { panoramaIdentifier = "night"; } } @@ -133,19 +137,36 @@ public class BasicPage extends GuiProfileViewerPage { Panorama.getPanoramasForLocation(location == null ? "unknown" : location, panoramaIdentifier) ); + if (Utils.isWithinRect(mouseX, mouseY, guiLeft + 23, guiTop + 44, 81, 108)) { + Optional<PronounDB.PronounChoice> pronounChoice = + GuiProfileViewer.pronouns + .peekValue() + .flatMap(it -> it); // Flatten: First optional is whether it loaded, second optional is whether it was successful + if (pronounChoice.isPresent()) { + PronounDB.PronounChoice pronouns = pronounChoice.get(); + if (pronouns.isConsciousChoice()) { + getInstance().tooltipToDisplay = pronouns.render(); + } + } + } + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_basic); Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST); if (entityPlayer != null && profile.getHypixelProfile() != null) { String playerName = null; if (profile.getHypixelProfile().has("prefix")) { - playerName = Utils.getElementAsString(profile.getHypixelProfile().get("prefix"), "") + " " + entityPlayer.getName(); + playerName = Utils.getElementAsString(profile.getHypixelProfile().get("prefix"), "") + " " + + entityPlayer.getName(); } else { String rank = Utils.getElementAsString( profile.getHypixelProfile().get("rank"), Utils.getElementAsString(profile.getHypixelProfile().get("newPackageRank"), "NONE") ); - String monthlyPackageRank = Utils.getElementAsString(profile.getHypixelProfile().get("monthlyPackageRank"), "NONE"); + String monthlyPackageRank = Utils.getElementAsString( + profile.getHypixelProfile().get("monthlyPackageRank"), + "NONE" + ); if (!rank.equals("YOUTUBER") && !monthlyPackageRank.equals("NONE")) { rank = monthlyPackageRank; } @@ -191,7 +212,13 @@ public class BasicPage extends GuiProfileViewerPage { int x = guiLeft + 63; int y = guiTop + 54; - GuiScreen.drawRect(x - halfRankPrefixLen - 1, y - 1, x + halfRankPrefixLen + 1, y + 8, new Color(0, 0, 0, 64).getRGB()); + GuiScreen.drawRect( + x - halfRankPrefixLen - 1, + y - 1, + x + halfRankPrefixLen + 1, + y + 8, + new Color(0, 0, 0, 64).getRGB() + ); fr.drawString(playerName, x - halfRankPrefixLen, y, 0, true); } @@ -200,7 +227,8 @@ public class BasicPage extends GuiProfileViewerPage { long networth = profile.getNetWorth(profileId); if (networth > 0) { Utils.drawStringCentered( - EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD + GuiProfileViewer.numberFormat.format(networth), + EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(networth), fr, guiLeft + 63, guiTop + 38, @@ -211,31 +239,38 @@ public class BasicPage extends GuiProfileViewerPage { double networthInCookies = ( networth / - NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo("BOOSTER_COOKIE").get("avg_buy").getAsDouble() + NotEnoughUpdates.INSTANCE.manager.auctionManager + .getBazaarInfo("BOOSTER_COOKIE") + .get("avg_buy") + .getAsDouble() ); String networthIRLMoney = Long.toString(Math.round(((networthInCookies * 325) / 675) * 4.99)); if ( mouseX > guiLeft + 8 && - mouseX < guiLeft + 8 + fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth)) + mouseX < guiLeft + 8 + fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth)) ) { if (mouseY > guiTop + 32 && mouseY < guiTop + 32 + fr.FONT_HEIGHT) { getInstance().tooltipToDisplay = new ArrayList<>(); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Net worth in IRL money: " + - EnumChatFormatting.DARK_GREEN + - "$" + - EnumChatFormatting.GOLD + - networthIRLMoney + "Net worth in IRL money: " + + EnumChatFormatting.DARK_GREEN + + "$" + + EnumChatFormatting.GOLD + + networthIRLMoney ); getInstance().tooltipToDisplay.add(""); if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "This is calculated using the current"); - getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "price of booster cookies on bazaar and the price"); - getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "for cookies using gems, then the price of gems"); - getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "is where we get the amount of IRL money you"); - getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "theoretically have on skyblock in net worth."); + getInstance().tooltipToDisplay.add( + EnumChatFormatting.RED + "price of booster cookies on bazaar and the price"); + getInstance().tooltipToDisplay.add( + EnumChatFormatting.RED + "for cookies using gems, then the price of gems"); + getInstance().tooltipToDisplay.add( + EnumChatFormatting.RED + "is where we get the amount of IRL money you"); + getInstance().tooltipToDisplay.add( + EnumChatFormatting.RED + "theoretically have on skyblock in net worth."); } else { getInstance().tooltipToDisplay.add(EnumChatFormatting.GRAY + "[SHIFT for Info]"); } @@ -245,7 +280,8 @@ public class BasicPage extends GuiProfileViewerPage { } } } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } if (status != null) { @@ -261,9 +297,17 @@ public class BasicPage extends GuiProfileViewerPage { NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("POTATO_CROWN") ); potato_crown.addEnchantment(Enchantment.unbreaking, 1656638942); // this number may be useful - Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(new ItemStack(Items.potato), guiLeft + 35, guiTop + 160); + Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI( + new ItemStack(Items.potato), + guiLeft + 35, + guiTop + 160 + ); Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(potato_crown, guiLeft + 50, guiTop + 162); - Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(new ItemStack(Items.potato), guiLeft + 63, guiTop + 160); + Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI( + new ItemStack(Items.potato), + guiLeft + 63, + guiTop + 160 + ); } else if (online) { locationStr = NotEnoughUpdates.INSTANCE.navigation.getNameForAreaModeOrUnknown(location); } @@ -370,7 +414,8 @@ public class BasicPage extends GuiProfileViewerPage { }, false ); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } GlStateManager.color(1, 1, 1, 1); @@ -388,9 +433,9 @@ public class BasicPage extends GuiProfileViewerPage { int x = guiLeft + 20; float y = guiTop + - 82 + - 15 * - (float) Math.sin(((getInstance().currentTime - getInstance().startTime) / 800f) % (2 * Math.PI)); + 82 + + 15 * + (float) Math.sin(((getInstance().currentTime - getInstance().startTime) / 800f) % (2 * Math.PI)); GlStateManager.translate(x, y, 0); ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false); @@ -410,7 +455,14 @@ public class BasicPage extends GuiProfileViewerPage { } } if (entityPlayer != null) { - drawEntityOnScreen(guiLeft + 63, guiTop + 128 + 7, 36, guiLeft + 63 - mouseX, guiTop + 129 - mouseY, entityPlayer); + drawEntityOnScreen( + guiLeft + 63, + guiTop + 128 + 7, + 36, + guiLeft + 63 - mouseX, + guiTop + 129 - mouseY, + entityPlayer + ); } PlayerStats.Stats stats = profile.getStats(profileId); @@ -426,7 +478,12 @@ public class BasicPage extends GuiProfileViewerPage { GlStateManager.color(1, 1, 1, 1); GlStateManager.enableBlend(); - GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL14.glBlendFuncSeparate( + GL11.GL_SRC_ALPHA, + GL11.GL_ONE_MINUS_SRC_ALPHA, + GL11.GL_ONE, + GL11.GL_ONE_MINUS_SRC_ALPHA + ); Utils.renderAlignedString( statNamePretty, EnumChatFormatting.WHITE.toString() + val, @@ -445,49 +502,49 @@ public class BasicPage extends GuiProfileViewerPage { getInstance() .tooltipToDisplay.add( EnumChatFormatting.GRAY + - "Base " + - split.get(1) + - ": " + - EnumChatFormatting.GREEN + - base + - " " + - split.get(0) + "Base " + + split.get(1) + + ": " + + EnumChatFormatting.GREEN + + base + + " " + + split.get(0) ); int passive = Math.round(profile.getPassiveStats(profileId).get(statName) - baseStats.get(statName)); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GRAY + - "Passive " + - split.get(1) + - " Bonus: +" + - EnumChatFormatting.YELLOW + - passive + - " " + - split.get(0) + "Passive " + + split.get(1) + + " Bonus: +" + + EnumChatFormatting.YELLOW + + passive + + " " + + split.get(0) ); int itemBonus = Math.round(stats.get(statName) - profile.getPassiveStats(profileId).get(statName)); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GRAY + - "Item " + - split.get(1) + - " Bonus: +" + - EnumChatFormatting.DARK_PURPLE + - itemBonus + - " " + - split.get(0) + "Item " + + split.get(1) + + " Bonus: +" + + EnumChatFormatting.DARK_PURPLE + + itemBonus + + " " + + split.get(0) ); int finalStat = Math.round(stats.get(statName)); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GRAY + - "Final " + - split.get(1) + - ": +" + - EnumChatFormatting.RED + - finalStat + - " " + - split.get(0) + "Final " + + split.get(1) + + ": +" + + EnumChatFormatting.RED + + finalStat + + " " + + split.get(0) ); } } @@ -551,17 +608,18 @@ public class BasicPage extends GuiProfileViewerPage { getInstance().tooltipToDisplay = new ArrayList<>(); getInstance().tooltipToDisplay.add(skillName); if (skyblockInfo.get(entry.getKey()).maxed) { - getInstance().tooltipToDisplay.add(EnumChatFormatting.GRAY + "Progress: " + EnumChatFormatting.GOLD + "MAXED!"); + getInstance().tooltipToDisplay.add( + EnumChatFormatting.GRAY + "Progress: " + EnumChatFormatting.GOLD + "MAXED!"); } else { int maxXp = (int) skyblockInfo.get(entry.getKey()).maxXpForLevel; getInstance() .tooltipToDisplay.add( EnumChatFormatting.GRAY + - "Progress: " + - EnumChatFormatting.DARK_PURPLE + - GuiProfileViewer.shortNumberFormat(Math.round((level % 1) * maxXp), 0) + - "/" + - GuiProfileViewer.shortNumberFormat(maxXp, 0) + "Progress: " + + EnumChatFormatting.DARK_PURPLE + + GuiProfileViewer.shortNumberFormat(Math.round((level % 1) * maxXp), 0) + + "/" + + GuiProfileViewer.shortNumberFormat(maxXp, 0) ); } String totalXpS = GuiProfileViewer.numberFormat.format((int) skyblockInfo.get(entry.getKey()).totalXp); @@ -605,23 +663,29 @@ public class BasicPage extends GuiProfileViewerPage { return ( uuidStr.substring(0, 8) + - "-" + - uuidStr.substring(8, 12) + - "-" + - uuidStr.substring(12, 16) + - "-" + - uuidStr.substring(16, 20) + - "-" + - uuidStr.substring(20, 32) + "-" + + uuidStr.substring(8, 12) + + "-" + + uuidStr.substring(12, 16) + + "-" + + uuidStr.substring(16, 20) + + "-" + + uuidStr.substring(20, 32) ); } - private void renderWeight(int mouseX, int mouseY, Map<String, ProfileViewer.Level> skyblockInfo, JsonObject profileInfo) { + private void renderWeight( + int mouseX, + int mouseY, + Map<String, ProfileViewer.Level> skyblockInfo, + JsonObject profileInfo + ) { if (skyblockInfo == null) { return; } - if (Constants.WEIGHT == null || Utils.getElement(Constants.WEIGHT, "lily.skills.overall") == null || !Utils.getElement(Constants.WEIGHT, "lily.skills.overall").isJsonPrimitive()) { + if (Constants.WEIGHT == null || Utils.getElement(Constants.WEIGHT, "lily.skills.overall") == null || + !Utils.getElement(Constants.WEIGHT, "lily.skills.overall").isJsonPrimitive()) { Utils.showOutdatedRepoNotification(); return; } @@ -635,9 +699,9 @@ public class BasicPage extends GuiProfileViewerPage { Utils.drawStringCentered( EnumChatFormatting.GREEN + - "Senither Weight: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())), + "Senither Weight: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())), fr, guiLeft + 63, guiTop + 18, @@ -646,7 +710,8 @@ public class BasicPage extends GuiProfileViewerPage { ); int textWidth = fr.getStringWidth( - "Senither Weight: " + GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())) + "Senither Weight: " + + GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())) ); if (mouseX > guiLeft + 63 - textWidth / 2 && mouseX < guiLeft + 63 + textWidth / 2) { if (mouseY > guiTop + 12 && mouseY < guiTop + 12 + fr.FONT_HEIGHT) { @@ -654,34 +719,40 @@ public class BasicPage extends GuiProfileViewerPage { getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Skills: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getSkillsWeight().getWeightStruct().getRaw())) + "Skills: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight + .getSkillsWeight() + .getWeightStruct() + .getRaw())) ); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Slayer: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getSlayerWeight().getWeightStruct().getRaw())) + "Slayer: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight + .getSlayerWeight() + .getWeightStruct() + .getRaw())) ); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Dungeons: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format( - roundToNearestInt(senitherWeight.getDungeonsWeight().getWeightStruct().getRaw()) - ) + "Dungeons: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format( + roundToNearestInt(senitherWeight.getDungeonsWeight().getWeightStruct().getRaw()) + ) ); } } Utils.drawStringCentered( EnumChatFormatting.GREEN + - "Lily Weight: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw())), + "Lily Weight: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw())), fr, guiLeft + 63, guiTop + 28, @@ -698,23 +769,32 @@ public class BasicPage extends GuiProfileViewerPage { getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Skills: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getSkillsWeight().getWeightStruct().getRaw())) + "Skills: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight + .getSkillsWeight() + .getWeightStruct() + .getRaw())) ); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Slayer: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getSlayerWeight().getWeightStruct().getRaw())) + "Slayer: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight + .getSlayerWeight() + .getWeightStruct() + .getRaw())) ); getInstance() .tooltipToDisplay.add( EnumChatFormatting.GREEN + - "Dungeons: " + - EnumChatFormatting.GOLD + - GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getDungeonsWeight().getWeightStruct().getRaw())) + "Dungeons: " + + EnumChatFormatting.GOLD + + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight + .getDungeonsWeight() + .getWeightStruct() + .getRaw())) ); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java index 758ea6e8..3cbd944d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java @@ -22,7 +22,9 @@ package io.github.moulberry.notenoughupdates.profileviewer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.PronounDB; import io.github.moulberry.notenoughupdates.util.Utils; import java.time.Instant; import java.time.LocalDateTime; @@ -32,6 +34,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TimeZone; import java.util.TreeMap; @@ -113,9 +116,10 @@ public class ExtraPage extends GuiProfileViewerPage { ); } } + JsonObject guildInfo = profile.getGuildInformation(null); + boolean shouldRenderGuild = guildInfo != null && guildInfo.has("name"); { - JsonObject guildInfo = profile.getGuildInformation(null); - if (guildInfo != null && guildInfo.has("name")) { + if (shouldRenderGuild) { Utils.renderAlignedString( EnumChatFormatting.AQUA + "Guild", EnumChatFormatting.WHITE + guildInfo.get("name").getAsString(), @@ -125,6 +129,15 @@ public class ExtraPage extends GuiProfileViewerPage { ); } } + { + GuiProfileViewer.pronouns.peekValue().flatMap(it -> it).ifPresent(choice -> Utils.renderAlignedString( + EnumChatFormatting.GREEN + "Pronouns", + EnumChatFormatting.WHITE + String.join(" / ", choice.render()), + guiLeft + xStart, + guiTop + yStartTop + yOffset * (shouldRenderGuild ? 5 : 4), + 76 + )); + } float fairySouls = Utils.getElementAsFloat(Utils.getElement(profileInfo, "fairy_souls_collected"), 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 09eed1cf..59373952 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java @@ -19,7 +19,6 @@ package io.github.moulberry.notenoughupdates.profileviewer; -import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -29,7 +28,9 @@ import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay; import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryPage; import io.github.moulberry.notenoughupdates.profileviewer.trophy.TrophyFishPage; +import io.github.moulberry.notenoughupdates.util.AsyncDependencyLoader; import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.PronounDB; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityOtherPlayerMP; @@ -53,6 +54,7 @@ import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL20; import java.awt.*; +import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -63,6 +65,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; public class GuiProfileViewer extends GuiScreen { @@ -73,69 +77,72 @@ public class GuiProfileViewer extends GuiScreen { public static final ResourceLocation pv_bingo = new ResourceLocation("notenoughupdates:pv_bingo.png"); public static final ResourceLocation pv_stranded = new ResourceLocation("notenoughupdates:pv_stranded.png"); public static final ResourceLocation pv_unknown = new ResourceLocation("notenoughupdates:pv_unknown.png"); - public static final ResourceLocation resource_packs = new ResourceLocation("minecraft:textures/gui/resource_packs.png"); + public static final ResourceLocation resource_packs = + new ResourceLocation("minecraft:textures/gui/resource_packs.png"); public static final ResourceLocation icons = new ResourceLocation("textures/gui/icons.png"); - public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS = new HashMap<String, HashMap<String, Float>>() { - { - put( - "PET_ITEM_BIG_TEETH_COMMON", - new HashMap<String, Float>() { - { - put("CRIT_CHANCE", 5f); + public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS = + new HashMap<String, HashMap<String, Float>>() { + { + put( + "PET_ITEM_BIG_TEETH_COMMON", + new HashMap<String, Float>() { + { + put("CRIT_CHANCE", 5f); + } } - } - ); - put( - "PET_ITEM_HARDENED_SCALES_UNCOMMON", - new HashMap<String, Float>() { - { - put("DEFENCE", 25f); + ); + put( + "PET_ITEM_HARDENED_SCALES_UNCOMMON", + new HashMap<String, Float>() { + { + put("DEFENCE", 25f); + } } - } - ); - put( - "PET_ITEM_LUCKY_CLOVER", - new HashMap<String, Float>() { - { - put("MAGIC_FIND", 7f); + ); + put( + "PET_ITEM_LUCKY_CLOVER", + new HashMap<String, Float>() { + { + put("MAGIC_FIND", 7f); + } } - } - ); - put( - "PET_ITEM_SHARPENED_CLAWS_UNCOMMON", - new HashMap<String, Float>() { - { - put("CRIT_DAMAGE", 15f); + ); + put( + "PET_ITEM_SHARPENED_CLAWS_UNCOMMON", + new HashMap<String, Float>() { + { + put("CRIT_DAMAGE", 15f); + } } - } - ); - } - }; - public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS_MULT = new HashMap<String, HashMap<String, Float>>() { - { - put( - "PET_ITEM_IRON_CLAWS_COMMON", - new HashMap<String, Float>() { - { - put("CRIT_DAMAGE", 1.4f); - put("CRIT_CHANCE", 1.4f); + ); + } + }; + public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS_MULT = + new HashMap<String, HashMap<String, Float>>() { + { + put( + "PET_ITEM_IRON_CLAWS_COMMON", + new HashMap<String, Float>() { + { + put("CRIT_DAMAGE", 1.4f); + put("CRIT_CHANCE", 1.4f); + } } - } - ); - put( - "PET_ITEM_TEXTBOOK", - new HashMap<String, Float>() { - { - put("INTELLIGENCE", 2f); + ); + put( + "PET_ITEM_TEXTBOOK", + new HashMap<String, Float>() { + { + put("INTELLIGENCE", 2f); + } } - } - ); - } - }; + ); + } + }; public static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); - private static final char[] c = new char[] { 'k', 'm', 'b', 't' }; + private static final char[] c = new char[]{'k', 'm', 'b', 't'}; public static ProfileViewerPage currentPage = ProfileViewerPage.BASIC; public static HashMap<String, String> MINION_RARITY_TO_NUM = new HashMap<String, String>() { { @@ -151,6 +158,14 @@ public class GuiProfileViewer extends GuiScreen { private static int guiTop; private static ProfileViewer.Profile profile; private static String profileId = null; + public static AsyncDependencyLoader<Optional<PronounDB.PronounChoice>> pronouns = + AsyncDependencyLoader.withEqualsInvocation( + () -> + NotEnoughUpdates.INSTANCE.config.profileViewer.showPronounsInPv + ? Optional.ofNullable(profile).map(it -> Utils.parseDashlessUUID(it.getUuid())) + : Optional.<UUID>empty(), + uuid -> CompletableFuture.supplyAsync(() -> uuid.flatMap(PronounDB::getPronounsFor)) + ); public final GuiElementTextField playerNameTextField; public final GuiElementTextField inventoryTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT); private final Map<ProfileViewerPage, GuiProfileViewerPage> pages = new HashMap<>(); @@ -268,7 +283,6 @@ public class GuiProfileViewer extends GuiScreen { return levelObj; } - public static String shortNumberFormat(double n, int iteration) { if (n < 1000) { if (n % 1 == 0) { @@ -280,7 +294,10 @@ public class GuiProfileViewer extends GuiScreen { double d = ((long) n / 100) / 10.0; boolean isRound = (d * 10) % 10 == 0; - return d < 1000 ? (isRound || d > 9.99 ? (int) d * 10 / 10 : d + "") + "" + c[iteration] : shortNumberFormat(d, iteration + 1); + return d < 1000 ? (isRound || d > 9.99 ? (int) d * 10 / 10 : d + "") + "" + c[iteration] : shortNumberFormat( + d, + iteration + 1 + ); } public static int getGuiLeft() { @@ -429,7 +446,17 @@ public class GuiProfileViewer extends GuiScreen { //Render Open In Skycrypt button renderBlurredBackground(width, height, guiLeft + 100 + 6 + 2, guiTop + sizeY + 3 + 2, 100 - 4, 20 - 4); Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown); - Utils.drawTexturedRect(guiLeft + 100 + 6, guiTop + sizeY + 3, 100, 20, 0, 100 / 200f, 0, 20 / 185f, GL11.GL_NEAREST); + Utils.drawTexturedRect( + guiLeft + 100 + 6, + guiTop + sizeY + 3, + 100, + 20, + 0, + 100 / 200f, + 0, + 20 / 185f, + GL11.GL_NEAREST + ); Utils.drawStringCenteredScaledMaxWidth( "Open in Skycrypt", Minecraft.getMinecraft().fontRendererObj, @@ -567,7 +594,14 @@ public class GuiProfileViewer extends GuiScreen { } } - Utils.drawStringCentered(str, Minecraft.getMinecraft().fontRendererObj, guiLeft + sizeX / 2f, guiTop + 101, true, 0); + Utils.drawStringCentered( + str, + Minecraft.getMinecraft().fontRendererObj, + guiLeft + sizeX / 2f, + guiTop + 101, + true, + 0 + ); //This is just here to inform the player what to do //like typing /api new or telling them to go find a psychotherapist @@ -846,7 +880,8 @@ public class GuiProfileViewer extends GuiScreen { Desktop desk = Desktop.getDesktop(); desk.browse( new URI( - "https://sky.shiiyu.moe/stats/" + profile.getHypixelProfile().get("displayname").getAsString() + "/" + profileId + "https://sky.shiiyu.moe/stats/" + profile.getHypixelProfile().get("displayname").getAsString() + "/" + + profileId ) ); Utils.playPressSound(); @@ -970,7 +1005,8 @@ public class GuiProfileViewer extends GuiScreen { String levelStr; String totalXpStr = null; if (skillName.contains("Catacombs")) totalXpStr = - EnumChatFormatting.GRAY + "Total XP: " + EnumChatFormatting.DARK_PURPLE + numberFormat.format(levelObj.totalXp); + EnumChatFormatting.GRAY + "Total XP: " + EnumChatFormatting.DARK_PURPLE + + numberFormat.format(levelObj.totalXp); if (levelObj.maxed) { levelStr = EnumChatFormatting.GOLD + "MAXED!"; } else { @@ -1150,14 +1186,21 @@ public class GuiProfileViewer extends GuiScreen { ); blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } if (blurShaderVert == null) { try { - blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", blurOutputHorz, blurOutputVert); + blurShaderVert = new Shader( + Minecraft.getMinecraft().getResourceManager(), + "blur", + blurOutputHorz, + blurOutputVert + ); blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } if (blurShaderHorz != null && blurShaderVert != null) { if (15 != lastBgBlurFactor) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java index 7ca3e6a8..b37aa73f 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java @@ -112,6 +112,13 @@ public class BestiaryPage extends GuiProfileViewerPage { List<String> mobs = BestiaryData.getBestiaryLocations().get(selectedBestiaryLocation); Color color = new Color(128, 128, 128, 255); + Utils.renderAlignedString( + EnumChatFormatting.RED + "Bestiary Level: ", + EnumChatFormatting.GRAY + "" + (float) getBestiaryTiers(profileInfo) / 10, + guiLeft + 220, + guiTop + 50, + 110 + ); if (mobs != null) { for (int i = 0; i < mobs.size(); i++) { String mob = mobs.get(i); @@ -218,13 +225,6 @@ public class BestiaryPage extends GuiProfileViewerPage { ); } } - Utils.renderAlignedString( - EnumChatFormatting.RED + "Bestiary Level: ", - EnumChatFormatting.GRAY + "" + (float) getBestiaryTiers(profileInfo) / 10, - guiLeft + 220, - guiTop + 50, - 110 - ); } } if (tooltipToDisplay != null) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java index 0d891071..61749593 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java @@ -26,6 +26,7 @@ import com.google.gson.JsonPrimitive; import io.github.moulberry.notenoughupdates.NEUManager; import io.github.moulberry.notenoughupdates.miscfeatures.entityviewer.EntityViewer; import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe; +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer; import io.github.moulberry.notenoughupdates.profileviewer.Panorama; import io.github.moulberry.notenoughupdates.util.ItemUtils; import io.github.moulberry.notenoughupdates.util.JsonUtils; @@ -64,11 +65,32 @@ public class MobLootRecipe implements NeuRecipe { if (itemStack == null) { itemStack = drop.getItemStack().copy(); List<String> arrayList = new ArrayList<>(extra); - arrayList.add("§r§e§lDrop Chance: §6" + chance); + arrayList.add("§r§e§lDrop Chance: §6" + formatDropChance()); ItemUtils.appendLore(itemStack, arrayList); } return itemStack; } + + private String formatDropChance() { + if (chance == null) { + return ""; + } + + if (!chance.endsWith("%")) { + return chance; + } + + String chanceText = chance.substring(0, chance.length() - 1); + int chanceIn; + try { + chanceIn = (int) (100.0 / Double.parseDouble(chanceText)); + } catch (NumberFormatException e) { + return chance; + } + + String format = GuiProfileViewer.numberFormat.format(chanceIn); + return "1/" + format + " (" + chance + ")"; + } } public static ResourceLocation BACKGROUND = new ResourceLocation( diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java new file mode 100644 index 00000000..37b0a187 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java @@ -0,0 +1,55 @@ +/* + * 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 com.google.common.base.Objects; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +public interface AsyncDependencyLoader<T> { + + Optional<T> peekValue(); + + public static <R, T> AsyncDependencyLoader<T> withObjectIdentity( + Supplier<R> supplier, + Function<R, CompletableFuture<T>> generator + ) { + return new AsyncDependencyLoaderImpl<>(supplier, generator, (a, b) -> a != b); + } + + public static <R, T> AsyncDependencyLoader<T> withEqualsInvocation( + Supplier<R> supplier, + Function<R, CompletableFuture<T>> generator + ) { + return new AsyncDependencyLoaderImpl<>(supplier, generator, (a, b) -> !Objects.equal(a, b)); + } + + public static <R, T> AsyncDependencyLoader<T> withEqualityFunction( + Supplier<R> supplier, + Function<R, CompletableFuture<T>> generator, + BiFunction<R, R, Boolean> isEqual + ) { + return new AsyncDependencyLoaderImpl<>(supplier, generator, (a, b) -> !isEqual.apply(a, b)); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java new file mode 100644 index 00000000..4b7f2fb8 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java @@ -0,0 +1,59 @@ +/* + * 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 java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +class AsyncDependencyLoaderImpl<R, T> implements AsyncDependencyLoader<T> { + + private final Supplier<R> supplyDependency; + private final Function<R, CompletableFuture<T>> generator; + private final BiFunction<R, R, Boolean> isDifferent; + private volatile CompletableFuture<T> lastValue; + private volatile R lastDependency; + private volatile boolean isFirstFire = true; + + @Override + public synchronized Optional<T> peekValue() { + R nextDependency = supplyDependency.get(); + if (isFirstFire || isDifferent.apply(nextDependency, lastDependency)) { + isFirstFire = false; + if (lastValue != null) + lastValue.cancel(true); + lastValue = generator.apply(nextDependency); + } + lastDependency = nextDependency; + return Optional.ofNullable(lastValue.getNow(null)); + } + + AsyncDependencyLoaderImpl( + Supplier<R> supplyDependency, + Function<R, CompletableFuture<T>> generator, + BiFunction<R, R, Boolean> isDifferent + ) { + this.supplyDependency = supplyDependency; + this.generator = generator; + this.isDifferent = isDifferent; + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java b/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java new file mode 100644 index 00000000..bf973b76 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java @@ -0,0 +1,37 @@ +/* + * 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 net.minecraft.client.Minecraft; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Executor; + +public class MinecraftExecutor implements Executor { + + public static MinecraftExecutor INSTANCE = new MinecraftExecutor(); + + private MinecraftExecutor() {} + + @Override + public void execute(@NotNull Runnable runnable) { + Minecraft.getMinecraft().addScheduledTask(runnable); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java b/src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java new file mode 100644 index 00000000..e7286721 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java @@ -0,0 +1,221 @@ +/* + * 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 com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.core.util.StringUtils; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +public class PronounDB { + + static SSLContext ctx; + + static { + try { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(PronounDB.class.getResourceAsStream("/pronoundb.jks"), "pronoundb".toCharArray()); + ctx = SSLContext.getInstance("TLS"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, null); + tmf.init(ks); + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException | + IOException | CertificateException e) { + System.out.println("Failed to load keystore. PronounDB requests will probably not work"); + e.printStackTrace(); + } + } + + private static boolean isDisabled() { + JsonObject disabled = Constants.DISABLE; + return disabled != null && disabled.has("pronoundb"); + } + + /** + * Returns an Optional, since JVMs can be *very* funky with KeyStore loading + */ + public static Optional<JsonObject> performPronouning(String platform, String id) { + if (isDisabled()) return Optional.empty(); + try { + URL url = new URL("https://pronoundb.org/api/v1/lookup" + + "?platform=" + StringUtils.urlEncode(platform) + + "&id=" + StringUtils.urlEncode(id)); + HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); + urlConnection.setSSLSocketFactory(ctx.getSocketFactory()); + return Optional.of(NotEnoughUpdates.INSTANCE.manager.gson.fromJson( + new InputStreamReader(urlConnection.getInputStream()), + JsonObject.class + )); + } catch (ClassCastException | IOException | JsonParseException e) { + System.out.println("Failed to contact PronounDB: " + e); + return Optional.empty(); + } + } + + public enum Pronoun { + HE("he", "him", "his"), + IT("it", "it", "its"), + SHE("she", "her", "hers"), + THEY("they", "they", "theirs"); + + private final String subject; + private final String object; + private final String possessive; + + Pronoun(String subject, String object, String possessive) { + this.subject = subject; + this.object = object; + this.possessive = possessive; + } + + public String getSubject() { + return subject; + } + + public String getObject() { + return object; + } + + public String getPossessive() { + return possessive; + } + } + + public enum PronounChoice { + UNSPECIFIED("unspecified", "Unspecified"), + HE("hh", Pronoun.HE), + HEIT("hi", Pronoun.HE, Pronoun.IT), + HESHE("hs", Pronoun.HE, Pronoun.SHE), + HETHEY("ht", Pronoun.HE, Pronoun.THEY), + ITHE("ih", Pronoun.IT, Pronoun.HE), + IT("ii", Pronoun.IT), + ITSHE("is", Pronoun.IT, Pronoun.SHE), + ITTHEY("it", Pronoun.IT, Pronoun.THEY), + SHEHE("shh", Pronoun.SHE, Pronoun.HE), + SHE("sh", Pronoun.SHE), + SHEIT("si", Pronoun.SHE, Pronoun.IT), + SHETHEY("st", Pronoun.SHE, Pronoun.THEY), + THEYHE("th", Pronoun.THEY, Pronoun.HE), + THEYIT("ti", Pronoun.THEY, Pronoun.IT), + THEYSHE("ts", Pronoun.THEY, Pronoun.SHE), + THEY("tt", Pronoun.THEY), + ANY("any", "Any pronouns"), + OTHER("other", "Other pronouns"), + ASK("ask", "Ask me my pronouns"), + AVOID("avoid", "Avoid pronouns, use my name"); + private final String id; + private List<Pronoun> pronouns = null; + private String override = null; + + PronounChoice(String id, String override) { + this.override = override; + this.id = id; + } + + PronounChoice(String id, Pronoun... pronouns) { + this.id = id; + this.pronouns = Arrays.asList(pronouns); + } + + public static Optional<PronounChoice> findPronounsForId(String id) { + for (PronounChoice value : values()) { + if (value.id.equals(id)) return Optional.of(value); + } + return Optional.empty(); + } + + public String getOverride() { + return override; + } + + public List<Pronoun> getPronounsInPreferredOrder() { + return pronouns; + } + + public String getId() { + return id; + } + + public List<String> render() { + if (override != null) + return Arrays.asList(override); + return pronouns + .stream() + .map(pronoun -> pronoun.getSubject() + "/" + pronoun.getObject()) + .collect(Collectors.toList()); + } + + public boolean isConsciousChoice() { + return this != UNSPECIFIED; + } + + } + + public static Optional<PronounChoice> parsePronouns(JsonObject pronounObject) { + if (pronounObject.has("pronouns")) { + JsonElement pronouns = pronounObject.get("pronouns"); + if (pronouns.isJsonPrimitive() && pronouns.getAsJsonPrimitive().isString()) + return PronounChoice.findPronounsForId(pronouns.getAsString()); + } + return Optional.empty(); + } + + public static Optional<PronounChoice> getPronounsFor(String platform, String name) { + return performPronouning(platform, name).flatMap(PronounDB::parsePronouns); + } + + public static Optional<PronounChoice> getPronounsFor(UUID minecraftPlayer) { + return performPronouning("minecraft", minecraftPlayer.toString() /* dashed UUID */) + .flatMap(PronounDB::parsePronouns); + } + + public static void test() { + try { + System.out.println("Pronouning..."); + PronounChoice pronounsFor = getPronounsFor(UUID.fromString("842204e6-6880-487b-ae5a-0595394f9948")).get(); + pronounsFor.render().forEach(System.out::println); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java index 74409648..4e920aea 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java @@ -61,6 +61,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -87,6 +89,8 @@ public class SBInfo { public Date currentTimeDate = null; + private JsonObject mayorJson = new JsonObject(); + /** * Use Utils.getOpenChestName() instead */ @@ -97,6 +101,7 @@ public class SBInfo { private long lastManualLocRaw = -1; private long lastLocRaw = -1; public long joinedWorld = -1; + private long lastMayorUpdate; public long unloadedWorld = -1; private JsonObject locraw = null; public boolean isInDungeon = false; @@ -297,7 +302,10 @@ public class SBInfo { lastLocRaw = System.currentTimeMillis(); NotEnoughUpdates.INSTANCE.sendChatMessage("/locraw"); } - + if (currentTime - lastMayorUpdate > 300 * 1000) { + updateMayor(); + lastMayorUpdate = currentTime; + } try { for (NetworkPlayerInfo info : Minecraft.getMinecraft().thePlayer.sendQueue.getPlayerInfoMap()) { String name = Minecraft.getMinecraft().ingameGUI.getTabList().getPlayerName(info); @@ -421,4 +429,17 @@ public class SBInfo { e.printStackTrace(); } } + + public void updateMayor() { + NotEnoughUpdates.INSTANCE.manager.hypixelApi.getHypixelApiAsync( + NotEnoughUpdates.INSTANCE.config.apiData.apiKey, + "resources/skyblock/election", + new HashMap<>() + ).thenAcceptAsync(newJson -> mayorJson = newJson); + } + + + public JsonObject getMayorJson() { + return mayorJson; + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java index 5b3ea853..2267cbea 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -73,6 +73,7 @@ import java.io.FileInputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.math.BigInteger; import java.nio.FloatBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -81,6 +82,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1943,9 +1945,13 @@ public class Utils { if (NotEnoughUpdates.INSTANCE.config.notifications.outdatedRepo) { NotificationHandler.displayNotification(Lists.newArrayList( EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "Missing repo data", - EnumChatFormatting.RED + "Data used for many NEU features is not up to date, this should normally not be the case.", - EnumChatFormatting.RED + "You can try " + EnumChatFormatting.BOLD + "/neuresetrepo" + EnumChatFormatting.RESET + EnumChatFormatting.RED +" and restart your game" + - " to see if that fixes the issue.", EnumChatFormatting.RED + "If the problem persists please join " + EnumChatFormatting.BOLD + "discord.gg/moulberry" + + EnumChatFormatting.RED + + "Data used for many NEU features is not up to date, this should normally not be the case.", + EnumChatFormatting.RED + "You can try " + EnumChatFormatting.BOLD + "/neuresetrepo" + EnumChatFormatting.RESET + + EnumChatFormatting.RED + " and restart your game" + + " to see if that fixes the issue.", + EnumChatFormatting.RED + "If the problem persists please join " + EnumChatFormatting.BOLD + + "discord.gg/moulberry" + EnumChatFormatting.RESET + EnumChatFormatting.RED + " and message in " + EnumChatFormatting.BOLD + "#neu-support" + EnumChatFormatting.RESET + EnumChatFormatting.RED + " to get support" ), @@ -1979,6 +1985,13 @@ public class Utils { return -1; } + public static UUID parseDashlessUUID(String dashlessUuid) { + // From: https://stackoverflow.com/a/30760478/ + BigInteger most = new BigInteger(dashlessUuid.substring(0, 16), 16); + BigInteger least = new BigInteger(dashlessUuid.substring(16, 32), 16); + return new UUID(most.longValue(), least.longValue()); + } + public static String getOpenChestName() { return SBInfo.getInstance().currentlyOpenChestName; } diff --git a/src/main/resources/pronoundb.jks b/src/main/resources/pronoundb.jks Binary files differnew file mode 100644 index 00000000..1c279333 --- /dev/null +++ b/src/main/resources/pronoundb.jks |