diff options
author | Aaron <51387595+AzureAaron@users.noreply.github.com> | 2024-05-04 19:14:06 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-04 19:14:06 -0400 |
commit | 4a4234d7c9d4f038d4fa418fb15ef24ce3fcc501 (patch) | |
tree | 6e87c6b67aabeb82dbe075d68c16b5492ff92c9b | |
parent | ed0489539902d77595625aaa3bca4e328e1f7e88 (diff) | |
parent | f7b13895a4605e1d22e2c00e7b62c7365902d1aa (diff) | |
download | Skyblocker-4a4234d7c9d4f038d4fa418fb15ef24ce3fcc501.tar.gz Skyblocker-4a4234d7c9d4f038d4fa418fb15ef24ce3fcc501.tar.bz2 Skyblocker-4a4234d7c9d4f038d4fa418fb15ef24ce3fcc501.zip |
Merge pull request #669 from SkyblockerMod/1.20.5
1.20.5 & 1.20.6
178 files changed, 1984 insertions, 1338 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 6ffca898..42b083d4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,7 +35,7 @@ body: label: Minecraft Version description: What version of Minecraft are you running? If you do not know what version you are using, look in the bottom left corner of the main menu in game. options: - - "1.20.4" + - "1.20.6" validations: required: true - type: input @@ -43,7 +43,7 @@ body: attributes: label: Skyblocker Version description: What version of Skyblocker are you running? Every part is important! If you do not know what version you are using, look at the file name in your "mods" folder. - placeholder: ex. skyblocker-1.19.0+1.20.4.jar + placeholder: ex. skyblocker-1.20.3+1.20.6.jar validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/crash_report.yml b/.github/ISSUE_TEMPLATE/crash_report.yml index 7135848d..142e1314 100644 --- a/.github/ISSUE_TEMPLATE/crash_report.yml +++ b/.github/ISSUE_TEMPLATE/crash_report.yml @@ -16,7 +16,7 @@ body: label: Minecraft Version description: What version of Minecraft are you running? If you do not know what version you are using, look in the bottom left corner of the main menu in game. options: - - "1.20.4" + - "1.20.6" validations: required: true - type: input @@ -24,7 +24,7 @@ body: attributes: label: Skyblocker Version description: What version of Skyblocker are you running? Every part is important! If you do not know what version you are using, look at the file name in your "mods" folder. - placeholder: ex. skyblocker-1.19.0+1.20.4.jar + placeholder: ex. skyblocker-1.20.3+1.20.6.jar validations: required: true - type: textarea diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 7100e2e2..e1d3427c 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -59,6 +59,15 @@ jobs: - name: Build with Gradle run: ./gradlew build + - name: Store reports + if: failure() + uses: actions/upload-artifact@v4 + with: + name: reports + path: | + **/build/reports/ + **/build/test-results/ + - uses: actions/github-script@v7 id: fname with: @@ -10,7 +10,7 @@ [![Ko-fi](https://img.shields.io/badge/buy%20me%20coffee-skyblocker?color=434B57&logo=kofi)](https://ko-fi.com/wohlhabend) [![Translated](https://translate.hysky.de/widgets/Skyblocker/-/skyblocker/svg-badge.svg)](https://translate.hysky.de/projects/Skyblocker/skyblocker/) -Hypixel Skyblock Mod for Minecraft 1.20.4 +Hypixel Skyblock Mod for Minecraft 1.20.6 Installation guide is [here](https://github.com/SkyblockerMod/Skyblocker/wiki/installation) or use our [Modpack](https://modrinth.com/modpack/skyblocker-modpack) ## Features diff --git a/build.gradle b/build.gradle index d7b37bfe..fd21ebd5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.5-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' id "me.modmuss50.mod-publish-plugin" version "0.5.1" } @@ -36,14 +36,19 @@ dependencies { testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}" // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + //Layered Yarn & Mojmap - used to fill in intermediary names + mappings loom.layered { + //Using Mojmap breaks runClient, so uncomment only for snapshots when temp mappings are needed + //officialMojangMappings() + mappings("net.fabricmc:yarn:${project.yarn_mappings}:v2") + } modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" // YACL - include modImplementation("dev.isxander.yacl:yet-another-config-lib-fabric:${project.yacl_version}") + include modImplementation("dev.isxander:yet-another-config-lib:${project.yacl_version}-fabric") // Mod Menu modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}" @@ -92,17 +97,12 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 17 + it.options.release = 21 } java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. - withSourcesJar() - - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } jar { diff --git a/gradle.properties b/gradle.properties index ce2fbd89..ceb86ac8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,19 +3,19 @@ org.gradle.parallel=true # Fabric Properties (https://fabricmc.net/versions.html) ## 1.20 -minecraft_version=1.20.4 -yarn_mappings=1.20.4+build.1 -loader_version=0.15.1 +minecraft_version=1.20.6 +yarn_mappings=1.20.6+build.1 +loader_version=0.15.10 #Fabric api ## 1.20 -fabric_api_version=0.92.0+1.20.4 +fabric_api_version=0.97.8+1.20.6 # Minecraft Mods ## YACL (https://github.com/isXander/YetAnotherConfigLib) -yacl_version=3.3.2+1.20.4 +yacl_version=3.4.1+1.20.5 ## Mod Menu (https://modrinth.com/mod/modmenu/versions) -mod_menu_version = 9.0.0-alpha.3 +mod_menu_version = 10.0.0-beta.1 ## REI (https://modrinth.com/mod/rei/versions?l=fabric) rei_version = 13.0.666 ## EMI (https://modrinth.com/mod/emi/versions) @@ -25,11 +25,11 @@ emi_version = 1.0.22+1.20.2 ## Occlusion Culling (https://github.com/LogisticsCraft/OcclusionCulling) occlusionculling_version = 0.0.8-SNAPSHOT ## neu repoparser (https://repo.nea.moe/#/releases/moe/nea/neurepoparser/) -repoparser_version = 1.4.0 +repoparser_version = 1.5.0 # Other Libraries ## JGit (https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit) -jgit_version = 6.8.0.202311291450-r +jgit_version = 6.9.0.202403050737-r ## Apache Commons Math (https://mvnrepository.com/artifact/org.apache.commons/commons-math3) commons_math_version = 3.6.1 diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index e0815eee..3336cefb 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -136,6 +136,7 @@ public class SkyblockerMod implements ClientModInitializer { LividColor.init(); FishingHelper.init(); DungeonMap.init(); + DungeonScoreHUD.init(); DungeonManager.init(); DungeonBlaze.init(); Waterboard.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java b/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java index 07109b46..41511732 100644 --- a/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java @@ -6,7 +6,6 @@ import it.unimi.dsi.fastutil.ints.IntIntMutablePair; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; import java.awt.*; import java.util.List; @@ -70,8 +69,8 @@ public abstract class HudConfigScreen extends Screen { @Override public final boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (button == 0 && draggingWidget != null) { - draggingWidget.setX((int) MathHelper.clamp(mouseX - mouseClickRelativeX, 0, this.width - draggingWidget.getWidth())); - draggingWidget.setY((int) MathHelper.clamp(mouseY - mouseClickRelativeY, 0, this.height - draggingWidget.getHeight())); + draggingWidget.setX((int) Math.clamp(mouseX - mouseClickRelativeX, 0, this.width - draggingWidget.getWidth())); + draggingWidget.setY((int) Math.clamp(mouseY - mouseClickRelativeY, 0, this.height - draggingWidget.getHeight())); } return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); } diff --git a/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java b/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java index 584b79e7..77dd2f61 100644 --- a/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java +++ b/src/main/java/de/hysky/skyblocker/config/ImageRepoLoader.java @@ -8,6 +8,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -85,7 +86,7 @@ public class ImageRepoLoader { update(retries + 1); } } - }); + }, Executors.newVirtualThreadPerTaskExecutor()); } /** @@ -96,7 +97,7 @@ public class ImageRepoLoader { if (Files.exists(file)) { try (BufferedReader reader = Files.newBufferedReader(file)) { - CommitData commitData = CommitData.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow(); + CommitData commitData = CommitData.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow(); return commitData.commit(); } @@ -115,7 +116,7 @@ public class ImageRepoLoader { CommitData commitData = new CommitData(newHash, System.currentTimeMillis()); try (BufferedWriter writer = Files.newBufferedWriter(file)) { - SkyblockerMod.GSON.toJson(CommitData.CODEC.encodeStart(JsonOps.INSTANCE, commitData).result().orElseThrow(), writer); + SkyblockerMod.GSON.toJson(CommitData.CODEC.encodeStart(JsonOps.INSTANCE, commitData).getOrThrow(), writer); } } diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java index 70578822..31f1357d 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java @@ -4,7 +4,7 @@ import com.google.gson.FieldNamingPolicy; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.categories.*; -import de.hysky.skyblocker.mixin.accessor.HandledScreenAccessor; +import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.utils.scheduler.Scheduler; import dev.isxander.yacl3.api.YetAnotherConfigLib; import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; diff --git a/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java index e2684115..4b3c0dfd 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java @@ -4,6 +4,7 @@ import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.OptionDescription; import dev.isxander.yacl3.api.OptionGroup; import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder; import dev.isxander.yacl3.api.controller.StringControllerBuilder; @@ -51,6 +52,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button1.item.nbt, () -> config.quickNav.button1.item.nbt, newValue -> config.quickNav.button1.item.nbt = newValue) @@ -99,6 +101,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button2.item.nbt, () -> config.quickNav.button2.item.nbt, newValue -> config.quickNav.button2.item.nbt = newValue) @@ -147,6 +150,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button3.item.nbt, () -> config.quickNav.button3.item.nbt, newValue -> config.quickNav.button3.item.nbt = newValue) @@ -195,6 +199,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button4.item.nbt, () -> config.quickNav.button4.item.nbt, newValue -> config.quickNav.button4.item.nbt = newValue) @@ -243,6 +248,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button5.item.nbt, () -> config.quickNav.button5.item.nbt, newValue -> config.quickNav.button5.item.nbt = newValue) @@ -291,6 +297,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button6.item.nbt, () -> config.quickNav.button6.item.nbt, newValue -> config.quickNav.button6.item.nbt = newValue) @@ -339,6 +346,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button7.item.nbt, () -> config.quickNav.button7.item.nbt, newValue -> config.quickNav.button7.item.nbt = newValue) @@ -387,6 +395,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button8.item.nbt, () -> config.quickNav.button8.item.nbt, newValue -> config.quickNav.button8.item.nbt = newValue) @@ -435,6 +444,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button9.item.nbt, () -> config.quickNav.button9.item.nbt, newValue -> config.quickNav.button9.item.nbt = newValue) @@ -483,6 +493,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button10.item.nbt, () -> config.quickNav.button10.item.nbt, newValue -> config.quickNav.button10.item.nbt = newValue) @@ -531,6 +542,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button11.item.nbt, () -> config.quickNav.button11.item.nbt, newValue -> config.quickNav.button11.item.nbt = newValue) @@ -579,6 +591,7 @@ public class QuickNavigationCategory { .build()) .option(Option.<String>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip"))) .binding(defaults.quickNav.button12.item.nbt, () -> config.quickNav.button12.item.nbt, newValue -> config.quickNav.button12.item.nbt = newValue) diff --git a/src/main/java/de/hysky/skyblocker/debug/Debug.java b/src/main/java/de/hysky/skyblocker/debug/Debug.java index 86adcac6..8c883b30 100644 --- a/src/main/java/de/hysky/skyblocker/debug/Debug.java +++ b/src/main/java/de/hysky/skyblocker/debug/Debug.java @@ -3,26 +3,37 @@ package de.hysky.skyblocker.debug; import com.mojang.brigadier.Command; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.text.Text; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; +import java.util.List; + public class Debug { private static final boolean DEBUG_ENABLED = Boolean.parseBoolean(System.getProperty("skyblocker.debug", "false")); + private static boolean showInvisibleArmorStands = false; + public static boolean debugEnabled() { return DEBUG_ENABLED || FabricLoader.getInstance().isDevelopmentEnvironment(); } public static void init() { if (debugEnabled()) { + SnapshotDebug.init(); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("debug") .then(dumpPlayersCommand()) - .then(ItemUtils.dumpHeldItemNbtCommand()) + .then(ItemUtils.dumpHeldItemCommand()) + .then(toggleShowingInvisibleArmorStands()) + .then(dumpArmorStandHeadTextures()) ))); } } @@ -34,4 +45,36 @@ public class Debug { return Command.SINGLE_SUCCESS; }); } + + private static LiteralArgumentBuilder<FabricClientCommandSource> toggleShowingInvisibleArmorStands() { + return literal("toggleShowingInvisibleArmorStands") + .executes(context -> { + showInvisibleArmorStands = !showInvisibleArmorStands; + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.debug.toggledShowingInvisibleArmorStands", showInvisibleArmorStands))); + return Command.SINGLE_SUCCESS; + }); + } + + private static LiteralArgumentBuilder<FabricClientCommandSource> dumpArmorStandHeadTextures() { + return literal("dumpArmorStandHeadTextures") + .executes(context -> { + List<ArmorStandEntity> armorStands = context.getSource().getWorld().getEntitiesByClass(ArmorStandEntity.class, context.getSource().getPlayer().getBoundingBox().expand(8d), EntityPredicates.NOT_MOUNTED); + + for (ArmorStandEntity armorStand : armorStands) { + Iterable<ItemStack> equippedItems = armorStand.getEquippedItems(); + + for (ItemStack stack : equippedItems) { + String texture = ItemUtils.getHeadTexture(stack); + + if (!texture.isEmpty()) context.getSource().sendFeedback(Text.of(texture)); + } + } + + return Command.SINGLE_SUCCESS; + }); + } + + public static boolean shouldShowInvisibleArmorStands() { + return showInvisibleArmorStands; + } } diff --git a/src/main/java/de/hysky/skyblocker/debug/SnapshotDebug.java b/src/main/java/de/hysky/skyblocker/debug/SnapshotDebug.java new file mode 100644 index 00000000..bd4abd2c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/debug/SnapshotDebug.java @@ -0,0 +1,32 @@ +package de.hysky.skyblocker.debug; + +import de.hysky.skyblocker.utils.render.RenderHelper; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.SharedConstants; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class SnapshotDebug { + private static final float[] RED = { 1.0f, 0.0f, 0.0f }; + private static final float ALPHA = 0.5f; + private static final float LINE_WIDTH = 8f; + + private static boolean isInSnapshot() { + return !SharedConstants.getGameVersion().isStable(); + } + + static void init() { + if (isInSnapshot()) { + WorldRenderEvents.AFTER_TRANSLUCENT.register(SnapshotDebug::renderTest); + } + } + + private static void renderTest(WorldRenderContext wrc) { + RenderHelper.renderFilledWithBeaconBeam(wrc, new BlockPos(175, 63, -14), RED, ALPHA, true); + RenderHelper.renderLinesFromPoints(wrc, new Vec3d[] { new Vec3d(173, 66, -7.5), new Vec3d(178, 66, -7.5) }, RED, ALPHA, LINE_WIDTH, false); + RenderHelper.renderQuad(wrc, new Vec3d[] { new Vec3d(183, 66, -16), new Vec3d(183, 63, -16), new Vec3d(183, 63, -14), new Vec3d(183, 66, -14) }, RED, ALPHA, false); + RenderHelper.renderText(wrc, Text.of("Skyblocker on " + SharedConstants.getGameVersion().getName() + "!"), new Vec3d(175.5, 67.5, -7.5), false); + } +} diff --git a/src/main/java/de/hysky/skyblocker/events/HudRenderEvents.java b/src/main/java/de/hysky/skyblocker/events/HudRenderEvents.java new file mode 100644 index 00000000..13e70498 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/events/HudRenderEvents.java @@ -0,0 +1,50 @@ +package de.hysky.skyblocker.events; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.gui.DrawContext; + +/** + * HUD render events that allow for proper layering between different HUD elements. + * This should always be preferred over Fabric's {@link net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback}. + * + * Perhaps in the future this system could be PR'd to Fabric. + */ +public class HudRenderEvents { + /** + * Called after the hotbar, status bars, and experience bar have been rendered. + */ + public static final Event<HudRenderStage> AFTER_MAIN_HUD = createEventForStage(); + + /** + * Called before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. + */ + public static final Event<HudRenderStage> BEFORE_CHAT = createEventForStage(); + + /** + * Called after the entire HUD is rendered. + */ + public static final Event<HudRenderStage> LAST = createEventForStage(); + + private static Event<HudRenderStage> createEventForStage() { + return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (context, tickDelta) -> { + for (HudRenderStage listener : listeners) { + listener.onRender(context, tickDelta); + } + }); + } + + /** + * @implNote Similar to Fabric's {@link net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback} + */ + @FunctionalInterface + public interface HudRenderStage { + /** + * Called sometime during a specific HUD render stage. + * + * @param drawContext The {@link DrawContext} instance + * @param tickDelta Progress for linearly interpolating between the previous and current game state + */ + void onRender(DrawContext context, float tickDelta); + } +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/ArmorTrimMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ArmorTrimMixin.java deleted file mode 100644 index b9bdb523..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/ArmorTrimMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.hysky.skyblocker.mixin; - -import com.llamalad7.mixinextras.injector.ModifyReturnValue; -import com.llamalad7.mixinextras.sugar.Local; -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.item.CustomArmorTrims; -import de.hysky.skyblocker.utils.ItemUtils; -import de.hysky.skyblocker.utils.Utils; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.item.ItemStack; -import net.minecraft.item.trim.ArmorTrim; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; - -import java.util.Optional; - -@Mixin(ArmorTrim.class) -public class ArmorTrimMixin { - - @ModifyReturnValue(method = "getTrim", at = @At("RETURN")) - private static Optional<ArmorTrim> skyblocker$customArmorTrims(@SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<ArmorTrim> original, @Local ItemStack stack) { - if (Utils.isOnSkyblock()) { - Object2ObjectOpenHashMap<String, CustomArmorTrims.ArmorTrimId> customTrims = SkyblockerConfigManager.get().general.customArmorTrims; - String itemUuid = ItemUtils.getItemUuid(stack); - - if (customTrims.containsKey(itemUuid)) { - CustomArmorTrims.ArmorTrimId trimKey = customTrims.get(itemUuid); - return CustomArmorTrims.TRIMS_CACHE.getOrDefault(trimKey, original); - } - } - - return original; - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java deleted file mode 100644 index bf330d80..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java +++ /dev/null @@ -1,82 +0,0 @@ -package de.hysky.skyblocker.mixin; - - -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.auction.AuctionBrowserScreen; -import de.hysky.skyblocker.skyblock.auction.AuctionHouseScreenHandler; -import de.hysky.skyblocker.skyblock.auction.AuctionViewScreen; -import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; -import de.hysky.skyblocker.skyblock.item.SkyblockCraftingTableScreenHandler; -import de.hysky.skyblocker.skyblock.item.SkyblockCraftingTableScreen; -import de.hysky.skyblocker.utils.Utils; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.ingame.HandledScreens; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.screen.GenericContainerScreenHandler; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.text.Text; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(HandledScreens.Provider.class) -public interface HandledScreenProviderMixin<T extends ScreenHandler> { - @Inject(method = "open", at = @At("HEAD"), cancellable = true) - default void skyblocker$open(Text name, ScreenHandlerType<T> type, MinecraftClient client, int id, CallbackInfo ci) { - ClientPlayerEntity player = client.player; - if (player == null) return; - if (!Utils.isOnSkyblock()) return; - T screenHandler = type.create(id, player.getInventory()); - if (!(screenHandler instanceof GenericContainerScreenHandler containerScreenHandler)) return; - String nameLowercase = name.getString().toLowerCase(); - // Better party finder - if (SkyblockerConfigManager.get().general.betterPartyFinder && PartyFinderScreen.possibleInventoryNames.contains(nameLowercase)) { - if (client.currentScreen != null) { - String lowerCase = client.currentScreen.getTitle().getString().toLowerCase(); - if (lowerCase.contains("group builder")) return; - if (lowerCase.contains("select tier")) { - PartyFinderScreen.isInKuudraPartyFinder = true; - } else if (lowerCase.contains("catacombs")) { - PartyFinderScreen.isInKuudraPartyFinder = false; - } - } - if (PartyFinderScreen.isInKuudraPartyFinder) return; - client.player.currentScreenHandler = containerScreenHandler; - if (client.currentScreen instanceof PartyFinderScreen screen) { - screen.updateHandler(containerScreenHandler, name); - } else { - client.setScreen(new PartyFinderScreen(containerScreenHandler, player.getInventory(), name)); - } - - ci.cancel(); - // Fancy AH - } else if (SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && (nameLowercase.contains("auctions browser") || nameLowercase.contains("auctions: "))) { - AuctionHouseScreenHandler auctionHouseScreenHandler = AuctionHouseScreenHandler.of(containerScreenHandler, false); - client.player.currentScreenHandler = auctionHouseScreenHandler; - if (client.currentScreen instanceof AuctionBrowserScreen auctionBrowserScreen) { - auctionBrowserScreen.changeHandler(auctionHouseScreenHandler); - } else client.setScreen(new AuctionBrowserScreen(auctionHouseScreenHandler, client.player.getInventory())); - ci.cancel(); - } else if (SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && nameLowercase.contains("auction view")) { - AuctionHouseScreenHandler auctionHouseScreenHandler = AuctionHouseScreenHandler.of(containerScreenHandler, true); - client.player.currentScreenHandler = auctionHouseScreenHandler; - if (client.currentScreen instanceof AuctionViewScreen auctionViewScreen) { - auctionViewScreen.changeHandler(auctionHouseScreenHandler); - } else - client.setScreen(new AuctionViewScreen(auctionHouseScreenHandler, client.player.getInventory(), name)); - ci.cancel(); - } else if (SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && (nameLowercase.contains("confirm purchase") || nameLowercase.contains("confirm bid")) && client.currentScreen instanceof AuctionViewScreen auctionViewScreen) { - client.setScreen(auctionViewScreen.getConfirmPurchasePopup(name)); - client.player.currentScreenHandler = containerScreenHandler; - ci.cancel(); - // Fancy crafting table - } else if (SkyblockerConfigManager.get().general.fancyCraftingTable && name.getString().toLowerCase().contains("craft item")) { - SkyblockCraftingTableScreenHandler skyblockCraftingTableScreenHandler = new SkyblockCraftingTableScreenHandler(containerScreenHandler, player.getInventory()); - client.player.currentScreenHandler = skyblockCraftingTableScreenHandler; - client.setScreen(new SkyblockCraftingTableScreen(skyblockCraftingTableScreenHandler, player.getInventory(), Text.literal("Craft Item"))); - ci.cancel(); - } - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java deleted file mode 100644 index 6b49220b..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.hysky.skyblocker.mixin; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Item.class) -public abstract class ItemMixin { - @Redirect( - method = {"getItemBarColor", "getItemBarStep"}, - at = @At(value = "FIELD", target = "Lnet/minecraft/item/Item;maxDamage:I", opcode = Opcodes.GETFIELD) - ) - private int skyblocker$handlePickoDrillBar(Item item, ItemStack stack) { - return stack.getMaxDamage(); - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/ItemStackAccessor.java b/src/main/java/de/hysky/skyblocker/mixin/accessor/ItemStackAccessor.java deleted file mode 100644 index e3bd69aa..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/ItemStackAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.hysky.skyblocker.mixin.accessor; - -import net.minecraft.item.ItemStack; -import net.minecraft.text.Style; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(ItemStack.class) -public interface ItemStackAccessor { - @Accessor - static Style getLORE_STYLE() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/AbstractInventoryScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/AbstractInventoryScreenMixin.java index d0d4b9f7..53151826 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/AbstractInventoryScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/AbstractInventoryScreenMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/de/hysky/skyblocker/mixin/BatEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixins/BatEntityMixin.java index fa97e546..7ee59be1 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/BatEntityMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/BatEntityMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import net.minecraft.entity.EntityType; diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index 743f949f..0a5ebc64 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -1,7 +1,7 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.llamalad7.mixinextras.sugar.Local; import de.hysky.skyblocker.skyblock.FishingHelper; import de.hysky.skyblocker.skyblock.dungeon.DungeonScore; diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayerEntityMixin.java index 8fb2fda4..d4c930d2 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayerEntityMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.mojang.authlib.GameProfile; import de.hysky.skyblocker.config.SkyblockerConfigManager; diff --git a/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java b/src/main/java/de/hysky/skyblocker/mixins/CommandTreeS2CPacketMixin.java index 1cc1b8de..289923c8 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/CommandTreeS2CPacketMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.mojang.brigadier.tree.CommandNode; diff --git a/src/main/java/de/hysky/skyblocker/mixins/ComponentHolderMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ComponentHolderMixin.java new file mode 100644 index 00000000..8fa03cdc --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixins/ComponentHolderMixin.java @@ -0,0 +1,39 @@ +package de.hysky.skyblocker.mixins; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.CustomArmorTrims; +import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.component.ComponentHolder; +import net.minecraft.component.DataComponentType; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.item.ItemStack; +import net.minecraft.item.trim.ArmorTrim; + +@Mixin(ComponentHolder.class) +public interface ComponentHolderMixin { + + @SuppressWarnings("unchecked") + @ModifyReturnValue(method = "get", at = @At("RETURN")) + private <T> T skyblocker$customArmorTrims(T original, DataComponentType<? extends T> dataComponentType) { + if (Utils.isOnSkyblock() && ((Object) this) instanceof ItemStack stack) { + if (dataComponentType == DataComponentTypes.TRIM) { + Object2ObjectOpenHashMap<String, CustomArmorTrims.ArmorTrimId> customTrims = SkyblockerConfigManager.get().general.customArmorTrims; + String itemUuid = ItemUtils.getItemUuid(stack); + + if (customTrims.containsKey(itemUuid)) { + CustomArmorTrims.ArmorTrimId trimKey = customTrims.get(itemUuid); + return (T) CustomArmorTrims.TRIMS_CACHE.getOrDefault(trimKey, (ArmorTrim) original); + } + } + } + + return original; + } +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/DataTrackerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/DataTrackerMixin.java index d9db5dae..77bb09bb 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/DataTrackerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/DataTrackerMixin.java @@ -1,14 +1,15 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.sugar.Local; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.mixin.accessor.EndermanEntityAccessor; +import de.hysky.skyblocker.mixins.accessors.EndermanEntityAccessor; import de.hysky.skyblocker.skyblock.entity.MobGlow; import de.hysky.skyblocker.utils.Utils; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; +import net.minecraft.entity.data.DataTracked; import net.minecraft.entity.data.DataTracker; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; @@ -26,14 +27,14 @@ import java.util.Optional; public abstract class DataTrackerMixin { @Shadow @Final - private Entity trackedEntity; + private DataTracked trackedEntity; @SuppressWarnings("ConstantValue") @Inject(method = "writeUpdatedEntries", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/data/DataTracker;copyToFrom(Lnet/minecraft/entity/data/DataTracker$Entry;Lnet/minecraft/entity/data/DataTracker$SerializedEntry;)V")) private <T> void skyblocker$onWriteUpdatedEntries(CallbackInfo ci, @Local DataTracker.Entry<T> entry, @Local DataTracker.SerializedEntry<T> serializedEntry) { if (Utils.isInTheEnd() && SkyblockerConfigManager.get().slayer.endermanSlayer.enableYangGlyphsNotification && entry.getData() == EndermanEntityAccessor.getCARRIED_BLOCK() && entry.get() instanceof Optional<?> value && value.isPresent() && value.get() instanceof BlockState state && state.isOf(Blocks.BEACON) && ((Optional<?>) serializedEntry.value()).isEmpty()) { MinecraftClient client = MinecraftClient.getInstance(); - if (MobGlow.getArmorStands(trackedEntity).stream().anyMatch(armorStand -> armorStand.getName().getString().contains(client.getSession().getUsername()))) { + if (trackedEntity instanceof Entity entity && MobGlow.getArmorStands(entity).stream().anyMatch(armorStand -> armorStand.getName().getString().contains(client.getSession().getUsername()))) { client.inGameHud.setTitleTicks(5, 20, 10); client.inGameHud.setTitle(Text.literal("Yang Glyph!").formatted(Formatting.RED)); client.player.playSound(SoundEvents.BLOCK_NOTE_BLOCK_PLING.value(), 100f, 0.1f); @@ -41,7 +42,6 @@ public abstract class DataTrackerMixin { } } - @SuppressWarnings({"MixinAnnotationTarget", "UnresolvedMixinReference"}) @Inject(method = "copyToFrom", at = @At(value = "NEW", target = "Ljava/lang/IllegalStateException;"), cancellable = true) public void skyblocker$ignoreInvalidDataExceptions(CallbackInfo ci) { //These exceptions cause annoying small lag spikes for some reason diff --git a/src/main/java/de/hysky/skyblocker/mixin/DrawContextMixin.java b/src/main/java/de/hysky/skyblocker/mixins/DrawContextMixin.java index b33a8b23..7964b114 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/DrawContextMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/DrawContextMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; @@ -36,10 +36,10 @@ public abstract class DrawContextMixin { if (!SkyblockerConfigManager.get().general.itemInfoDisplay.attributeShardInfo) return; if (Utils.isOnSkyblock()) { - NbtCompound extraAttributes = ItemUtils.getExtraAttributes(stack); + NbtCompound customData = ItemUtils.getCustomData(stack); - if (extraAttributes != null && extraAttributes.getString(ItemUtils.ID).equals("ATTRIBUTE_SHARD")) { - NbtCompound attributesTag = extraAttributes.getCompound("attributes"); + if (ItemUtils.getItemId(stack).equals("ATTRIBUTE_SHARD")) { + NbtCompound attributesTag = customData.getCompound("attributes"); String[] attributes = attributesTag.getKeys().toArray(String[]::new); if (attributes.length != 0) { @@ -65,7 +65,7 @@ public abstract class DrawContextMixin { @ModifyExpressionValue(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/ItemCooldownManager;getCooldownProgress(Lnet/minecraft/item/Item;F)F")) - private float skyblocker$modifyItemCooldown(float cooldownProgress, @Local ItemStack stack) { + private float skyblocker$modifyItemCooldown(float cooldownProgress, @Local(argsOnly = true) ItemStack stack) { return Utils.isOnSkyblock() && ItemCooldowns.isOnCooldown(stack) ? ItemCooldowns.getItemCooldownEntry(stack).getRemainingCooldownPercent() : cooldownProgress; } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java b/src/main/java/de/hysky/skyblocker/mixins/DyedColorComponentMixin.java index 64f6a452..0fd4f8a0 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/DyedColorComponentMixin.java @@ -1,27 +1,32 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.sugar.Local; + import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.item.CustomArmorAnimatedDyes; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; -import net.minecraft.item.DyeableItem; +import net.minecraft.component.type.DyedColorComponent; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.ColorHelper; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -@Mixin(DyeableItem.class) -public interface DyeableItemMixin { +@Mixin(DyedColorComponent.class) +public record DyedColorComponentMixin() { + @ModifyReturnValue(method = "getColor", at = @At("RETURN")) - private int skyblocker$customDyeColor(int originalColor, ItemStack stack) { + private static int skyblocker$customDyeColor(int originalColor, @Local(argsOnly = true) ItemStack stack) { if (Utils.isOnSkyblock()) { String itemUuid = ItemUtils.getItemUuid(stack); if (SkyblockerConfigManager.get().general.customAnimatedDyes.containsKey(itemUuid)) { - return CustomArmorAnimatedDyes.animateColorTransition(SkyblockerConfigManager.get().general.customAnimatedDyes.get(itemUuid)); + return ColorHelper.Argb.fullAlpha(CustomArmorAnimatedDyes.animateColorTransition(SkyblockerConfigManager.get().general.customAnimatedDyes.get(itemUuid))); } - return SkyblockerConfigManager.get().general.customDyeColors.getOrDefault(itemUuid, originalColor); + return ColorHelper.Argb.fullAlpha(SkyblockerConfigManager.get().general.customDyeColors.getOrDefault(itemUuid, originalColor)); } return originalColor; diff --git a/src/main/java/de/hysky/skyblocker/mixin/EntityRenderDispatcherMixin.java b/src/main/java/de/hysky/skyblocker/mixins/EntityRenderDispatcherMixin.java index 5cf88588..79d13068 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/EntityRenderDispatcherMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import de.hysky.skyblocker.debug.Debug; @@ -13,6 +13,6 @@ import org.spongepowered.asm.mixin.injection.At; public class EntityRenderDispatcherMixin { @ModifyExpressionValue(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;isInvisible()Z", ordinal = 1)) private <E extends Entity> boolean skyblocker$armorStandHitboxVisible(boolean invisible, E entity) { - return (!(entity instanceof ArmorStandEntity) || !Utils.isOnHypixel() || !Debug.debugEnabled()) && invisible; + return (!(entity instanceof ArmorStandEntity) || !Utils.isOnHypixel() || !Debug.debugEnabled() || !Debug.shouldShowInvisibleArmorStands()) && invisible; } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/FarmlandBlockMixin.java b/src/main/java/de/hysky/skyblocker/mixins/FarmlandBlockMixin.java index dfa886c4..4c981d9a 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/FarmlandBlockMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/FarmlandBlockMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import de.hysky.skyblocker.config.SkyblockerConfigManager; @@ -30,7 +30,6 @@ public abstract class FarmlandBlockMixin extends Block { return Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.hitbox.oldFarmlandHitbox ? VoxelShapes.fullCube() : original; } - @SuppressWarnings("deprecation") @Override public VoxelShape getCullingShape(BlockState state, BlockView world, BlockPos pos) { return SHAPE; diff --git a/src/main/java/de/hysky/skyblocker/mixin/GenericContainerScreenHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java index a7843ba2..f75af09a 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/GenericContainerScreenHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; diff --git a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java index 7d2f849e..9ae25d85 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.systems.RenderSystem; @@ -97,7 +97,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen public void skyblocker$keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) { if (this.client != null && this.focusedSlot != null && keyCode != 256) { //wiki lookup - if (!this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && WikiLookup.wikiLookup.matchesKey(keyCode, scanCode)) { + if (!this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && WikiLookup.wikiLookup.matchesKey(keyCode, scanCode) && client.player != null) { WikiLookup.openWiki(this.focusedSlot, client.player); } //item protection @@ -165,6 +165,8 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen /** * The naming of this method in yarn is half true, its mostly to handle slot/item interactions (which are mouse or keyboard clicks) * For example, using the drop key bind while hovering over an item will invoke this method to drop the players item + * + * @implNote This runs before {@link ScreenHandler#onSlotClick(int, int, SlotActionType, net.minecraft.entity.player.PlayerEntity)} */ @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;clickSlot(IIILnet/minecraft/screen/slot/SlotActionType;Lnet/minecraft/entity/player/PlayerEntity;)V"), cancellable = true) private void skyblocker$onSlotClick(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { @@ -201,11 +203,11 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen return; } if (this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) { - VisitorHelper.onSlotClick(slot, slotId, title); + VisitorHelper.onSlotClick(slot, slotId, title, genericContainerScreenHandler.getSlot(13).getStack()); // Prevent selling to NPC shops ItemStack sellStack = this.handler.slots.get(49).getStack(); - if (sellStack.getName().getString().equals("Sell Item") || ItemUtils.getNbtTooltip(sellStack, text -> text.contains("buyback")) != null) { + if (sellStack.getName().getString().equals("Sell Item") || ItemUtils.getLoreLineIf(sellStack, text -> text.contains("buyback")) != null) { if (slotId != 49 && ItemProtection.isItemProtected(stack)) { ci.cancel(); return; @@ -213,21 +215,32 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen } } + if (currentSolver != null) { + SkyblockerMod.getInstance().containerSolverManager.onSlotClick(slotId, stack); + } + // Experiment Solvers if (currentSolver instanceof ExperimentSolver experimentSolver && experimentSolver.getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) { - if (experimentSolver instanceof ChronomatronSolver chronomatronSolver) { - Item item = chronomatronSolver.getChronomatronSlots().get(chronomatronSolver.getChronomatronCurrentOrdinal()); - if ((stack.isOf(item) || ChronomatronSolver.TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) && chronomatronSolver.incrementChronomatronCurrentOrdinal() >= chronomatronSolver.getChronomatronSlots().size()) { - chronomatronSolver.setState(ExperimentSolver.State.END); + switch (experimentSolver) { + case ChronomatronSolver chronomatronSolver -> { + Item item = chronomatronSolver.getChronomatronSlots().get(chronomatronSolver.getChronomatronCurrentOrdinal()); + if ((stack.isOf(item) || ChronomatronSolver.TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) && chronomatronSolver.incrementChronomatronCurrentOrdinal() >= chronomatronSolver.getChronomatronSlots().size()) { + chronomatronSolver.setState(ExperimentSolver.State.END); + } + } + + case SuperpairsSolver superpairsSolver -> { + superpairsSolver.setSuperpairsPrevClickedSlot(slot.getIndex()); + superpairsSolver.setSuperpairsCurrentSlot(ItemStack.EMPTY); } - } else if (experimentSolver instanceof SuperpairsSolver superpairsSolver) { - superpairsSolver.setSuperpairsPrevClickedSlot(slot.getIndex()); - superpairsSolver.setSuperpairsCurrentSlot(ItemStack.EMPTY); - } else if (experimentSolver instanceof UltrasequencerSolver ultrasequencerSolver && slot.getIndex() == ultrasequencerSolver.getUltrasequencerNextSlot()) { - int count = ultrasequencerSolver.getSlots().get(ultrasequencerSolver.getUltrasequencerNextSlot()).getCount() + 1; - ultrasequencerSolver.getSlots().entrySet().stream().filter(entry -> entry.getValue().getCount() == count).findAny().map(Map.Entry::getKey).ifPresentOrElse(ultrasequencerSolver::setUltrasequencerNextSlot, () -> ultrasequencerSolver.setState(ExperimentSolver.State.END)); + + case UltrasequencerSolver ultrasequencerSolver when slot.getIndex() == ultrasequencerSolver.getUltrasequencerNextSlot() -> { + int count = ultrasequencerSolver.getSlots().get(ultrasequencerSolver.getUltrasequencerNextSlot()).getCount() + 1; + ultrasequencerSolver.getSlots().entrySet().stream().filter(entry -> entry.getValue().getCount() == count).findAny().map(Map.Entry::getKey).ifPresentOrElse(ultrasequencerSolver::setUltrasequencerNextSlot, () -> ultrasequencerSolver.setState(ExperimentSolver.State.END)); + } + + default -> { /*Do Nothing*/ } } - return; } } diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java new file mode 100644 index 00000000..da87c2a3 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java @@ -0,0 +1,99 @@ +package de.hysky.skyblocker.mixins; + + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.auction.AuctionBrowserScreen; +import de.hysky.skyblocker.skyblock.auction.AuctionHouseScreenHandler; +import de.hysky.skyblocker.skyblock.auction.AuctionViewScreen; +import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; +import de.hysky.skyblocker.skyblock.item.SkyblockCraftingTableScreenHandler; +import de.hysky.skyblocker.skyblock.item.SkyblockCraftingTableScreen; +import de.hysky.skyblocker.utils.Utils; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(HandledScreens.Provider.class) +public interface HandledScreenProviderMixin<T extends ScreenHandler> { + + @Inject(method = "open", at = @At("HEAD"), cancellable = true) + default void skyblocker$open(Text name, ScreenHandlerType<T> type, MinecraftClient client, int id, CallbackInfo ci) { + ClientPlayerEntity player = client.player; + if (player == null) return; + if (!Utils.isOnSkyblock()) return; + T screenHandler = type.create(id, player.getInventory()); + String nameLowercase = name.getString().toLowerCase(); + + switch (screenHandler) { + // Better party finder + case GenericContainerScreenHandler ignored when SkyblockerConfigManager.get().general.betterPartyFinder && nameLowercase.contains("select tier") -> PartyFinderScreen.isInKuudraPartyFinder = true; + case GenericContainerScreenHandler ignored when SkyblockerConfigManager.get().general.betterPartyFinder && nameLowercase.contains("catacombs") -> PartyFinderScreen.isInKuudraPartyFinder = false; + + case GenericContainerScreenHandler containerScreenHandler when SkyblockerConfigManager.get().general.betterPartyFinder && PartyFinderScreen.possibleInventoryNames.contains(nameLowercase) -> { + if (client.currentScreen != null) { + String lowerCase = client.currentScreen.getTitle().getString().toLowerCase(); + if (lowerCase.contains("group builder")) return; + } + + if (PartyFinderScreen.isInKuudraPartyFinder) return; + client.player.currentScreenHandler = containerScreenHandler; + + switch (client.currentScreen) { + case PartyFinderScreen screen -> screen.updateHandler(containerScreenHandler, name); + case null, default -> client.setScreen(new PartyFinderScreen(containerScreenHandler, player.getInventory(), name)); + } + + ci.cancel(); + } + + // Fancy AH + case GenericContainerScreenHandler containerScreenHandler when SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && (nameLowercase.contains("auctions browser") || nameLowercase.contains("auctions: ")) -> { + AuctionHouseScreenHandler auctionHouseScreenHandler = AuctionHouseScreenHandler.of(containerScreenHandler, false); + client.player.currentScreenHandler = auctionHouseScreenHandler; + + switch (client.currentScreen) { + case AuctionBrowserScreen auctionBrowserScreen -> auctionBrowserScreen.changeHandler(auctionHouseScreenHandler); + case null, default -> client.setScreen(new AuctionBrowserScreen(auctionHouseScreenHandler, client.player.getInventory())); + } + + ci.cancel(); + } + + case GenericContainerScreenHandler containerScreenHandler when SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && nameLowercase.contains("auction view") -> { + AuctionHouseScreenHandler auctionHouseScreenHandler = AuctionHouseScreenHandler.of(containerScreenHandler, true); + client.player.currentScreenHandler = auctionHouseScreenHandler; + + switch (client.currentScreen) { + case AuctionViewScreen auctionViewScreen -> auctionViewScreen.changeHandler(auctionHouseScreenHandler); + case null, default -> client.setScreen(new AuctionViewScreen(auctionHouseScreenHandler, client.player.getInventory(), name)); + } + + ci.cancel(); + } + + case GenericContainerScreenHandler containerScreenHandler when SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && (nameLowercase.contains("confirm purchase") || nameLowercase.contains("confirm bid")) && client.currentScreen instanceof AuctionViewScreen auctionViewScreen -> { + client.setScreen(auctionViewScreen.getConfirmPurchasePopup(name)); + client.player.currentScreenHandler = containerScreenHandler; + ci.cancel(); + } + + // Fancy crafting table + case GenericContainerScreenHandler containerScreenHandler when SkyblockerConfigManager.get().general.fancyCraftingTable && name.getString().toLowerCase().contains("craft item") -> { + SkyblockCraftingTableScreenHandler skyblockCraftingTableScreenHandler = new SkyblockCraftingTableScreenHandler(containerScreenHandler, player.getInventory()); + client.player.currentScreenHandler = skyblockCraftingTableScreenHandler; + client.setScreen(new SkyblockCraftingTableScreen(skyblockCraftingTableScreenHandler, player.getInventory(), Text.literal("Craft Item"))); + ci.cancel(); + } + + case null, default -> {} + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java b/src/main/java/de/hysky/skyblocker/mixins/InGameHudMixin.java index b0970b4b..897b98b3 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/InGameHudMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; @@ -6,10 +6,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars; -import de.hysky.skyblocker.skyblock.dungeon.DungeonMap; -import de.hysky.skyblocker.skyblock.dungeon.DungeonScore; -import de.hysky.skyblocker.skyblock.dungeon.DungeonScoreHUD; -import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; +import de.hysky.skyblocker.events.HudRenderEvents; import de.hysky.skyblocker.skyblock.item.HotbarSlotLock; import de.hysky.skyblocker.skyblock.item.ItemCooldowns; import de.hysky.skyblocker.skyblock.item.ItemProtection; @@ -19,6 +16,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.LayeredDrawer; import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; @@ -34,6 +32,8 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Environment(EnvType.CLIENT) @@ -51,16 +51,15 @@ public abstract class InGameHudMixin { private final FancyStatusBars statusBars = new FancyStatusBars(); @Shadow - private int scaledHeight; - @Shadow - private int scaledWidth; + @Final + private MinecraftClient client; @Shadow @Final - private MinecraftClient client; + private LayeredDrawer layeredDrawer; @Inject(method = "renderHotbar", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;renderHotbarItem(Lnet/minecraft/client/gui/DrawContext;IIFLnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/item/ItemStack;I)V", ordinal = 0)) - public void skyblocker$renderHotbarItemLockOrRarityBg(float tickDelta, DrawContext context, CallbackInfo ci, @Local(ordinal = 4, name = "m") int index, @Local(ordinal = 5, name = "n") int x, @Local(ordinal = 6, name = "o") int y, @Local PlayerEntity player) { + public void skyblocker$renderHotbarItemLockOrRarityBg(CallbackInfo ci, @Local(argsOnly = true) DrawContext context, @Local(ordinal = 4, name = "m") int index, @Local(ordinal = 5, name = "n") int x, @Local(ordinal = 6, name = "o") int y, @Local PlayerEntity player) { if (Utils.isOnSkyblock()) { // slot lock if (SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) ItemRarityBackgrounds.tryDraw(player.getInventory().main.get(index), context, x, y); @@ -70,7 +69,7 @@ public abstract class InGameHudMixin { RenderSystem.disableBlend(); } //item protection - if (ItemProtection.isItemProtected(player.getInventory().main.get(index))){ + if (ItemProtection.isItemProtected(player.getInventory().main.get(index))) { RenderSystem.enableBlend(); context.drawTexture(ITEM_PROTECTION, x, y, 0, 0, 16, 16, 16, 16); RenderSystem.disableBlend(); @@ -78,7 +77,7 @@ public abstract class InGameHudMixin { } } - @Inject(method = "renderExperienceBar", at = @At("HEAD"), cancellable = true) + @Inject(method = { "renderExperienceBar", "renderExperienceLevel" }, at = @At("HEAD"), cancellable = true) private void skyblocker$renderExperienceBar(CallbackInfo ci) { if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.bars.enableBars && !Utils.isInTheRift()) ci.cancel(); @@ -88,13 +87,8 @@ public abstract class InGameHudMixin { private void skyblocker$renderStatusBars(DrawContext context, CallbackInfo ci) { if (!Utils.isOnSkyblock()) return; - if (statusBars.render(context, scaledWidth, scaledHeight)) + if (statusBars.render(context, context.getScaledWindowWidth(), context.getScaledWindowHeight())) ci.cancel(); - - if (Utils.isInDungeons() && DungeonScore.isDungeonStarted()) { - if (SkyblockerConfigManager.get().locations.dungeons.enableMap && !DungeonManager.isInBoss()) DungeonMap.render(context.getMatrices()); - if (SkyblockerConfigManager.get().locations.dungeons.dungeonScore.enableScoreHUD) DungeonScoreHUD.render(context); - } } @Inject(method = "renderMountHealth", at = @At("HEAD"), cancellable = true) @@ -126,4 +120,25 @@ public abstract class InGameHudMixin { ci.cancel(); } } + + @ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)) + private LayeredDrawer.Layer skyblocker$afterMainHud(LayeredDrawer.Layer mainHudLayer) { + return (context, tickDelta) -> { + mainHudLayer.render(context, tickDelta); + HudRenderEvents.AFTER_MAIN_HUD.invoker().onRender(context, tickDelta); + }; + } + + @ModifyArg(method = "<init>", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) + private LayeredDrawer.Layer skyblocker$beforeChat(LayeredDrawer.Layer beforeChatLayer) { + return (context, tickDelta) -> { + HudRenderEvents.BEFORE_CHAT.invoker().onRender(context, tickDelta); + beforeChatLayer.render(context, tickDelta); + }; + } + + @Inject(method = "<init>", at = @At("TAIL")) + private void skyblocker$afterDrawersInitialized(CallbackInfo ci) { + this.layeredDrawer.addLayer(HudRenderEvents.LAST.invoker()::onRender); + } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/InGameOverlayRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/InGameOverlayRendererMixin.java index 4775ce2d..c7704558 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/InGameOverlayRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/InGameOverlayRendererMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.config.SkyblockerConfigManager; import net.minecraft.client.gui.hud.InGameOverlayRenderer; diff --git a/src/main/java/de/hysky/skyblocker/mixin/InventoryScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/InventoryScreenMixin.java index 8e6b9230..0d833c22 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/InventoryScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/InventoryScreenMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import de.hysky.skyblocker.config.SkyblockerConfigManager; diff --git a/src/main/java/de/hysky/skyblocker/mixin/ItemStackMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java index 2a1ed125..3ebfc439 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ItemStackMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java @@ -1,17 +1,20 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.ints.IntIntPair; +import net.minecraft.component.type.ItemEnchantmentsComponent; import net.minecraft.item.ItemStack; +import net.minecraft.item.TooltipAppender; import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ItemStack.class) @@ -35,6 +38,11 @@ public abstract class ItemStackMixin { return original; } + @ModifyVariable(method = "appendTooltip", at = @At("STORE")) + private TooltipAppender skyblocker$hideVanillaEnchants(TooltipAppender original) { + return Utils.isOnSkyblock() && original instanceof ItemEnchantmentsComponent component ? component.withShowInTooltip(false) : original; + } + /** * Updates the durability of this item stack every tick when in the inventory. */ @@ -72,6 +80,11 @@ public abstract class ItemStackMixin { return skyblocker$shouldProcess() || original; } + @ModifyReturnValue(method = "isDamaged", at = @At("RETURN")) + private boolean skyblocker$handleDamaged(boolean original) { + return skyblocker$shouldProcess() || original; + } + @Unique private boolean skyblocker$shouldProcess() { return Utils.isOnSkyblock() && SkyblockerConfigManager.get().locations.dwarvenMines.enableDrillFuel && ItemUtils.hasCustomDurability((ItemStack) (Object) this); diff --git a/src/main/java/de/hysky/skyblocker/mixin/LeverBlockMixin.java b/src/main/java/de/hysky/skyblocker/mixins/LeverBlockMixin.java index a1cfe44b..eb8c6bf6 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/LeverBlockMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/LeverBlockMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.dungeon.OldLever; import de.hysky.skyblocker.utils.Utils; diff --git a/src/main/java/de/hysky/skyblocker/mixin/LivingEntityRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/LivingEntityRendererMixin.java index cf927f0c..60fa7dec 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/LivingEntityRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/LivingEntityRendererMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import de.hysky.skyblocker.debug.Debug; @@ -13,6 +13,6 @@ import org.spongepowered.asm.mixin.injection.At; public class LivingEntityRendererMixin { @ModifyExpressionValue(method = "render(Lnet/minecraft/entity/LivingEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/LivingEntityRenderer;isVisible(Lnet/minecraft/entity/LivingEntity;)Z")) private <T extends LivingEntity> boolean skyblocker$armorStandVisible(boolean visible, T entity) { - return entity instanceof ArmorStandEntity && Utils.isOnHypixel() && Debug.debugEnabled() || visible; + return entity instanceof ArmorStandEntity && Utils.isOnHypixel() && Debug.debugEnabled() && Debug.shouldShowInvisibleArmorStands() || visible; } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/MinecraftClientMixin.java b/src/main/java/de/hysky/skyblocker/mixins/MinecraftClientMixin.java index dd671b2e..b04f958f 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/MinecraftClientMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/MinecraftClientMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.item.HotbarSlotLock; import de.hysky.skyblocker.skyblock.item.ItemProtection; @@ -42,14 +42,12 @@ public abstract class MinecraftClientMixin { //Remove Downloading Terrain Screen and Reconfiguring Screen @ModifyVariable(at = @At("HEAD"), method = "setScreen", ordinal = 0, argsOnly = true) public Screen modifySetScreen(Screen screen) { - if (Utils.isOnSkyblock()) { - if (screen instanceof DownloadingTerrainScreen) { - return null; - } else if (screen instanceof ReconfiguringScreen && this.getNetworkHandler() != null) { - return new ReconfiguringPlaceholderScreen(this.getNetworkHandler().getConnection()); - } - } - return screen; + return switch (screen) { + case DownloadingTerrainScreen _s when Utils.isOnHypixel() -> null; + case ReconfiguringScreen _s when Utils.isOnHypixel() && this.getNetworkHandler() != null -> new ReconfiguringPlaceholderScreen(this.getNetworkHandler().getConnection()); + + case null, default -> screen; + }; } @ModifyArg(method = "joinWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;reset(Lnet/minecraft/client/gui/screen/Screen;)V"), index = 0) diff --git a/src/main/java/de/hysky/skyblocker/mixin/MouseMixin.java b/src/main/java/de/hysky/skyblocker/mixins/MouseMixin.java index 33c3f487..fb156af2 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/MouseMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/MouseMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import de.hysky.skyblocker.skyblock.garden.LowerSensitivity; diff --git a/src/main/java/de/hysky/skyblocker/mixin/PlayerInventoryMixin.java b/src/main/java/de/hysky/skyblocker/mixins/PlayerInventoryMixin.java index 4795a28b..35747267 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/PlayerInventoryMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/PlayerInventoryMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/de/hysky/skyblocker/mixin/PlayerListHudMixin.java b/src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java index 88ca7c67..a1a9116c 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/PlayerListHudMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster; import de.hysky.skyblocker.config.SkyblockerConfigManager; diff --git a/src/main/java/de/hysky/skyblocker/mixin/PlayerSkinProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinProviderMixin.java index dd38e15a..9cd2ef14 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/PlayerSkinProviderMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinProviderMixin.java @@ -1,10 +1,10 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import de.hysky.skyblocker.utils.Utils; diff --git a/src/main/java/de/hysky/skyblocker/mixin/PlayerSkinTextureMixin.java b/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java index 50f478b8..f9e2c8cd 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/PlayerSkinTextureMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.item.PlayerHeadHashCache; diff --git a/src/main/java/de/hysky/skyblocker/mixin/RenderFishMixin.java b/src/main/java/de/hysky/skyblocker/mixins/RenderFishMixin.java index e74bbaea..71e7f56f 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/RenderFishMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/RenderFishMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.config.SkyblockerConfigManager; diff --git a/src/main/java/de/hysky/skyblocker/mixin/ScoreboardMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ScoreboardMixin.java index 2cfb658a..94b39c0c 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ScoreboardMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ScoreboardMixin.java @@ -1,6 +1,6 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import de.hysky.skyblocker.utils.Utils; import net.minecraft.scoreboard.Scoreboard; import org.slf4j.Logger; diff --git a/src/main/java/de/hysky/skyblocker/mixin/SocialInteractionsPlayerListWidgetMixin.java b/src/main/java/de/hysky/skyblocker/mixins/SocialInteractionsPlayerListWidgetMixin.java index cad7cf38..121e3045 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/SocialInteractionsPlayerListWidgetMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/SocialInteractionsPlayerListWidgetMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import java.util.Map; diff --git a/src/main/java/de/hysky/skyblocker/mixin/WindowMixin.java b/src/main/java/de/hysky/skyblocker/mixins/WindowMixin.java index 481a70a6..d9df4b74 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/WindowMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/WindowMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars; import net.minecraft.client.util.Window; diff --git a/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java index a24daa80..2959d4b5 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/WorldRendererMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import de.hysky.skyblocker.skyblock.dungeon.LividColor; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/de/hysky/skyblocker/mixin/YggdrasilMinecraftSessionServiceMixin.java b/src/main/java/de/hysky/skyblocker/mixins/YggdrasilMinecraftSessionServiceMixin.java index 47c8780f..17dbbb71 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/YggdrasilMinecraftSessionServiceMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/YggdrasilMinecraftSessionServiceMixin.java @@ -1,10 +1,10 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; import de.hysky.skyblocker.utils.Utils; diff --git a/src/main/java/de/hysky/skyblocker/mixin/YggdrasilServicesKeyInfoMixin.java b/src/main/java/de/hysky/skyblocker/mixins/YggdrasilServicesKeyInfoMixin.java index 78c4bac1..12621894 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/YggdrasilServicesKeyInfoMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/YggdrasilServicesKeyInfoMixin.java @@ -1,6 +1,6 @@ -package de.hysky.skyblocker.mixin; +package de.hysky.skyblocker.mixins; -import com.llamalad7.mixinextras.injector.WrapWithCondition; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.mojang.authlib.yggdrasil.YggdrasilServicesKeyInfo; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/BeaconBlockEntityRendererInvoker.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/BeaconBlockEntityRendererInvoker.java index e470cdae..833cfc22 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/BeaconBlockEntityRendererInvoker.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/BeaconBlockEntityRendererInvoker.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.BeaconBlockEntityRenderer; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/DrawContextInvoker.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/DrawContextInvoker.java index 9c14fdc6..7a04630d 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/DrawContextInvoker.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/DrawContextInvoker.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/EndermanEntityAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/EndermanEntityAccessor.java index b7bcd95c..4dfed6dc 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/EndermanEntityAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/EndermanEntityAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.block.BlockState; import net.minecraft.entity.data.TrackedData; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/FrustumInvoker.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/FrustumInvoker.java index dd4f5ef1..e4d04dde 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/FrustumInvoker.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/FrustumInvoker.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.render.Frustum; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/HandledScreenAccessor.java index 5b84072d..447031d4 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/HandledScreenAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.screen.ScreenHandler; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/MessageHandlerAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/MessageHandlerAccessor.java index 6e5793e3..bf4f9bae 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/MessageHandlerAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/MessageHandlerAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.network.message.MessageHandler; import net.minecraft.text.Text; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/PlayerListHudAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/PlayerListHudAccessor.java index c982249a..d1fd1c46 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/PlayerListHudAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/PlayerListHudAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.gui.hud.PlayerListHud; import net.minecraft.client.network.PlayerListEntry; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/RecipeBookWidgetAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/RecipeBookWidgetAccessor.java index 30aad00c..555a0d8a 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/RecipeBookWidgetAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/RecipeBookWidgetAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget; import net.minecraft.client.gui.widget.TextFieldWidget; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/ScreenAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/ScreenAccessor.java index c0196e5f..c3544302 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/ScreenAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/ScreenAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/SkullBlockEntityAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/SkullBlockEntityAccessor.java index dfe544bc..34c196b3 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/SkullBlockEntityAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/SkullBlockEntityAccessor.java @@ -1,7 +1,8 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import com.mojang.authlib.GameProfile; import net.minecraft.block.entity.SkullBlockEntity; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; @@ -11,7 +12,7 @@ import java.util.concurrent.CompletableFuture; @Mixin(SkullBlockEntity.class) public interface SkullBlockEntityAccessor { @Invoker - static CompletableFuture<Optional<GameProfile>> invokeFetchProfile(String name) { + static CompletableFuture<Optional<GameProfile>> invokeFetchProfileByName(String name) { throw new UnsupportedOperationException(); } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/SlotAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/SlotAccessor.java index ef11006c..7c261458 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/SlotAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/SlotAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import net.minecraft.screen.slot.Slot; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/WorldRendererAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/WorldRendererAccessor.java index f1b3158d..e52b1c85 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/WorldRendererAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/WorldRendererAccessor.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.accessor; +package de.hysky.skyblocker.mixins.accessors; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/main/java/de/hysky/skyblocker/mixin/discordipc/ConnectionMixin.java b/src/main/java/de/hysky/skyblocker/mixins/discordipc/ConnectionMixin.java index 47f1cadc..79a93e69 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/discordipc/ConnectionMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/discordipc/ConnectionMixin.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.mixin.discordipc; +package de.hysky.skyblocker.mixins.discordipc; import de.hysky.skyblocker.utils.discord.DiscordRPCManager; import meteordevelopment.discordipc.DiscordIPC; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java index 5cdca216..e04a30ef 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java @@ -3,10 +3,11 @@ package de.hysky.skyblocker.skyblock; import com.google.gson.JsonObject; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.mixin.accessor.HandledScreenAccessor; -import de.hysky.skyblocker.mixin.accessor.ScreenAccessor; +import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; +import de.hysky.skyblocker.mixins.accessors.ScreenAccessor; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.longs.LongBooleanPair; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; @@ -15,7 +16,6 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.item.TooltipContext; import net.minecraft.item.ItemStack; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.slot.Slot; @@ -206,7 +206,7 @@ public class ChestValue { * Searches for a specific string of characters in the name and lore of an item */ private static String searchLoreFor(ItemStack stack, MinecraftClient client, String searchString) { - return stack.getTooltip(client.player, TooltipContext.BASIC).stream().map(Text::getString).filter(line -> line.contains(searchString)).findAny().orElse(null); + return ItemUtils.getLoreLineIf(stack, line -> line.contains(searchString)); } static Text getProfitText(long profit, boolean hasIncompleteData) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java b/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java index c3483102..c31e2107 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java @@ -21,6 +21,7 @@ public class StatusBarTracker { private int defense = 0; public void init() { + ClientReceiveMessageEvents.ALLOW_GAME.register(this::allowOverlayMessage); ClientReceiveMessageEvents.MODIFY_GAME.register(this::onOverlayMessage); } @@ -65,6 +66,11 @@ public class StatusBarTracker { return str; } + private boolean allowOverlayMessage(Text text, boolean overlay) { + onOverlayMessage(text, overlay); + return true; + } + private Text onOverlayMessage(Text text, boolean overlay) { if (!overlay || !Utils.isOnSkyblock() || !SkyblockerConfigManager.get().general.bars.enableBars || Utils.isInTheRift()) { return text; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java index e572d9dc..f7f9836c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java @@ -9,6 +9,7 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.hit.BlockHitResult; @@ -27,7 +28,7 @@ public class TeleportOverlay { if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.teleportOverlay.enableTeleportOverlays && client.player != null && client.world != null) { ItemStack heldItem = client.player.getMainHandStack(); String itemId = ItemTooltip.getInternalNameFromNBT(heldItem, true); - NbtCompound extraAttributes = ItemUtils.getExtraAttributes(heldItem); + NbtCompound customData = ItemUtils.getCustomData(heldItem); if (itemId != null) { switch (itemId) { @@ -42,20 +43,20 @@ public class TeleportOverlay { } } case "ASPECT_OF_THE_END", "ASPECT_OF_THE_VOID" -> { - if (SkyblockerConfigManager.get().general.teleportOverlay.enableEtherTransmission && client.options.sneakKey.isPressed() && extraAttributes != null && extraAttributes.getInt("ethermerge") == 1) { - render(wrc, extraAttributes, 57); + if (SkyblockerConfigManager.get().general.teleportOverlay.enableEtherTransmission && client.options.sneakKey.isPressed() && customData != null && customData.getInt("ethermerge") == 1) { + render(wrc, customData, 57); } else if (SkyblockerConfigManager.get().general.teleportOverlay.enableInstantTransmission) { - render(wrc, extraAttributes, 8); + render(wrc, customData, 8); } } case "ETHERWARP_CONDUIT" -> { if (SkyblockerConfigManager.get().general.teleportOverlay.enableEtherTransmission) { - render(wrc, extraAttributes, 57); + render(wrc, customData, 57); } } case "SINSEEKER_SCYTHE" -> { if (SkyblockerConfigManager.get().general.teleportOverlay.enableSinrecallTransmission) { - render(wrc, extraAttributes, 4); + render(wrc, customData, 4); } } case "NECRON_BLADE", "ASTRAEA", "HYPERION", "SCYLLA", "VALKYRIE" -> { @@ -71,8 +72,8 @@ public class TeleportOverlay { /** * Renders the teleport overlay with a given base range and the tuned transmission stat. */ - private static void render(WorldRenderContext wrc, NbtCompound extraAttributes, int baseRange) { - render(wrc, extraAttributes != null && extraAttributes.contains("tuned_transmission") ? baseRange + extraAttributes.getInt("tuned_transmission") : baseRange); + private static void render(WorldRenderContext wrc, NbtCompound customData, int baseRange) { + render(wrc, customData != null && customData.contains("tuned_transmission") ? baseRange + customData.getInt("tuned_transmission") : baseRange); } /** @@ -83,7 +84,7 @@ public class TeleportOverlay { private static void render(WorldRenderContext wrc, int range) { if (client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.BLOCK && client.crosshairTarget instanceof BlockHitResult blockHitResult && client.crosshairTarget.squaredDistanceTo(client.player) < range * range) { render(wrc, blockHitResult); - } else if (client.interactionManager != null && range > client.interactionManager.getReachDistance()) { + } else if (client.interactionManager != null && range > client.player.getAttributeInstance(EntityAttributes.PLAYER_BLOCK_INTERACTION_RANGE).getValue()) { @SuppressWarnings("DataFlowIssue") HitResult result = client.player.raycast(range, wrc.tickDelta(), false); if (result.getType() == HitResult.Type.BLOCK && result instanceof BlockHitResult blockHitResult) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java index 8862185f..a44a3102 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java @@ -20,7 +20,7 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.arg import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; /** - * the mixin {@link de.hysky.skyblocker.mixin.CommandTreeS2CPacketMixin} + * the mixin {@link de.hysky.skyblocker.mixins.CommandTreeS2CPacketMixin} */ public class WarpAutocomplete { private static final Logger LOGGER = LoggerFactory.getLogger(WarpAutocomplete.class); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java index e0d67fbe..9b2080a3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java @@ -3,12 +3,12 @@ package de.hysky.skyblocker.skyblock.accessories.newyearcakes; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.MinecraftClient; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import java.util.List; -import java.util.Map; public class NewYearCakeBagHelper extends ContainerSolver { public NewYearCakeBagHelper() { @@ -21,7 +21,7 @@ public class NewYearCakeBagHelper extends ContainerSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { MinecraftClient client = MinecraftClient.getInstance(); if (client.player != null) { for (Slot slot : client.player.currentScreenHandler.slots) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java index b722849b..2fdcf3b4 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java @@ -4,6 +4,7 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -64,14 +65,14 @@ public class NewYearCakesHelper extends ContainerSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { String profile = Utils.getProfile(); if (cakes.isEmpty() || !cakes.containsKey(profile) || cakes.containsKey(profile) && cakes.get(profile).isEmpty()) return List.of(); List<ColorHighlight> highlights = new ArrayList<>(); - for (Map.Entry<Integer, ItemStack> entry : slots.entrySet()) { + for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) { int year = getCakeYear(entry.getValue()); if (year >= 0 && cakes.containsKey(profile)) { - highlights.add(cakes.get(profile).contains(year) ? ColorHighlight.red(entry.getKey()) : ColorHighlight.green(entry.getKey())); + highlights.add(cakes.get(profile).contains(year) ? ColorHighlight.red(entry.getIntKey()) : ColorHighlight.green(entry.getIntKey())); } } return highlights; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java index c8bc1f13..10823418 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java @@ -34,6 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; @@ -93,7 +94,7 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS resetFiltersButton = new ScaledTextButtonWidget(x + 10, y + 77, 12, 12, Text.literal("↻"), this::onResetPressed); addDrawableChild(resetFiltersButton); resetFiltersButton.setTooltip(Tooltip.of(Text.literal("Reset Filters"))); - resetFiltersButton.setTooltipDelay(500); + resetFiltersButton.setTooltipDelay(Duration.ofMillis(500)); addDrawableChild(new ButtonWidget.Builder(Text.literal("<"), button -> this.clickSlot(BACK_BUTTON_SLOT)) .position(x + 98, y + 4) @@ -240,11 +241,11 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS } } case SORT_BUTTON_SLOT -> - sortWidget.setCurrent(SortWidget.Option.get(getOrdinal(ItemUtils.getNbtTooltips(stack)))); + sortWidget.setCurrent(SortWidget.Option.get(getOrdinal(ItemUtils.getLore(stack)))); case AUCTION_TYPE_BUTTON_SLOT -> - auctionTypeWidget.setCurrent(AuctionTypeWidget.Option.get(getOrdinal(ItemUtils.getNbtTooltips(stack)))); + auctionTypeWidget.setCurrent(AuctionTypeWidget.Option.get(getOrdinal(ItemUtils.getLore(stack)))); case RARITY_BUTTON_SLOT -> { - List<Text> tooltip = ItemUtils.getNbtTooltips(stack); + List<Text> tooltip = ItemUtils.getLore(stack); int ordinal = getOrdinal(tooltip); String split = tooltip.get(ordinal + 1).getString().substring(2); rarityWidget.setText(tooltip.subList(1, tooltip.size() - 3), split); @@ -254,7 +255,7 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS resetFiltersButton.active = handler.getSlot(slotId).getStack().isOf(Items.ANVIL); } case SEARCH_BUTTON_SLOT -> { - List<Text> tooltipSearch = ItemUtils.getNbtTooltips(stack); + List<Text> tooltipSearch = ItemUtils.getLore(stack); for (Text text : tooltipSearch) { String string = text.getString(); if (string.contains("Filtered:")) { @@ -271,7 +272,7 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS CategoryTabWidget categoryTabWidget = categoryTabWidgets.get(slotId / 9); categoryTabWidget.setSlotId(slotId); categoryTabWidget.setIcon(handler.getSlot(slotId).getStack()); - List<Text> tooltipDefault = ItemUtils.getNbtTooltips(handler.getSlot(slotId).getStack()); + List<Text> tooltipDefault = ItemUtils.getLore(handler.getSlot(slotId).getStack()); for (int j = tooltipDefault.size() - 1; j >= 0; j--) { String lowerCase = tooltipDefault.get(j).getString().toLowerCase(); if (lowerCase.contains("currently")) { @@ -284,7 +285,7 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS } } else if (slotId > 9 && slotId < (handler.getRows() - 1) * 9 && slotId % 9 > 1 && slotId % 9 < 8) { if (!SkyblockerConfigManager.get().general.fancyAuctionHouse.highlightCheapBIN) return; - List<Text> tooltip = ItemUtils.getNbtTooltips(stack); + List<Text> tooltip = ItemUtils.getLore(stack); for (int k = tooltip.size() - 1; k >= 0; k--) { Text text = tooltip.get(k); String string = text.getString(); @@ -349,7 +350,7 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI<AuctionHouseS private void parsePage(ItemStack stack) { assert client != null; try { - List<Text> tooltip = ItemUtils.getNbtTooltips(stack); + List<Text> tooltip = ItemUtils.getLore(stack); String str = tooltip.get(0).getString().trim(); str = str.substring(1, str.length() - 1); // remove parentheses String[] parts = str.split("/"); // split the string diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java index 28898cdc..4c4e1c0f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java @@ -1,6 +1,6 @@ package de.hysky.skyblocker.skyblock.auction; -import de.hysky.skyblocker.mixin.accessor.SlotAccessor; +import de.hysky.skyblocker.mixins.accessors.SlotAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.Inventory; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java index a8b30a50..af931eb1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java @@ -198,18 +198,18 @@ public class AuctionViewScreen extends AbstractCustomHypixelGUI<AuctionHouseScre if (priceParsed) return; if (stack.isOf(Items.POISONOUS_POTATO)) { changeState(BuyState.CANT_AFFORD); - getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + getPriceFromTooltip(ItemUtils.getLore(stack)); buySlotID = slotId; } else if (stack.isOf(Items.GOLD_NUGGET)) { changeState(BuyState.AFFORD); - getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + getPriceFromTooltip(ItemUtils.getLore(stack)); buySlotID = slotId; } else if (stack.isOf(Items.GOLD_BLOCK)) { changeState(BuyState.TOP_BID); - getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + getPriceFromTooltip(ItemUtils.getLore(stack)); buySlotID = slotId; } else if (stack.isOf(Items.NAME_TAG)) { - getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + getPriceFromTooltip(ItemUtils.getLore(stack)); changeProfile = true; buySlotID = slotId; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java index 4334fc58..2204d39c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java @@ -4,7 +4,6 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; import net.minecraft.text.Text; import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; public class AuctionTypeWidget extends SliderWidget<AuctionTypeWidget.Option> { @@ -34,7 +33,7 @@ public class AuctionTypeWidget extends SliderWidget<AuctionTypeWidget.Option> { private static final AuctionTypeWidget.Option[] values = values(); public static AuctionTypeWidget.Option get(int ordinal) { - return values[MathHelper.clamp(ordinal, 0, values.length - 1)]; + return values[Math.clamp(ordinal, 0, values.length - 1)]; } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java index 03d91780..02dbc132 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java @@ -5,7 +5,8 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ButtonTextures; import net.minecraft.client.gui.widget.ToggleButtonWidget; -import net.minecraft.client.item.TooltipContext; +import net.minecraft.client.item.TooltipType; +import net.minecraft.item.Item.TooltipContext; import net.minecraft.item.ItemStack; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; @@ -39,7 +40,7 @@ public class CategoryTabWidget extends ToggleButtonWidget { if (isMouseOver(mouseX, mouseY)) { context.getMatrices().push(); - context.drawTooltip(MinecraftClient.getInstance().textRenderer, icon.getTooltip(MinecraftClient.getInstance().player, TooltipContext.BASIC), mouseX, mouseY); + context.drawTooltip(MinecraftClient.getInstance().textRenderer, icon.getTooltip(TooltipContext.DEFAULT, MinecraftClient.getInstance().player, TooltipType.BASIC), mouseX, mouseY); context.getMatrices().pop(); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java index b2450b59..84b8ae4d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java @@ -4,7 +4,6 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; import net.minecraft.text.Text; import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; public class SortWidget extends SliderWidget<SortWidget.Option> { @@ -39,7 +38,7 @@ public class SortWidget extends SliderWidget<SortWidget.Option> { private static final Option[] values = values(); public static Option get(int ordinal) { - return values[MathHelper.clamp(ordinal, 0, values.length - 1)]; + return values[Math.clamp(ordinal, 0, values.length - 1)]; } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/barn/HungryHiker.java b/src/main/java/de/hysky/skyblocker/skyblock/barn/HungryHiker.java index abb4a76d..4a0213c1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/barn/HungryHiker.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/barn/HungryHiker.java @@ -1,6 +1,7 @@ package de.hysky.skyblocker.skyblock.barn; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.chat.ChatFilterResult; import de.hysky.skyblocker.utils.chat.ChatPatternListener; import net.minecraft.client.MinecraftClient; @@ -14,7 +15,7 @@ public class HungryHiker extends ChatPatternListener { private static final Map<String, String> foods; - public HungryHiker() { super("^§e\\[NPC] Hungry Hiker§f: (The food I want is|(I asked for) food that is) ([a-zA-Z, '\\-]*\\.)$"); } + public HungryHiker() { super("^\\[NPC] Hungry Hiker: (The food I want is|(I asked for) food that is) ([a-zA-Z, '\\-]*\\.)$"); } @Override public ChatFilterResult state() { @@ -29,7 +30,7 @@ public class HungryHiker extends ChatPatternListener { String food = foods.get(foodDescription); if (food == null) return false; String middlePartOfTheMessageToSend = matcher.group(2) != null ? matcher.group(2) : matcher.group(1); - client.player.sendMessage(Text.of("§e[NPC] Hungry Hiker§f: " + middlePartOfTheMessageToSend + " " + food + "."), false); + Utils.sendMessageToBypassEvents(Text.of("§e[NPC] Hungry Hiker§f: " + middlePartOfTheMessageToSend + " " + food + ".")); return true; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/barn/TreasureHunter.java b/src/main/java/de/hysky/skyblocker/skyblock/barn/TreasureHunter.java index 191014d5..032c7df9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/barn/TreasureHunter.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/barn/TreasureHunter.java @@ -14,7 +14,7 @@ public class TreasureHunter extends ChatPatternListener { private static final Map<String, String> locations; - public TreasureHunter() { super("^§e\\[NPC] Treasure Hunter§f: ([a-zA-Z, '\\-\\.]*)$"); } + public TreasureHunter() { super("^\\[NPC] Treasure Hunter: ([a-zA-Z, '\\-\\.]*)$"); } @Override public ChatFilterResult state() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java index bafada27..d61a0b59 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.chat; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import de.hysky.skyblocker.events.HudRenderEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.util.math.MatrixStack; @@ -13,7 +13,7 @@ public class ChatRuleAnnouncementScreen { private static Text text = null; public static void init() { - HudRenderCallback.EVENT.register((context, tickDelta) -> { + HudRenderEvents.BEFORE_CHAT.register((context, tickDelta) -> { if (timer <= 0 || text == null) { return; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java index a1b9317a..747e826b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java @@ -39,8 +39,8 @@ public class ChatRulesConfigListWidget extends ElementListWidget<ChatRulesConfig } @Override - protected int getScrollbarPositionX() { - return super.getScrollbarPositionX() + 50; + protected int getScrollbarX() { + return super.getScrollbarX() + 50; } protected void addRuleAfterSelected() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java index 2a103d13..d1c7f4fd 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java @@ -6,7 +6,7 @@ import com.google.gson.JsonParser; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.mixin.accessor.MessageHandlerAccessor; +import de.hysky.skyblocker.mixins.accessors.MessageHandlerAccessor; import de.hysky.skyblocker.utils.Http; import de.hysky.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -52,7 +52,7 @@ public class ChatRulesHandler { private static void loadChatRules() { try (BufferedReader reader = Files.newBufferedReader(CHAT_RULE_FILE)) { - Map<String, List<ChatRule>> chatRules = MAP_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow(); + Map<String, List<ChatRule>> chatRules = MAP_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow(); LOGGER.info("[Skyblocker Chat Rules]: {}", chatRules); chatRuleList.addAll(chatRules.get("rules")); @@ -98,7 +98,7 @@ public class ChatRulesHandler { protected static void saveChatRules() { JsonObject chatRuleJson = new JsonObject(); - chatRuleJson.add("rules", ChatRule.LIST_CODEC.encodeStart(JsonOps.INSTANCE, chatRuleList).result().orElseThrow()); + chatRuleJson.add("rules", ChatRule.LIST_CODEC.encodeStart(JsonOps.INSTANCE, chatRuleList).getOrThrow()); try (BufferedWriter writer = Files.newBufferedWriter(CHAT_RULE_FILE)) { SkyblockerMod.GSON.toJson(chatRuleJson, writer); LOGGER.info("[Skyblocker Chat Rules] Saved chat rules file"); @@ -139,9 +139,7 @@ public class ChatRulesHandler { //show replacement message in chat //bypass MessageHandler#onGameMessage to avoid activating chat rules again if (!rule.getHideMessage() && CLIENT.player != null) { - CLIENT.inGameHud.getChatHud().addMessage(newMessage); - ((MessageHandlerAccessor) CLIENT.getMessageHandler()).invokeAddToChatLog(newMessage, Instant.now()); - CLIENT.getNarratorManager().narrateSystemMessage(newMessage); + Utils.sendMessageToBypassEvents(newMessage); } //play sound diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java index 790d434a..00cd85a0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java @@ -60,7 +60,7 @@ public class KuudraWaypoints { private static CompletableFuture<Void> loadWaypoints(MinecraftClient client, Identifier file, ObjectArrayList<Waypoint> list, float[] colorComponents) { return CompletableFuture.supplyAsync(() -> { try (BufferedReader reader = client.getResourceManager().openAsReader(file)) { - return CODEC.apply(colorComponents).parse(JsonOps.INSTANCE, getWaypoints(reader)).result().orElseThrow(); + return CODEC.apply(colorComponents).parse(JsonOps.INSTANCE, getWaypoints(reader)).getOrThrow(); } catch (Exception e) { LOGGER.error("[Skyblocker Kuudra Waypoints] Failed to load kuudra waypoints from: {}", file, e); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java index 01422770..0bc34c57 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java @@ -1,13 +1,15 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.component.DataComponentTypes; import net.minecraft.item.ItemStack; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class CroesusHelper extends ContainerSolver { @@ -21,15 +23,15 @@ public class CroesusHelper extends ContainerSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { List<ColorHighlight> highlights = new ArrayList<>(); - for (Map.Entry<Integer, ItemStack> entry : slots.entrySet()) { + for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) { ItemStack stack = entry.getValue(); - if (stack != null && stack.getNbt() != null) { - if (stack.getNbt().toString().contains("Opened Chest:")) { - highlights.add(ColorHighlight.gray(entry.getKey())); - } else if (stack.getNbt().toString().contains("No more Chests to open!")) { - highlights.add(ColorHighlight.red(entry.getKey())); + if (stack != null && stack.contains(DataComponentTypes.LORE)) { + if (ItemUtils.getLoreLineIf(stack, s -> s.contains("Opened Chest:")) != null) { + highlights.add(ColorHighlight.gray(entry.getIntKey())); + } else if (ItemUtils.getLoreLineIf(stack, s -> s.contains("No more Chests to open!")) != null) { + highlights.add(ColorHighlight.red(entry.getIntKey())); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java index ca166915..c6cbe2ce 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java @@ -6,8 +6,11 @@ import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; +import net.minecraft.util.Util; + import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -29,15 +32,15 @@ public class CroesusProfit extends ContainerSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { List<ColorHighlight> highlights = new ArrayList<>(); ItemStack bestChest = null, secondBestChest = null; long bestValue = 0, secondBestValue = 0; // If negative value of chest - it is out of the question long dungeonKeyPriceData = getItemPrice("DUNGEON_CHEST_KEY") * 2; // lesser ones don't worth the hassle - for (Map.Entry<Integer, ItemStack> entry : slots.entrySet()) { + for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) { ItemStack stack = entry.getValue(); - if (stack != null && stack.getNbt() != null && stack.getName().toString().contains("Chest")) { + if (stack.getName().getString().contains("Chest")) { long value = valueChest(stack); if (value > bestValue) { secondBestChest = bestChest; @@ -51,13 +54,13 @@ public class CroesusProfit extends ContainerSolver { } } - for (Map.Entry<Integer, ItemStack> entry : slots.entrySet()) { + for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) { ItemStack stack = entry.getValue(); - if (stack != null && stack.getNbt() != null) { + if (stack != null) { if (stack.equals(bestChest)) { - highlights.add(ColorHighlight.green(entry.getKey())); + highlights.add(ColorHighlight.green(entry.getIntKey())); } else if (stack.equals(secondBestChest) && secondBestValue > dungeonKeyPriceData) { - highlights.add(ColorHighlight.yellow(entry.getKey())); + highlights.add(ColorHighlight.yellow(entry.getIntKey())); } } } @@ -71,7 +74,7 @@ public class CroesusProfit extends ContainerSolver { List<String> chestItems = new ArrayList<>(); boolean processingContents = false; - for (Text line : ItemUtils.getNbtTooltips(chest)) { + for (Text line : ItemUtils.getLore(chest)) { String lineString = line.getString(); if (lineString.contains("Contents")) { processingContents = true; @@ -124,144 +127,144 @@ public class CroesusProfit extends ContainerSolver { // I did a thing :( - final Map<String, String> dungeonDropsNameToId = new HashMap<>() {{ - put("Enchanted Book (Ultimate Jerry I)", "ENCHANTMENT_ULTIMATE_JERRY_1"); // ultimate books start - put("Enchanted Book (Ultimate Jerry II)", "ENCHANTMENT_ULTIMATE_JERRY_2"); - put("Enchanted Book (Ultimate Jerry III)", "ENCHANTMENT_ULTIMATE_JERRY_3"); - put("Enchanted Book (Bank I)", "ENCHANTMENT_ULTIMATE_BANK_1"); - put("Enchanted Book (Bank II)", "ENCHANTMENT_ULTIMATE_BANK_2"); - put("Enchanted Book (Bank III)", "ENCHANTMENT_ULTIMATE_BANK_3"); - put("Enchanted Book (Combo I)", "ENCHANTMENT_ULTIMATE_COMBO_1"); - put("Enchanted Book (Combo II)", "ENCHANTMENT_ULTIMATE_COMBO_2"); - put("Enchanted Book (No Pain No Gain I)", "ENCHANTMENT_ULTIMATE_NO_PAIN_NO_GAIN_1"); - put("Enchanted Book (No Pain No Gain II)", "ENCHANTMENT_ULTIMATE_NO_PAIN_NO_GAIN_2"); - put("Enchanted Book (Ultimate Wise I)", "ENCHANTMENT_ULTIMATE_WISE_1"); - put("Enchanted Book (Ultimate Wise II)", "ENCHANTMENT_ULTIMATE_WISE_2"); - put("Enchanted Book (Wisdom I)", "ENCHANTMENT_ULTIMATE_WISDOM_1"); - put("Enchanted Book (Wisdom II)", "ENCHANTMENT_ULTIMATE_WISDOM_2"); - put("Enchanted Book (Last Stand I)", "ENCHANTMENT_ULTIMATE_LAST_STAND_1"); - put("Enchanted Book (Last Stand II)", "ENCHANTMENT_ULTIMATE_LAST_STAND_2"); - put("Enchanted Book (Rend I)", "ENCHANTMENT_ULTIMATE_REND_1"); - put("Enchanted Book (Rend II)", "ENCHANTMENT_ULTIMATE_REND_2"); - put("Enchanted Book (Legion I)", "ENCHANTMENT_ULTIMATE_LEGION_1"); - put("Enchanted Book (Swarm I)", "ENCHANTMENT_ULTIMATE_SWARM_1"); - put("Enchanted Book (One For All I)", "ENCHANTMENT_ULTIMATE_ONE_FOR_ALL_1"); - put("Enchanted Book (Soul Eater I)", "ENCHANTMENT_ULTIMATE_SOUL_EATER_1"); // ultimate books end - put("Enchanted Book (Infinite Quiver VI)", "ENCHANTMENT_INFINITE_QUIVER_6"); // enchanted books start - put("Enchanted Book (Infinite Quiver VII)", "ENCHANTMENT_INFINITE_QUIVER_7"); - put("Enchanted Book (Feather Falling VI)", "ENCHANTMENT_FEATHER_FALLING_6"); - put("Enchanted Book (Feather Falling VII)", "ENCHANTMENT_FEATHER_FALLING_7"); - put("Enchanted Book (Rejuvenate I)", "ENCHANTMENT_REJUVENATE_1"); - put("Enchanted Book (Rejuvenate II)", "ENCHANTMENT_REJUVENATE_2"); - put("Enchanted Book (Rejuvenate III)", "ENCHANTMENT_REJUVENATE_3"); - put("Enchanted Book (Overload)", "ENCHANTMENT_OVERLOAD_1"); - put("Enchanted Book (Lethality VI)", "ENCHANTMENT_LETHALITY_6"); - put("Enchanted Book (Thunderlord VII)", "ENCHANTMENT_THUNDERLORD_7"); // enchanted books end + private final Map<String, String> dungeonDropsNameToId = Util.make(new HashMap<>(), map -> { + map.put("Enchanted Book (Ultimate Jerry I)", "ENCHANTMENT_ULTIMATE_JERRY_1"); // ultimate books start + map.put("Enchanted Book (Ultimate Jerry II)", "ENCHANTMENT_ULTIMATE_JERRY_2"); + map.put("Enchanted Book (Ultimate Jerry III)", "ENCHANTMENT_ULTIMATE_JERRY_3"); + map.put("Enchanted Book (Bank I)", "ENCHANTMENT_ULTIMATE_BANK_1"); + map.put("Enchanted Book (Bank II)", "ENCHANTMENT_ULTIMATE_BANK_2"); + map.put("Enchanted Book (Bank III)", "ENCHANTMENT_ULTIMATE_BANK_3"); + map.put("Enchanted Book (Combo I)", "ENCHANTMENT_ULTIMATE_COMBO_1"); + map.put("Enchanted Book (Combo II)", "ENCHANTMENT_ULTIMATE_COMBO_2"); + map.put("Enchanted Book (No Pain No Gain I)", "ENCHANTMENT_ULTIMATE_NO_PAIN_NO_GAIN_1"); + map.put("Enchanted Book (No Pain No Gain II)", "ENCHANTMENT_ULTIMATE_NO_PAIN_NO_GAIN_2"); + map.put("Enchanted Book (Ultimate Wise I)", "ENCHANTMENT_ULTIMATE_WISE_1"); + map.put("Enchanted Book (Ultimate Wise II)", "ENCHANTMENT_ULTIMATE_WISE_2"); + map.put("Enchanted Book (Wisdom I)", "ENCHANTMENT_ULTIMATE_WISDOM_1"); + map.put("Enchanted Book (Wisdom II)", "ENCHANTMENT_ULTIMATE_WISDOM_2"); + map.put("Enchanted Book (Last Stand I)", "ENCHANTMENT_ULTIMATE_LAST_STAND_1"); + map.put("Enchanted Book (Last Stand II)", "ENCHANTMENT_ULTIMATE_LAST_STAND_2"); + map.put("Enchanted Book (Rend I)", "ENCHANTMENT_ULTIMATE_REND_1"); + map.put("Enchanted Book (Rend II)", "ENCHANTMENT_ULTIMATE_REND_2"); + map.put("Enchanted Book (Legion I)", "ENCHANTMENT_ULTIMATE_LEGION_1"); + map.put("Enchanted Book (Swarm I)", "ENCHANTMENT_ULTIMATE_SWARM_1"); + map.put("Enchanted Book (One For All I)", "ENCHANTMENT_ULTIMATE_ONE_FOR_ALL_1"); + map.put("Enchanted Book (Soul Eater I)", "ENCHANTMENT_ULTIMATE_SOUL_EATER_1"); // ultimate books end + map.put("Enchanted Book (Infinite Quiver VI)", "ENCHANTMENT_INFINITE_QUIVER_6"); // enchanted books start + map.put("Enchanted Book (Infinite Quiver VII)", "ENCHANTMENT_INFINITE_QUIVER_7"); + map.put("Enchanted Book (Feather Falling VI)", "ENCHANTMENT_FEATHER_FALLING_6"); + map.put("Enchanted Book (Feather Falling VII)", "ENCHANTMENT_FEATHER_FALLING_7"); + map.put("Enchanted Book (Rejuvenate I)", "ENCHANTMENT_REJUVENATE_1"); + map.put("Enchanted Book (Rejuvenate II)", "ENCHANTMENT_REJUVENATE_2"); + map.put("Enchanted Book (Rejuvenate III)", "ENCHANTMENT_REJUVENATE_3"); + map.put("Enchanted Book (Overload)", "ENCHANTMENT_OVERLOAD_1"); + map.put("Enchanted Book (Lethality VI)", "ENCHANTMENT_LETHALITY_6"); + map.put("Enchanted Book (Thunderlord VII)", "ENCHANTMENT_THUNDERLORD_7"); // enchanted books end - put("Hot Potato Book", "HOT_POTATO_BOOK"); // HPB, FPB, Recomb (universal drops) - put("Fuming Potato Book", "FUMING_POTATO_BOOK"); - put("Recombobulator 3000", "RECOMBOBULATOR_3000"); - put("Necromancer's Brooch", "NECROMANCER_BROOCH"); - put("ESSENCE_WITHER","ESSENCE_WITHER"); // Essences. Really stupid way of doing this - put("ESSENCE_UNDEAD", "ESSENCE_UNDEAD"); - put("ESSENCE_DRAGON", "ESSENCE_DRAGON"); - put("ESSENCE_SPIDER", "ESSENCE_SPIDER"); - put("ESSENCE_ICE", "ESSENCE_ICE"); - put("ESSENCE_DIAMOND", "ESSENCE_DIAMOND"); - put("ESSENCE_GOLD", "ESSENCE_GOLD"); - put("ESSENCE_CRIMSON", "ESSENCE_CRIMSON"); - put("DUNGEON_CHEST_KEY", "DUNGEON_CHEST_KEY"); + map.put("Hot Potato Book", "HOT_POTATO_BOOK"); // HPB, FPB, Recomb (universal drops) + map.put("Fuming Potato Book", "FUMING_POTATO_BOOK"); + map.put("Recombobulator 3000", "RECOMBOBULATOR_3000"); + map.put("Necromancer's Brooch", "NECROMANCER_BROOCH"); + map.put("ESSENCE_WITHER","ESSENCE_WITHER"); // Essences. Really stupid way of doing this + map.put("ESSENCE_UNDEAD", "ESSENCE_UNDEAD"); + map.put("ESSENCE_DRAGON", "ESSENCE_DRAGON"); + map.put("ESSENCE_SPIDER", "ESSENCE_SPIDER"); + map.put("ESSENCE_ICE", "ESSENCE_ICE"); + map.put("ESSENCE_DIAMOND", "ESSENCE_DIAMOND"); + map.put("ESSENCE_GOLD", "ESSENCE_GOLD"); + map.put("ESSENCE_CRIMSON", "ESSENCE_CRIMSON"); + map.put("DUNGEON_CHEST_KEY", "DUNGEON_CHEST_KEY"); - put("Bonzo's Staff", "BONZO_STAFF"); // F1 M1 - put("Master Skull - Tier 1", "MASTER_SKULL_TIER_1"); - put("Bonzo's Mask", "BONZO_MASK"); - put("Balloon Snake", "BALLOON_SNAKE"); - put("Red Nose", "RED_NOSE"); + map.put("Bonzo's Staff", "BONZO_STAFF"); // F1 M1 + map.put("Master Skull - Tier 1", "MASTER_SKULL_TIER_1"); + map.put("Bonzo's Mask", "BONZO_MASK"); + map.put("Balloon Snake", "BALLOON_SNAKE"); + map.put("Red Nose", "RED_NOSE"); - put("Red Scarf", "RED_SCARF"); // F2 M2 - put("Adaptive Blade", "STONE_BLADE"); - put("Master Skull - Tier 2", "MASTER_SKULL_TIER_2"); - put("Adaptive Belt", "ADAPTIVE_BELT"); - put("Scarf's Studies", "SCARF_STUDIES"); + map.put("Red Scarf", "RED_SCARF"); // F2 M2 + map.put("Adaptive Blade", "STONE_BLADE"); + map.put("Master Skull - Tier 2", "MASTER_SKULL_TIER_2"); + map.put("Adaptive Belt", "ADAPTIVE_BELT"); + map.put("Scarf's Studies", "SCARF_STUDIES"); - put("First Master Star", "FIRST_MASTER_STAR"); // F3 M3 - put("Adaptive Helmet", "ADAPTIVE_HELMET"); - put("Adaptive Chestplate", "ADAPTIVE_CHESTPLATE"); - put("Adaptive Leggings", "ADAPTIVE_LEGGINGS"); - put("Adaptive Boots", "ADAPTIVE_BOOTS"); - put("Master Skull - Tier 3", "MASTER_SKULL_TIER_3"); - put("Suspicious Vial", "SUSPICIOUS_VIAL"); + map.put("First Master Star", "FIRST_MASTER_STAR"); // F3 M3 + map.put("Adaptive Helmet", "ADAPTIVE_HELMET"); + map.put("Adaptive Chestplate", "ADAPTIVE_CHESTPLATE"); + map.put("Adaptive Leggings", "ADAPTIVE_LEGGINGS"); + map.put("Adaptive Boots", "ADAPTIVE_BOOTS"); + map.put("Master Skull - Tier 3", "MASTER_SKULL_TIER_3"); + map.put("Suspicious Vial", "SUSPICIOUS_VIAL"); - put("Spirit Sword", "SPIRIT_SWORD"); // F4 M4 - put("Spirit Shortbow", "ITEM_SPIRIT_BOW"); - put("Spirit Boots", "THORNS_BOOTS"); - put("Spirit", "LVL_1_LEGENDARY_SPIRIT"); // Spirit pet (Legendary) - put("Spirit Epic", "LVL_1_EPIC_SPIRIT"); + map.put("Spirit Sword", "SPIRIT_SWORD"); // F4 M4 + map.put("Spirit Shortbow", "ITEM_SPIRIT_BOW"); + map.put("Spirit Boots", "THORNS_BOOTS"); + map.put("Spirit", "LVL_1_LEGENDARY_SPIRIT"); // Spirit pet (Legendary) + map.put("Spirit Epic", "LVL_1_EPIC_SPIRIT"); - put("Second Master Star", "SECOND_MASTER_STAR"); - put("Spirit Wing", "SPIRIT_WING"); - put("Spirit Bone", "SPIRIT_BONE"); - put("Spirit Stone", "SPIRIT_DECOY"); + map.put("Second Master Star", "SECOND_MASTER_STAR"); + map.put("Spirit Wing", "SPIRIT_WING"); + map.put("Spirit Bone", "SPIRIT_BONE"); + map.put("Spirit Stone", "SPIRIT_DECOY"); - put("Shadow Fury", "SHADOW_FURY"); // F5 M5 - put("Last Breath", "LAST_BREATH"); - put("Third Master Star", "THIRD_MASTER_STAR"); - put("Warped Stone", "AOTE_STONE"); - put("Livid Dagger", "LIVID_DAGGER"); - put("Shadow Assassin Helmet", "SHADOW_ASSASSIN_HELMET"); - put("Shadow Assassin Chestplate", "SHADOW_ASSASSIN_CHESTPLATE"); - put("Shadow Assassin Leggings", "SHADOW_ASSASSIN_LEGGINGS"); - put("Shadow Assassin Boots", "SHADOW_ASSASSIN_BOOTS"); - put("Shadow Assassin Cloak", "SHADOW_ASSASSIN_CLOAK"); - put("Master Skull - Tier 4", "MASTER_SKULL_TIER_4"); - put("Dark Orb", "DARK_ORB"); + map.put("Shadow Fury", "SHADOW_FURY"); // F5 M5 + map.put("Last Breath", "LAST_BREATH"); + map.put("Third Master Star", "THIRD_MASTER_STAR"); + map.put("Warped Stone", "AOTE_STONE"); + map.put("Livid Dagger", "LIVID_DAGGER"); + map.put("Shadow Assassin Helmet", "SHADOW_ASSASSIN_HELMET"); + map.put("Shadow Assassin Chestplate", "SHADOW_ASSASSIN_CHESTPLATE"); + map.put("Shadow Assassin Leggings", "SHADOW_ASSASSIN_LEGGINGS"); + map.put("Shadow Assassin Boots", "SHADOW_ASSASSIN_BOOTS"); + map.put("Shadow Assassin Cloak", "SHADOW_ASSASSIN_CLOAK"); + map.put("Master Skull - Tier 4", "MASTER_SKULL_TIER_4"); + map.put("Dark Orb", "DARK_ORB"); - put("Precursor Eye", "PRECURSOR_EYE"); // F6 M6 - put("Giant's Sword", "GIANTS_SWORD"); - put("Necromancer Lord Helmet", "NECROMANCER_LORD_HELMET"); - put("Necromancer Lord Chestplate", "NECROMANCER_LORD_CHESTPLATE"); - put("Necromancer Lord Leggings", "NECROMANCER_LORD_LEGGINGS"); - put("Necromancer Lord Boots", "NECROMANCER_LORD_BOOTS"); - put("Fourth Master Star", "FOURTH_MASTER_STAR"); - put("Summoning Ring", "SUMMONING_RING"); - put("Fel Skull", "FEL_SKULL"); - put("Necromancer Sword", "NECROMANCER_SWORD"); - put("Soulweaver Gloves", "SOULWEAVER_GLOVES"); - put("Sadan's Brooch", "SADAN_BROOCH"); - put("Giant Tooth", "GIANT_TOOTH"); + map.put("Precursor Eye", "PRECURSOR_EYE"); // F6 M6 + map.put("Giant's Sword", "GIANTS_SWORD"); + map.put("Necromancer Lord Helmet", "NECROMANCER_LORD_HELMET"); + map.put("Necromancer Lord Chestplate", "NECROMANCER_LORD_CHESTPLATE"); + map.put("Necromancer Lord Leggings", "NECROMANCER_LORD_LEGGINGS"); + map.put("Necromancer Lord Boots", "NECROMANCER_LORD_BOOTS"); + map.put("Fourth Master Star", "FOURTH_MASTER_STAR"); + map.put("Summoning Ring", "SUMMONING_RING"); + map.put("Fel Skull", "FEL_SKULL"); + map.put("Necromancer Sword", "NECROMANCER_SWORD"); + map.put("Soulweaver Gloves", "SOULWEAVER_GLOVES"); + map.put("Sadan's Brooch", "SADAN_BROOCH"); + map.put("Giant Tooth", "GIANT_TOOTH"); - put("Precursor Gear", "PRECURSOR_GEAR"); // F7 M7 - put("Necron Dye", "DYE_NECRON"); - put("Storm the Fish", "STORM_THE_FISH"); - put("Maxor the Fish", "MAXOR_THE_FISH"); - put("Goldor the Fish", "GOLDOR_THE_FISH"); - put("Dark Claymore", "DARK_CLAYMORE"); - put("Necron's Handle", "NECRON_HANDLE"); - put("Master Skull - Tier 5", "MASTER_SKULL_TIER_5"); - put("Shadow Warp", "SHADOW_WARP_SCROLL"); - put("Wither Shield", "WITHER_SHIELD_SCROLL"); - put("Implosion", "IMPLOSION_SCROLL"); - put("Fifth Master Star", "FIFTH_MASTER_STAR"); - put("Auto Recombobulator", "AUTO_RECOMBOBULATOR"); - put("Wither Helmet", "WITHER_HELMET"); - put("Wither Chestplate", "WITHER_CHESTPLATE"); - put("Wither Leggings", "WITHER_LEGGINGS"); - put("Wither Boots", "WITHER_BOOTS"); - put("Wither Catalyst", "WITHER_CATALYST"); - put("Wither Cloak Sword", "WITHER_CLOAK"); - put("Wither Blood", "WITHER_BLOOD"); + map.put("Precursor Gear", "PRECURSOR_GEAR"); // F7 M7 + map.put("Necron Dye", "DYE_NECRON"); + map.put("Storm the Fish", "STORM_THE_FISH"); + map.put("Maxor the Fish", "MAXOR_THE_FISH"); + map.put("Goldor the Fish", "GOLDOR_THE_FISH"); + map.put("Dark Claymore", "DARK_CLAYMORE"); + map.put("Necron's Handle", "NECRON_HANDLE"); + map.put("Master Skull - Tier 5", "MASTER_SKULL_TIER_5"); + map.put("Shadow Warp", "SHADOW_WARP_SCROLL"); + map.put("Wither Shield", "WITHER_SHIELD_SCROLL"); + map.put("Implosion", "IMPLOSION_SCROLL"); + map.put("Fifth Master Star", "FIFTH_MASTER_STAR"); + map.put("Auto Recombobulator", "AUTO_RECOMBOBULATOR"); + map.put("Wither Helmet", "WITHER_HELMET"); + map.put("Wither Chestplate", "WITHER_CHESTPLATE"); + map.put("Wither Leggings", "WITHER_LEGGINGS"); + map.put("Wither Boots", "WITHER_BOOTS"); + map.put("Wither Catalyst", "WITHER_CATALYST"); + map.put("Wither Cloak Sword", "WITHER_CLOAK"); + map.put("Wither Blood", "WITHER_BLOOD"); - put("Shiny Wither Helmet", "SHINY_WITHER_HELMET"); // M7 shiny drops - put("Shiny Wither Chestplate", "SHINY_WITHER_CHESTPLATE"); - put("Shiny Wither Leggings", "SHINY_WITHER_LEGGINGS"); - put("Shiny Wither Boots", "SHINY_WITHER_BOOTS"); - put("Shiny Necron's Handle", "SHINY_NECRON_HANDLE"); // cool thing + map.put("Shiny Wither Helmet", "SHINY_WITHER_HELMET"); // M7 shiny drops + map.put("Shiny Wither Chestplate", "SHINY_WITHER_CHESTPLATE"); + map.put("Shiny Wither Leggings", "SHINY_WITHER_LEGGINGS"); + map.put("Shiny Wither Boots", "SHINY_WITHER_BOOTS"); + map.put("Shiny Necron's Handle", "SHINY_NECRON_HANDLE"); // cool thing - put("Dungeon Disc", "DUNGEON_DISC_1"); - put("Clown Disc", "DUNGEON_DISC_2"); - put("Watcher Disc", "DUNGEON_DISC_3"); - put("Old Disc", "DUNGEON_DISC_4"); - put("Necron Disc", "DUNGEON_DISC_5"); - }}; + map.put("Dungeon Disc", "DUNGEON_DISC_1"); + map.put("Clown Disc", "DUNGEON_DISC_2"); + map.put("Watcher Disc", "DUNGEON_DISC_3"); + map.put("Old Disc", "DUNGEON_DISC_4"); + map.put("Necron Disc", "DUNGEON_DISC_5"); + }); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index f2986ec0..7a6cdcd0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -1,25 +1,32 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; +import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.MapRenderer; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.MapIdComponent; import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; public class DungeonMap { - private static final int DEFAULT_MAP_ID = 1024; - private static Integer cachedMapId = null; + private static final MapIdComponent DEFAULT_MAP_ID_COMPONENT = new MapIdComponent(1024); + private static MapIdComponent cachedMapIdComponent = null; public static void init() { + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickDelta) -> render(context)); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker") .then(ClientCommandManager.literal("hud") .then(ClientCommandManager.literal("dungeon") @@ -34,7 +41,7 @@ public class DungeonMap { MinecraftClient client = MinecraftClient.getInstance(); if (client.player == null || client.world == null) return; - int mapId = getMapId(client.player.getInventory().main.get(8)); + MapIdComponent mapId = getMapIdComponent(client.player.getInventory().main.get(8)); MapState state = FilledMapItem.getMapState(mapId, client.world); if (state == null) return; @@ -53,16 +60,21 @@ public class DungeonMap { matrices.pop(); } - public static int getMapId(ItemStack stack) { - if (stack.isOf(Items.FILLED_MAP)) { - @SuppressWarnings("DataFlowIssue") - int mapId = FilledMapItem.getMapId(stack); - cachedMapId = mapId; - return mapId; - } else return cachedMapId != null ? cachedMapId : DEFAULT_MAP_ID; + public static MapIdComponent getMapIdComponent(ItemStack stack) { + if (stack.isOf(Items.FILLED_MAP) && stack.contains(DataComponentTypes.MAP_ID)) { + MapIdComponent mapIdComponent = stack.get(DataComponentTypes.MAP_ID); + cachedMapIdComponent = mapIdComponent; + return mapIdComponent; + } else return cachedMapIdComponent != null ? cachedMapIdComponent : DEFAULT_MAP_ID_COMPONENT; + } + + private static void render(DrawContext context) { + if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss() && SkyblockerConfigManager.get().locations.dungeons.enableMap) { + render(context.getMatrices()); + } } private static void reset() { - cachedMapId = null; + cachedMapIdComponent = null; } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScoreHUD.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScoreHUD.java index 1dfb1b95..8d402172 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScoreHUD.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScoreHUD.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; +import de.hysky.skyblocker.utils.Utils; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.util.math.MatrixStack; @@ -11,13 +13,19 @@ public class DungeonScoreHUD { private DungeonScoreHUD() { } + public static void init() { + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickDelta) -> render(context)); + } + //This is 4+5 wide, needed to offset the extra width from bold numbers (3×1 wide) in S+ and the "+" (6 wide) so that it doesn't go off the screen if the score is S+ and the hud element is at the right edge of the screen private static final Text extraSpace = Text.literal(" ").append(Text.literal(" ").formatted(Formatting.BOLD)); - public static void render(DrawContext context) { - int x = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreX; - int y = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreY; - render(context, x, y); + private static void render(DrawContext context) { + if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && SkyblockerConfigManager.get().locations.dungeons.dungeonScore.enableScoreHUD) { + int x = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreX; + int y = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreY; + render(context, x, y); + } } public static void render(DrawContext context, int x, int y) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/FireFreezeStaffTimer.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/FireFreezeStaffTimer.java index e5d4f078..7c0aab4c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/FireFreezeStaffTimer.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/FireFreezeStaffTimer.java @@ -1,9 +1,9 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -14,7 +14,7 @@ public class FireFreezeStaffTimer { private static long fireFreezeTimer; public static void init() { - HudRenderCallback.EVENT.register(FireFreezeStaffTimer::onDraw); + HudRenderEvents.BEFORE_CHAT.register(FireFreezeStaffTimer::onDraw); ClientReceiveMessageEvents.GAME.register(FireFreezeStaffTimer::onChatMessage); ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> FireFreezeStaffTimer.reset()); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java index 15efe6e4..ee9791d5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java @@ -16,6 +16,7 @@ import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; import java.util.Map; +import java.util.Set; public class LividColor { private static final Map<Block, Formatting> WOOL_TO_FORMATTING = Map.of( @@ -40,6 +41,7 @@ public class LividColor { "Doctor Livid", Formatting.GRAY, "Vendetta Livid", Formatting.WHITE ); + public static final Set<String> LIVID_NAMES = Set.copyOf(LIVID_TO_FORMATTING.keySet()); public static final SkyblockerConfig.LividColor CONFIG = SkyblockerConfigManager.get().locations.dungeons.lividColor; private static int tenTicks = 0; private static Formatting color; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java index 0a048775..70902a17 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java @@ -5,7 +5,6 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; import net.minecraft.client.gui.widget.ContainerWidget; -import net.minecraft.client.item.TooltipContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.screen.GenericContainerScreenHandler; @@ -15,6 +14,8 @@ import net.minecraft.text.Text; import java.util.ArrayList; import java.util.List; +import de.hysky.skyblocker.utils.ItemUtils; + public class FinderSettingsContainer extends ContainerWidget { private boolean isInitialized = false; private OptionDropdownWidget floorSelector; @@ -161,7 +162,7 @@ public class FinderSettingsContainer extends ContainerWidget { * @return true if all goes well */ private boolean setRangeFromTooltip(ItemStack stack, RangedValueWidget widget) { - for (Text text : stack.getTooltip(null, TooltipContext.BASIC)) { + for (Text text : ItemUtils.getLore(stack)) { String textLowerCase = text.getString().toLowerCase(); if (textLowerCase.contains("selected:")) { String[] split = text.getString().split(":"); @@ -186,7 +187,7 @@ public class FinderSettingsContainer extends ContainerWidget { * @return true if all goes well */ private boolean setSelectedElementFromTooltip(Slot slot, ItemStack stack, OptionDropdownWidget dropdownWidget) { - for (Text text : stack.getTooltip(null, TooltipContext.BASIC)) { + for (Text text : ItemUtils.getLore(stack)) { String textLowerCase = text.getString().toLowerCase(); if (textLowerCase.contains("selected:")) { String[] split = text.getString().split(":"); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java index 64e45283..d2159751 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java @@ -29,7 +29,6 @@ public class OptionDropdownWidget extends ElementListWidget<OptionDropdownWidget this.screen = screen; this.slotId = slotId; setX(x); - setRenderBackground(false); setRenderHeader(true, 25); this.name = name; this.selectedOption = selectedOption; @@ -55,7 +54,7 @@ public class OptionDropdownWidget extends ElementListWidget<OptionDropdownWidget } @Override - protected int getScrollbarPositionX() { + protected int getScrollbarX() { return getRowLeft() + getRowWidth(); } @@ -120,6 +119,14 @@ public class OptionDropdownWidget extends ElementListWidget<OptionDropdownWidget matrices.pop(); } } + + @Override + protected void drawHeaderAndFooterSeparators(DrawContext context) { + } + + @Override + protected void drawMenuListBackground(DrawContext context) { + } public void open(List<Option> entries, int backButtonId) { isOpen = true; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java index b53047d8..a9ffafec 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java @@ -1,8 +1,9 @@ package de.hysky.skyblocker.skyblock.dungeon.partyfinder; -import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.authlib.properties.PropertyMap; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.mixin.accessor.SkullBlockEntityAccessor; +import de.hysky.skyblocker.mixins.accessors.SkullBlockEntityAccessor; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -12,10 +13,10 @@ import net.minecraft.client.gui.Selectable; import net.minecraft.client.gui.widget.ElementListWidget; import net.minecraft.client.util.DefaultSkinHelper; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ProfileComponent; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.StringNbtReader; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.text.TextColor; @@ -24,7 +25,10 @@ import net.minecraft.util.Identifier; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -32,13 +36,14 @@ public class PartyEntry extends ElementListWidget.Entry<PartyEntry> { private static final Identifier PARTY_CARD_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/party_card.png"); private static final Identifier PARTY_CARD_TEXTURE_HOVER = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/party_card_hover.png"); public static final Text JOIN_TEXT = Text.translatable("skyblocker.partyFinder.join"); + private static final Map<String, ProfileComponent> SKULL_CACHE = new Object2ObjectOpenHashMap<>(); protected final PartyFinderScreen screen; protected final int slotID; Player partyLeader; String floor = "???"; String dungeon = "???"; String note = ""; - NbtCompound floorSkullNBT = new NbtCompound(); + PropertyMap floorSkullProperties = new PropertyMap(); Identifier partyLeaderSkin = DefaultSkinHelper.getTexture(); Player[] partyMembers = new Player[4]; @@ -66,7 +71,7 @@ public class PartyEntry extends ElementListWidget.Entry<PartyEntry> { String partyHost = title.getString().split("'s")[0]; int membersIndex = -1; - for (int i = 1; i < tooltips.size(); i++) { + for (int i = 0; i < tooltips.size(); i++) { Text text = tooltips.get(i); String tooltipText = Formatting.strip(text.getString()); assert tooltipText != null; @@ -87,14 +92,14 @@ public class PartyEntry extends ElementListWidget.Entry<PartyEntry> { if (PartyFinderScreen.floorIconsMaster == null || PartyFinderScreen.floorIconsNormal == null) continue; if (dungeon.contains("Master Mode")) { try { - floorSkullNBT = StringNbtReader.parse(PartyEntryListWidget.BASE_SKULL_NBT.replace("%TEXTURE%", PartyFinderScreen.floorIconsMaster.getOrDefault(floor.toLowerCase(), ""))); - } catch (CommandSyntaxException e) { + floorSkullProperties = PartyFinderScreen.floorIconsMaster.getOrDefault(floor.toLowerCase(), new PropertyMap()); + } catch (Exception e) { throw new RuntimeException(e); } } else { try { - floorSkullNBT = StringNbtReader.parse(PartyEntryListWidget.BASE_SKULL_NBT.replace("%TEXTURE%", PartyFinderScreen.floorIconsNormal.getOrDefault(floor.toLowerCase(), ""))); - } catch (CommandSyntaxException e) { + floorSkullProperties = PartyFinderScreen.floorIconsNormal.getOrDefault(floor.toLowerCase(), new PropertyMap()); + } catch (Exception e) { throw new RuntimeException(e); } } @@ -143,7 +148,7 @@ public class PartyEntry extends ElementListWidget.Entry<PartyEntry> { if (matcher.find()) classLevel = Integer.parseInt(matcher.group(1)); Player player = new Player(playerName, className, classLevel); - SkullBlockEntityAccessor.invokeFetchProfile(playerNameTrim).thenAccept( + SkullBlockEntityAccessor.invokeFetchProfileByName(playerNameTrim).thenAccept( gameProfile -> gameProfile.ifPresent(profile -> player.skinTexture = (client.getSkinProvider().getSkinTextures(profile).texture()))); if (playerNameTrim.equals(partyHost)) { @@ -168,7 +173,7 @@ public class PartyEntry extends ElementListWidget.Entry<PartyEntry> { partyLeader = new Player(Text.literal("Error"), "Error", -1); } - SkullBlockEntityAccessor.invokeFetchProfile(partyLeader.name.getString()).thenAccept( + SkullBlockEntityAccessor.invokeFetchProfileByName(partyLeader.name.getString()).thenAccept( gameProfile -> gameProfile.ifPresent(profile -> partyLeaderSkin = client.getSkinProvider().getSkinTextures(profile).texture())); } @@ -226,7 +231,7 @@ public class PartyEntry extends ElementListWidget.Entry<PartyEntry> { } } ItemStack stack = new ItemStack(Items.PLAYER_HEAD); - stack.setNbt(floorSkullNBT); + stack.set(DataComponentTypes.PROFILE, SKULL_CACHE.computeIfAbsent("SkyblockerCustomPFSkull" + dungeon + floor, name -> new ProfileComponent(Optional.of(name), Optional.of(UUID.randomUUID()), floorSkullProperties))); context.drawItem(stack, 317, 3); int textWidth = textRenderer.getWidth(floor); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntryListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntryListWidget.java index 640f71bd..385b97f0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntryListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntryListWidget.java @@ -68,7 +68,7 @@ public class PartyEntryListWidget extends ElementListWidget<PartyEntry> { } @Override - protected int getScrollbarPositionX() { + protected int getScrollbarX() { return this.width / 2 + getRowWidth() / 2 + 2; } @@ -97,4 +97,12 @@ public class PartyEntryListWidget extends ElementListWidget<PartyEntry> { context.drawTextWrapped(textRenderer, string, getRowLeft(), getY() + 10, getRowWidth(), 0xFFFFFFFF); } else super.renderWidget(context, mouseX, mouseY, delta); } + + @Override + protected void drawHeaderAndFooterSeparators(DrawContext context) { + } + + @Override + protected void drawMenuListBackground(DrawContext context) { + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyFinderScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyFinderScreen.java index 16be2b67..fc66ab06 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyFinderScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyFinderScreen.java @@ -1,7 +1,10 @@ package de.hysky.skyblocker.skyblock.dungeon.partyfinder; import com.google.gson.JsonObject; +import com.mojang.authlib.properties.PropertyMap; + import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.ItemUtils; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.minecraft.block.entity.SignBlockEntity; import net.minecraft.client.MinecraftClient; @@ -10,7 +13,6 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.item.TooltipContext; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.toast.SystemToast; import net.minecraft.entity.player.PlayerInventory; @@ -99,8 +101,8 @@ public class PartyFinderScreen extends Screen { private boolean waitingForServer = false; - public static Map<String, String> floorIconsNormal = null; - public static Map<String, String> floorIconsMaster = null; + public static Map<String, PropertyMap> floorIconsNormal = null; + public static Map<String, PropertyMap> floorIconsMaster = null; public static void initClass() { ClientLifecycleEvents.CLIENT_STARTED.register(client -> { @@ -110,8 +112,8 @@ public class PartyFinderScreen extends Screen { floorIconsMaster = new HashMap<>(); try (BufferedReader skullTextureReader = client.getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/catacombs/floorskulls.json"))) { JsonObject json = SkyblockerMod.GSON.fromJson(skullTextureReader, JsonObject.class); - json.getAsJsonObject("normal").asMap().forEach((s, jsonElement) -> floorIconsNormal.put(s, jsonElement.getAsString())); - json.getAsJsonObject("master").asMap().forEach((s, jsonElement) -> floorIconsMaster.put(s, jsonElement.getAsString())); + json.getAsJsonObject("normal").asMap().forEach((s, tex) -> floorIconsNormal.put(s, ItemUtils.propertyMapWithTexture(tex.getAsString()))); + json.getAsJsonObject("master").asMap().forEach((s, tex) -> floorIconsMaster.put(s, ItemUtils.propertyMapWithTexture(tex.getAsString()))); LOGGER.debug("[Skyblocker] Dungeons floor skull textures json loaded"); } catch (Exception e) { LOGGER.error("[Skyblocker] Failed to load dungeons floor skull textures json", e); @@ -136,7 +138,6 @@ public class PartyFinderScreen extends Screen { int widget_height = (int) (this.height * 0.8); int entryListTopY = Math.max(43, (int) (height * 0.1)); this.partyEntryListWidget = new PartyEntryListWidget(client, width, widget_height, entryListTopY, 68); - partyEntryListWidget.setRenderBackground(false); // Search field this.searchField = new TextFieldWidget(textRenderer, partyEntryListWidget.getRowLeft() + 12, entryListTopY - 12, partyEntryListWidget.getRowWidth() - 12 * 3 - 6, 12, Text.literal("Search...")); @@ -370,7 +371,7 @@ public class PartyFinderScreen extends Screen { if (slot.id > (handler.getRows() - 1) * 9 - 1 || !slot.hasStack()) continue; if (slot.getStack().isOf(Items.PLAYER_HEAD)) { assert this.client != null; - parties.add(new PartyEntry(slot.getStack().getTooltip(this.client.player, TooltipContext.BASIC), this, slot.id)); + parties.add(new PartyEntry(ItemUtils.getLore(slot.getStack()), this, slot.id)); } else if (slot.getStack().isOf(Items.ARROW) && slot.getStack().getName().getString().toLowerCase().contains("previous")) { prevPageSlotId = slot.id; previousPageButton.active = true; @@ -399,7 +400,7 @@ public class PartyFinderScreen extends Screen { deListSlotId = slot.id; } else if (slot.getStack().isOf(Items.PLAYER_HEAD)) { assert this.client != null; - tooltips = slot.getStack().getTooltip(this.client.player, TooltipContext.BASIC); + tooltips = new ArrayList<>(ItemUtils.getLore(slot.getStack())); } } if (tooltips != null) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdos.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdos.java index c5e55f93..fd7a8dbf 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdos.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdos.java @@ -12,7 +12,7 @@ import java.util.regex.Matcher; public class ThreeWeirdos extends ChatPatternListener { public ThreeWeirdos() { - super("^§e\\[NPC] §c([A-Z][a-z]+)§f: (?:The reward is(?: not in my chest!|n't in any of our chests\\.)|My chest (?:doesn't have the reward\\. We are all telling the truth\\.|has the reward and I'm telling the truth!)|At least one of them is lying, and the reward is not in §c§c[A-Z][a-z]+'s §rchest\\!|Both of them are telling the truth\\. Also, §c§c[A-Z][a-z]+ §rhas the reward in their chest\\!)$"); + super("^\\[NPC] ([A-Z][a-z]+): (?:The reward is(?: not in my chest!|n't in any of our chests\\.)|My chest (?:doesn't have the reward\\. We are all telling the truth\\.|has the reward and I'm telling the truth!)|At least one of them is lying, and the reward is not in [A-Z][a-z]+'s chest\\!|Both of them are telling the truth\\. Also, [A-Z][a-z]+ has the reward in their chest\\!)$"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TicTacToe.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TicTacToe.java index a9b88b3d..1683276e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TicTacToe.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TicTacToe.java @@ -4,11 +4,11 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.tictactoe.BoardIndex; import de.hysky.skyblocker.utils.tictactoe.TicTacToeUtils; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.decoration.ItemFrameEntity; -import net.minecraft.item.FilledMapItem; import net.minecraft.item.map.MapState; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; @@ -50,11 +50,12 @@ public class TicTacToe extends DungeonPuzzle { try { //Only attempt to solve if the puzzle wasn't just completed and if its the player's turn - if (itemFramesThatHoldMaps.size() != 9 && itemFramesThatHoldMaps.size() % 2 == 1) { + //The low bit will always be set to 1 on odd numbers + if (itemFramesThatHoldMaps.size() != 9 && (itemFramesThatHoldMaps.size() & 1) == 1) { char[][] board = new char[3][3]; for (ItemFrameEntity itemFrame : itemFramesThatHoldMaps) { - MapState mapState = client.world.getMapState(FilledMapItem.getMapName(itemFrame.getMapId().getAsInt())); + MapState mapState = client.world.getMapState(itemFrame.getMapId()); if (mapState == null) continue; @@ -84,7 +85,7 @@ public class TicTacToe extends DungeonPuzzle { if (row == -1 || column == -1) continue; //Get the color of the middle pixel of the map which determines whether its X or O - int middleColor = mapState.colors[8256] & 255; + int middleColor = mapState.colors[8256] & 0xFF; if (middleColor == 114) { board[row][column] = 'X'; @@ -93,11 +94,11 @@ public class TicTacToe extends DungeonPuzzle { } } - int bestMove = TicTacToeUtils.getBestMove(board) - 1; + BoardIndex bestMove = TicTacToeUtils.getBestMove(board); double nextX = 8; - double nextY = 72 - (double) (bestMove / 3); - double nextZ = 17 - (bestMove % 3); + double nextY = 72 - bestMove.row(); + double nextZ = 17 - bestMove.column(); BlockPos nextPos = DungeonManager.getCurrentRoom().relativeToActual(BlockPos.ofFloored(nextX, nextY, nextZ)); nextBestMoveToMake = new Box(nextPos); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Trivia.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Trivia.java index c331bd48..eb09cf6e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Trivia.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Trivia.java @@ -2,6 +2,7 @@ package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.waypoint.FairySouls; +import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.chat.ChatFilterResult; import de.hysky.skyblocker.utils.chat.ChatPatternListener; import net.minecraft.client.MinecraftClient; @@ -23,7 +24,7 @@ public class Trivia extends ChatPatternListener { private List<String> solutions = Collections.emptyList(); public Trivia() { - super("^ +(?:([A-Za-z,' ]*\\?)|§6 ([ⓐⓑⓒ]) §a([a-zA-Z0-9 ]+))$"); + super("^ +(?:([A-Za-z,' ]*\\?)| ([ⓐⓑⓒ]) ([a-zA-Z0-9 ]+))$"); } @Override @@ -38,7 +39,7 @@ public class Trivia extends ChatPatternListener { if (!solutions.contains(riddle)) { ClientPlayerEntity player = MinecraftClient.getInstance().player; if (player != null) - MinecraftClient.getInstance().player.sendMessage(Text.of(" " + Formatting.GOLD + matcher.group(2) + Formatting.RED + " " + riddle), false); + Utils.sendMessageToBypassEvents(Text.of(" " + Formatting.GOLD + matcher.group(2) + Formatting.RED + " " + riddle)); return player != null; } } else updateSolutions(matcher.group(0)); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java index ba4b9a5f..2efadfda 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java @@ -119,13 +119,12 @@ public class Waterboard extends DungeonPuzzle { for (Cell[] row : cells) { sb.append("\n"); for (Cell cell : row) { - if (cell == null) { - sb.append('?'); - } else if (cell instanceof SwitchCell switchCell) { - sb.append(switchCell.id); - } else switch (cell.type) { - case BLOCK -> sb.append('#'); - case EMPTY -> sb.append('.'); + switch (cell) { + case SwitchCell switchCell -> sb.append(switchCell.id); + case Cell c when c.type == Cell.Type.BLOCK -> sb.append('#'); + case Cell c when c.type == Cell.Type.EMPTY -> sb.append('.'); + + case null, default -> sb.append('?'); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java index 86997cd3..8bb22e7e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java @@ -35,10 +35,12 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; +import net.minecraft.command.CommandRegistryAccess; import net.minecraft.command.CommandSource; import net.minecraft.command.argument.BlockPosArgumentType; import net.minecraft.command.argument.PosArgument; import net.minecraft.command.argument.TextArgumentType; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; @@ -244,8 +246,8 @@ public class DungeonManager { .then(literal("markAsMissing").then(markSecretsCommand(false))) .then(literal("getRelativePos").executes(DungeonManager::getRelativePos)) .then(literal("getRelativeTargetPos").executes(DungeonManager::getRelativeTargetPos)) - .then(literal("addWaypoint").then(addCustomWaypointCommand(false))) - .then(literal("addWaypointRelatively").then(addCustomWaypointCommand(true))) + .then(literal("addWaypoint").then(addCustomWaypointCommand(false, registryAccess))) + .then(literal("addWaypointRelatively").then(addCustomWaypointCommand(true, registryAccess))) .then(literal("removeWaypoint").then(removeCustomWaypointCommand(false))) .then(literal("removeWaypointRelatively").then(removeCustomWaypointCommand(true))) )))); @@ -385,11 +387,11 @@ public class DungeonManager { return Command.SINGLE_SUCCESS; } - private static RequiredArgumentBuilder<FabricClientCommandSource, PosArgument> addCustomWaypointCommand(boolean relative) { + private static RequiredArgumentBuilder<FabricClientCommandSource, PosArgument> addCustomWaypointCommand(boolean relative, CommandRegistryAccess registryAccess) { return argument("pos", BlockPosArgumentType.blockPos()) .then(argument("secretIndex", IntegerArgumentType.integer()) .then(argument("category", SecretWaypoint.Category.CategoryArgumentType.category()) - .then(argument("name", TextArgumentType.text()).executes(context -> { + .then(argument("name", TextArgumentType.text(registryAccess)).executes(context -> { // TODO Less hacky way with custom ClientBlockPosArgumentType BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); return relative ? addCustomWaypointRelative(context, pos) : addCustomWaypoint(context, pos); @@ -461,7 +463,7 @@ public class DungeonManager { context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to get dungeon map.")); return Command.SINGLE_SUCCESS; } - MapState map = FilledMapItem.getMapState(FilledMapItem.getMapId(stack), client.world); + MapState map = FilledMapItem.getMapState(stack.get(DataComponentTypes.MAP_ID), client.world); if (map == null) { context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to get dungeon map state.")); return Command.SINGLE_SUCCESS; @@ -538,7 +540,7 @@ public class DungeonManager { physicalEntrancePos = DungeonMapUtils.getPhysicalRoomPos(playerPos); currentRoom = newRoom(Room.Type.ENTRANCE, physicalEntrancePos); } - MapState map = FilledMapItem.getMapState(DungeonMap.getMapId(client.player.getInventory().main.get(8)), client.world); + MapState map = FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world); if (map == null) { return; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java index 8e0073f7..5474224a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java @@ -5,7 +5,8 @@ import it.unimi.dsi.fastutil.ints.IntSortedSet; import it.unimi.dsi.fastutil.objects.ObjectIntPair; import net.minecraft.block.Blocks; import net.minecraft.block.MapColor; -import net.minecraft.item.map.MapIcon; +import net.minecraft.item.map.MapDecoration; +import net.minecraft.item.map.MapDecorationTypes; import net.minecraft.item.map.MapState; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; @@ -45,9 +46,9 @@ public class DungeonMapUtils { @Nullable private static Vector2i getMapPlayerPos(MapState map) { - for (MapIcon icon : map.getIcons()) { - if (icon.type() == MapIcon.Type.FRAME) { - return new Vector2i((icon.x() >> 1) + 64, (icon.z() >> 1) + 64); + for (MapDecoration decoration : map.getDecorations()) { + if (decoration.type().value().equals(MapDecorationTypes.FRAME.value())) { + return new Vector2i((decoration.x() >> 1) + 64, (decoration.z() >> 1) + 64); } } return null; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java index 6e9eb02d..933fefa9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.skyblock.dungeon.terminal; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -32,7 +33,7 @@ public class ColorTerminal extends ContainerSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { trimEdges(slots, 6); List<ColorHighlight> highlights = new ArrayList<>(); String colorString = groups[0]; @@ -43,10 +44,10 @@ public class ColorTerminal extends ContainerSolver { return Collections.emptyList(); } } - for (Map.Entry<Integer, ItemStack> slot : slots.entrySet()) { + for (Int2ObjectMap.Entry<ItemStack> slot : slots.int2ObjectEntrySet()) { ItemStack itemStack = slot.getValue(); - if (!itemStack.hasEnchantments() && targetColor.equals(itemColor.get(itemStack.getItem()))) { - highlights.add(ColorHighlight.green(slot.getKey())); + if (!itemStack.hasGlint() && targetColor.equals(itemColor.get(itemStack.getItem()))) { + highlights.add(ColorHighlight.green(slot.getIntKey())); } } return highlights; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java index b2636373..4789e0f4 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java @@ -3,13 +3,13 @@ package de.hysky.skyblocker.skyblock.dungeon.terminal; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; public class OrderTerminal extends ContainerSolver { private final int PANES_NUM = 14; @@ -28,7 +28,7 @@ public class OrderTerminal extends ContainerSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { if(orderedSlots == null && !orderSlots(slots)) return Collections.emptyList(); while(currentNum < PANES_NUM && Items.LIME_STAINED_GLASS_PANE.equals(slots.get(orderedSlots[currentNum]).getItem())) @@ -41,16 +41,16 @@ public class OrderTerminal extends ContainerSolver { return highlights; } - public boolean orderSlots(Map<Integer, ItemStack> slots) { + public boolean orderSlots(Int2ObjectMap<ItemStack> slots) { trimEdges(slots, 4); orderedSlots = new int[PANES_NUM]; - for(Map.Entry<Integer, ItemStack> slot : slots.entrySet()) { + for(Int2ObjectMap.Entry<ItemStack> slot : slots.int2ObjectEntrySet()) { if(Items.AIR.equals(slot.getValue().getItem())) { orderedSlots = null; return false; } else - orderedSlots[slot.getValue().getCount() - 1] = slot.getKey(); + orderedSlots[slot.getValue().getCount() - 1] = slot.getIntKey(); } currentNum = 0; return true; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java index 5f856af2..0bfb896e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java @@ -3,33 +3,124 @@ package de.hysky.skyblocker.skyblock.dungeon.terminal; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import java.util.ArrayList; import java.util.List; -import java.util.Map; +import java.util.function.Predicate; public class StartsWithTerminal extends ContainerSolver { - public StartsWithTerminal() { - super("^What starts with: '([A-Z])'\\?$"); - } - - @Override - protected boolean isEnabled() { - return SkyblockerConfigManager.get().locations.dungeons.terminals.solveStartsWith; - } - - @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { - trimEdges(slots, 6); - String prefix = groups[0]; - List<ColorHighlight> highlights = new ArrayList<>(); - for (Map.Entry<Integer, ItemStack> slot : slots.entrySet()) { - ItemStack stack = slot.getValue(); - if (!stack.hasEnchantments() && stack.getName().getString().startsWith(prefix)) { - highlights.add(ColorHighlight.green(slot.getKey())); - } - } - return highlights; - } + private final Int2ObjectOpenHashMap<ItemState> trackedItemStates = new Int2ObjectOpenHashMap<>(); + private int lastKnownScreenId = Integer.MIN_VALUE; + + public StartsWithTerminal() { + super("^What starts with: '([A-Z])'\\?$"); + } + + @Override + protected boolean isEnabled() { + return SkyblockerConfigManager.get().locations.dungeons.terminals.solveStartsWith; + } + + @Override + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { + trimEdges(slots, 6); + setupState(slots); + + String prefix = groups[0]; + List<ColorHighlight> highlights = new ArrayList<>(); + + for (Int2ObjectMap.Entry<ItemStack> slot : slots.int2ObjectEntrySet()) { + ItemStack stack = slot.getValue(); + ItemState state = trackedItemStates.getOrDefault(slot.getIntKey(), ItemState.DEFAULT); + + //If the item hasn't been marked as clicked and it matches the starts with condition + //We keep track of the clicks ourselves instead of using the enchantment glint because some items like nether stars have the glint override component by default + //so even if Hypixel tries to change that to the same thing it was before (true) it won't work and the solver would permanently consider the item to be clicked + //even if it hasn't been yet + if (!state.clicked() && stack.getName().getString().startsWith(prefix)) { + highlights.add(ColorHighlight.green(slot.getIntKey())); + } + } + return highlights; + } + + @Override + protected void onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) { + //Some random glass pane was clicked or something + if (!trackedItemStates.containsKey(slot) || stack == null || stack.isEmpty()) return; + + ItemState state = trackedItemStates.get(slot); + String prefix = groups[0]; + + //If the item stack's name starts with the correct letter + //Also, since Hypixel closes & reopens the GUI after every click we check if the last known screen id is the same that way in case the server lags and + //either a player tries to click a second item or if the player puts the clicked item back and tries to click another that we don't mark multiple items + //as clicked when only the first one will count. + + //While Hypixel does use a different syncId each time they open the screen we opt to use our own so as to avoid them potentially changing that + //and in turn breaking this logic + if (stack.getName().getString().startsWith(prefix) && !state.clicked() && lastKnownScreenId != screenId) { + trackedItemStates.put(slot, state.click()); + lastKnownScreenId = screenId; + } + //In the future we could add an else branch and return a boolean to cancel the click since it would be wrong + + return; + } + + //We only setup the state when all items aren't null or empty. This prevents the state from being reset due to unsent items or server lag spikes/bad TPS (fix ur servers Hypixel) + private void setupState(Int2ObjectMap<ItemStack> usefulSlots) { + Predicate<Int2ObjectMap.Entry<ItemStack>> notNullOrEmpty = e -> e.getValue() != null && !e.getValue().isEmpty(); + + if (allEntriesMatch(usefulSlots.int2ObjectEntrySet(), notNullOrEmpty)) { + //If the state hasn't been setup then we will do that + if (trackedItemStates.isEmpty()) { + for (Int2ObjectMap.Entry<ItemStack> entry : usefulSlots.int2ObjectEntrySet()) { + trackedItemStates.put(entry.getIntKey(), ItemState.of(entry.getValue().getItem())); + } + } else { //If the state is setup then we verify that it hasn't changed since last time, and if it has then we will clear it and call this method again to set it up + //Checks whether the trackedItemStates contains the slot id and if it does it checks whether the tracked state's item is a 1:1 match + Predicate<Int2ObjectMap.Entry<ItemStack>> doesItemMatch = e -> trackedItemStates.containsKey(e.getIntKey()) && trackedItemStates.get(e.getIntKey()).itemMatches(e.getValue().getItem()); + + if (!allEntriesMatch(usefulSlots.int2ObjectEntrySet(), doesItemMatch)) { + clearState(); + setupState(usefulSlots); + } + } + } + } + + private void clearState() { + trackedItemStates.clear(); + lastKnownScreenId = Integer.MIN_VALUE; + } + + private static boolean allEntriesMatch(ObjectSet<Int2ObjectMap.Entry<ItemStack>> entries, Predicate<Int2ObjectMap.Entry<ItemStack>> predicate) { + for (Int2ObjectMap.Entry<ItemStack> entry : entries) { + if (!predicate.test(entry)) return false; + } + + return true; + } + + private record ItemState(Item item, boolean clicked) { + private static final ItemState DEFAULT = new ItemState(null, false); + + boolean itemMatches(Item item) { + return this.item.equals(item); + } + + ItemState click() { + return new ItemState(item, true); + } + + static ItemState of(Item item) { + return new ItemState(item, false); + } + } }
\ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java index 79e81ad0..a4af804c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java @@ -2,16 +2,15 @@ package de.hysky.skyblocker.skyblock.dwarven; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationAxis; import org.joml.Vector2i; import org.joml.Vector2ic; @@ -23,9 +22,10 @@ import java.util.Map; public class CrystalsHud { private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); protected static final Identifier MAP_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/crystals_map.png"); - private static final Identifier MAP_ICON = new Identifier("textures/map/map_icons.png"); + private static final Identifier MAP_ICON = new Identifier("textures/map/decorations/player.png"); private static final List<String> SMALL_LOCATIONS = List.of("Fairy Grotto", "King Yolkar", "Corleone", "Odawa", "Key Guardian"); + public static boolean visible = false; public static void init() { @@ -34,7 +34,7 @@ public class CrystalsHud { .then(ClientCommandManager.literal("crystals") .executes(Scheduler.queueOpenScreenCommand(CrystalsHudConfigScreen::new)))))); - HudRenderCallback.EVENT.register((context, tickDelta) -> { + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickDelta) -> { if (!SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enabled || CLIENT.player == null || !visible) { @@ -65,7 +65,7 @@ public class CrystalsHud { //and set position and scale MatrixStack matrices = context.getMatrices(); matrices.push(); - matrices.translate(hudX, hudY, 200f); + matrices.translate(hudX, hudY, 0f); matrices.scale(scale, scale, 0f); //draw map texture @@ -109,7 +109,7 @@ public class CrystalsHud { matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(yaw2Cardinal(playerRotation)), 2.5f, 3.5f, 0); //draw marker on map - context.drawTexture(MAP_ICON, 0, 0, 2, 0, 5, 7, 128, 128); + context.drawTexture(MAP_ICON, 0, 0, 2, 0, 5, 7, 8, 8); //todo add direction (can not work out how to rotate) matrices.pop(); @@ -126,8 +126,8 @@ public class CrystalsHud { //converts an x and z to a location on the map int transformedX = (int) ((x - 202) / 621 * 62); int transformedY = (int) ((z - 202) / 621 * 62); - transformedX = MathHelper.clamp(transformedX, 0, 62); - transformedY = MathHelper.clamp(transformedY, 0, 62); + transformedX = Math.clamp(transformedX, 0, 62); + transformedY = Math.clamp(transformedY, 0, 62); return new Vector2i(transformedX, transformedY); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java index 86a8e685..a5b9fa24 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.skyblock.dwarven; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; +import de.hysky.skyblocker.mixins.accessors.PlayerListHudAccessor; import de.hysky.skyblocker.skyblock.tabhud.util.Colors; import de.hysky.skyblocker.skyblock.tabhud.widget.hud.HudCommsWidget; import de.hysky.skyblocker.skyblock.tabhud.widget.hud.HudPowderWidget; @@ -8,7 +10,6 @@ import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.network.PlayerListEntry; @@ -32,7 +33,7 @@ public class DwarvenHud { private static final List<Pattern> COMMISSIONS = Stream.of( "(?:Titanium|Mithril|Hard Stone) Miner", - "(?:Glacite Walker|Golden Goblin|(?<!Golden )Goblin|Goblin Raid|Treasure Hoarder|Automaton|Sludge|Team Treasurite Member|Yog|Boss Corleone|Thyst) Slayer", + "(?:Glacite Walker|Golden Goblin|(?<!Golden )Goblin|Goblin Raid|Treasure Hoarder|Automaton|Sludge|Team Treasurite Member|Yog|Boss Corleone|Thyst|Maniac) Slayer", "(?:Lava Springs|Cliffside Veins|Rampart's Quarry|Upper Mines|Royal Mines) Mithril", "(?:Lava Springs|Cliffside Veins|Rampart's Quarry|Upper Mines|Royal Mines) Titanium", "Goblin Raid", @@ -60,7 +61,7 @@ public class DwarvenHud { ) )); - HudRenderCallback.EVENT.register((context, tickDelta) -> { + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickDelta) -> { if (!SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledCommissions && !SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledPowder || CLIENT.options.playerListKey.isPressed() || CLIENT.player == null @@ -169,7 +170,7 @@ public class DwarvenHud { commissionList = new ArrayList<>(); - for (PlayerListEntry playerListEntry : CLIENT.getNetworkHandler().getPlayerList()) { + for (PlayerListEntry playerListEntry : CLIENT.getNetworkHandler().getPlayerList().stream().sorted(PlayerListHudAccessor.getOrdering()).toList()) { if (playerListEntry.getDisplayName() == null) { continue; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Fetchur.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Fetchur.java index 27cd62ad..2ddaf6b5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Fetchur.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Fetchur.java @@ -18,7 +18,7 @@ public class Fetchur extends ChatPatternListener { private static final Map<String, String> answers; public Fetchur() { - super("^§e\\[NPC] Fetchur§f: (?:its|theyre) ([a-zA-Z, \\-]*)$"); + super("^\\[NPC] Fetchur: (?:its|theyre) ([a-zA-Z, \\-]*)$"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Puzzler.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Puzzler.java index fae845b5..1f5c0c90 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Puzzler.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/Puzzler.java @@ -13,7 +13,7 @@ import java.util.regex.Matcher; public class Puzzler extends ChatPatternListener { public Puzzler() { - super("^§e\\[NPC] §dPuzzler§f: ((?:§d▲|§5▶|§b◀|§a▼){10})$"); + super("^\\[NPC] Puzzler: ((?:▲|▶|◀|▼){10})$"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java index 30de9a48..ca3c8cd8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java @@ -4,6 +4,8 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; import de.hysky.skyblocker.skyblock.tabhud.widget.component.IcoTextComponent; import de.hysky.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ProfileComponent; import net.minecraft.enchantment.Enchantments; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -12,6 +14,9 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import java.text.NumberFormat; +import java.util.Optional; + +import com.mojang.authlib.properties.PropertyMap; public class EndHudWidget extends Widget { private static final MutableText TITLE = Text.literal("The End").formatted(Formatting.LIGHT_PURPLE, Formatting.BOLD); @@ -29,7 +34,7 @@ public class EndHudWidget extends Widget { private static final ItemStack POPPY = new ItemStack(Items.POPPY); static { - ENDERMAN_HEAD.getOrCreateNbt().putString("SkullOwner", "MHF_Enderman"); + ENDERMAN_HEAD.set(DataComponentTypes.PROFILE, new ProfileComponent(Optional.of("MHF_Enderman"), Optional.empty(), new PropertyMap())); POPPY.addEnchantment(Enchantments.INFINITY, 1); INSTANCE.setX(SkyblockerConfigManager.get().locations.end.x); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java b/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java index a093f598..6f2a0e40 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java @@ -4,13 +4,13 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; @@ -73,7 +73,7 @@ public class TheEnd { }); - HudRenderCallback.EVENT.register((drawContext, tickDelta) -> { + HudRenderEvents.AFTER_MAIN_HUD.register((drawContext, tickDelta) -> { if (!Utils.isInTheEnd()) return; if (!SkyblockerConfigManager.get().locations.end.hudEnabled) return; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java index b969ba0b..5522ceca 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobBoundingBoxes.java @@ -1,7 +1,5 @@ package de.hysky.skyblocker.skyblock.entity; -import java.util.List; - import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.FrustumUtils; @@ -31,20 +29,13 @@ public class MobBoundingBoxes { if (Utils.isInDungeons() && FrustumUtils.isVisible(box) && !entity.isInvisible()) { String name = entity.getName().getString(); - // Minibosses - if (entity instanceof PlayerEntity) { - switch (name) { - case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobBoundingBoxes; - } - } - - // Regular Mobs - if (!(entity instanceof ArmorStandEntity)) { - List<ArmorStandEntity> armorStands = MobGlow.getArmorStands(entity); + return switch (entity) { + case PlayerEntity _p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> SkyblockerConfigManager.get().locations.dungeons.starredMobBoundingBoxes; + case ArmorStandEntity _armorStand -> false; - if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) - return SkyblockerConfigManager.get().locations.dungeons.starredMobBoundingBoxes; - } + // Regular Mobs + default -> SkyblockerConfigManager.get().locations.dungeons.starredMobBoundingBoxes && MobGlow.isStarred(entity); + }; } return false; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index 12ae468f..75ba700e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -1,19 +1,22 @@ package de.hysky.skyblocker.skyblock.entity; +import com.mojang.authlib.properties.Property; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.dungeon.LividColor; +import de.hysky.skyblocker.skyblock.end.TheEnd; +import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.SlayerUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ProfileComponent; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.mob.EndermanEntity; import net.minecraft.entity.passive.BatEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; +import net.minecraft.item.Items; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.util.Formatting; import net.minecraft.util.math.Box; @@ -29,57 +32,52 @@ public class MobGlow { if (OcclusionCulling.getReducedCuller().isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { String name = entity.getName().getString(); - if (!entity.isInvisible()) { + // Dungeons + if (Utils.isInDungeons() && !entity.isInvisible()) { + return switch (entity) { + // Minibosses + case PlayerEntity p when name.equals("Lost Adventurer") || name.equals("Shadow Assassin") || name.equals("Diamond Guy") -> SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; + case PlayerEntity p when LividColor.LIVID_NAMES.contains(name) -> LividColor.shouldGlow(name); - // Dungeons - if (Utils.isInDungeons()) { + // Bats + case BatEntity b -> SkyblockerConfigManager.get().locations.dungeons.starredMobGlow || SkyblockerConfigManager.get().locations.dungeons.starredMobBoundingBoxes; - // Minibosses - if (entity instanceof PlayerEntity) { - switch (name) { - case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; - case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", - "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid": return LividColor.shouldGlow(name); - } - } + // Armor Stands + case ArmorStandEntity _armorStand -> false; // Regular Mobs - if (!(entity instanceof ArmorStandEntity)) { - List<ArmorStandEntity> armorStands = getArmorStands(entity); + default -> SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && isStarred(entity); + }; + } - if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) - return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; - } + return switch (entity) { + // Rift + case PlayerEntity p when Utils.isInTheRift() && !entity.isInvisible() && name.equals("Blobbercyst ") -> SkyblockerConfigManager.get().locations.rift.blobbercystGlow; - // Bats - return (SkyblockerConfigManager.get().locations.dungeons.starredMobGlow || SkyblockerConfigManager.get().locations.dungeons.starredMobBoundingBoxes) && entity instanceof BatEntity; - } + // Enderman Slayer + // Highlights Nukekubi Heads + case ArmorStandEntity armorStand when Utils.isInTheEnd() && SlayerUtils.isInSlayer() && isNukekubiHead(armorStand) -> SkyblockerConfigManager.get().slayer.endermanSlayer.highlightNukekubiHeads; - // Rift - if (Utils.isInTheRift()) { - if (entity instanceof PlayerEntity) { - switch (name) { - // They have a space in their name for some reason... - case "Blobbercyst ": return SkyblockerConfigManager.get().locations.rift.blobbercystGlow; - } - } - } - } + // Special Zelot + case EndermanEntity enderman when Utils.isInTheEnd() && !entity.isInvisible() -> TheEnd.isSpecialZealot(enderman); - // Enderman Slayer - // Highlights Nukekubi Heads - return SkyblockerConfigManager.get().slayer.endermanSlayer.highlightNukekubiHeads - && SlayerUtils.isInSlayer() - && entity instanceof ArmorStandEntity armorStandEntity - && isNukekubiHead(armorStandEntity); + default -> false; + }; } - // Special Zelot - if (entity instanceof EndermanEntity enderman && TheEnd.isSpecialZealot(enderman)) return true; - return false; } + /** + * Checks if an entity is starred by checking if its armor stand contains a star in its name. + * @param entity the entity to check. + * @return true if the entity is starred, false otherwise + */ + public static boolean isStarred(Entity entity) { + List<ArmorStandEntity> armorStands = getArmorStands(entity); + return !armorStands.isEmpty() && armorStands.getFirst().getName().getString().contains("✯"); + } + public static List<ArmorStandEntity> getArmorStands(Entity entity) { return getArmorStands(entity.getWorld(), entity.getBoundingBox()); } @@ -91,45 +89,28 @@ public class MobGlow { public static int getGlowColor(Entity entity) { String name = entity.getName().getString(); - if (entity instanceof PlayerEntity) { - return switch (name) { - case "Lost Adventurer" -> 0xfee15c; - case "Shadow Assassin" -> 0x5b2cb2; - case "Diamond Guy" -> 0x57c2f7; - case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", - "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid" -> LividColor.getGlowColor(name); - case "Blobbercyst " -> Formatting.GREEN.getColorValue(); - default -> 0xf57738; - }; - } - if (entity instanceof EndermanEntity enderman && TheEnd.isSpecialZealot(enderman)) return Formatting.RED.getColorValue(); + return switch (entity) { + case PlayerEntity p when name.equals("Lost Adventurer") -> 0xfee15c; + case PlayerEntity p when name.equals("Shadow Assassin") -> 0x5b2cb2; + case PlayerEntity p when name.equals("Diamond Guy") -> 0x57c2f7; + case PlayerEntity p when LividColor.LIVID_NAMES.contains(name) -> LividColor.getGlowColor(name); + case PlayerEntity p when name.equals("Blobbercyst ") -> Formatting.GREEN.getColorValue(); - // copypaste nukekebi head logic - if (entity instanceof ArmorStandEntity armorStandEntity && isNukekubiHead(armorStandEntity)) return 0x990099; + case EndermanEntity enderman when TheEnd.isSpecialZealot(enderman) -> Formatting.RED.getColorValue(); + case ArmorStandEntity armorStand when isNukekubiHead(armorStand) -> 0x990099; - return 0xf57738; + default -> 0xf57738; + }; } private static boolean isNukekubiHead(ArmorStandEntity entity) { for (ItemStack armorItem : entity.getArmorItems()) { - // hacky way to check if an item is a player head w/o - // some shenanigans - if (!armorItem.toString().startsWith("1 player_head")) - continue; - // eb07594e2df273921a77c101d0bfdfa1115abed5b9b2029eb496ceba9bdbb4b3 is texture id for the nukekubi head, // compare against it to exclusively find armorstands that are nukekubi heads - NbtCompound skullOwner = armorItem.getSubNbt("SkullOwner"); - if (skullOwner != null) { - // get the texture of the nukekubi head item itself and compare it - String texture = skullOwner - .getCompound("Properties") - .getList("textures", NbtElement.COMPOUND_TYPE) - .getCompound(0) - .getString("Value"); - - return texture.contains("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0="); - } + // get the texture of the nukekubi head item itself and compare it + String texture = ItemUtils.getHeadTexture(armorItem); + + return texture.contains("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0="); } return false; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java index 19459b43..98738112 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.inventory.Inventory; @@ -14,7 +15,6 @@ import net.minecraft.item.Items; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class ChronomatronSolver extends ExperimentSolver { public static final ImmutableMap<Item, Item> TERRACOTTA_TO_GLASS = ImmutableMap.ofEntries( @@ -64,7 +64,7 @@ public class ChronomatronSolver extends ExperimentSolver { Inventory inventory = genericContainerScreen.getScreenHandler().getInventory(); if (chronomatronCurrentSlot == 0) { for (int index = 10; index < 43; index++) { - if (inventory.getStack(index).hasEnchantments()) { + if (inventory.getStack(index).hasGlint()) { if (chronomatronSlots.size() <= chronomatronChainLengthCount) { chronomatronSlots.add(TERRACOTTA_TO_GLASS.get(inventory.getStack(index).getItem())); setState(State.WAIT); @@ -75,7 +75,7 @@ public class ChronomatronSolver extends ExperimentSolver { return; } } - } else if (!inventory.getStack(chronomatronCurrentSlot).hasEnchantments()) { + } else if (!inventory.getStack(chronomatronCurrentSlot).hasGlint()) { chronomatronCurrentSlot = 0; } } @@ -103,11 +103,11 @@ public class ChronomatronSolver extends ExperimentSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { List<ColorHighlight> highlights = new ArrayList<>(); if (getState() == State.SHOW && chronomatronSlots.size() > chronomatronCurrentOrdinal) { - for (Map.Entry<Integer, ItemStack> indexStack : slots.entrySet()) { - int index = indexStack.getKey(); + for (Int2ObjectMap.Entry<ItemStack> indexStack : slots.int2ObjectEntrySet()) { + int index = indexStack.getIntKey(); ItemStack stack = indexStack.getValue(); Item item = chronomatronSlots.get(chronomatronCurrentOrdinal); if (stack.isOf(item) || TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java index c34abca1..e7502c89 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java @@ -2,6 +2,7 @@ package de.hysky.skyblocker.skyblock.experiment; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.item.ItemStack; @@ -62,11 +63,11 @@ public class SuperpairsSolver extends ExperimentSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> displaySlots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> displaySlots) { List<ColorHighlight> highlights = new ArrayList<>(); if (getState() == State.SHOW) { - for (Map.Entry<Integer, ItemStack> indexStack : displaySlots.entrySet()) { - int index = indexStack.getKey(); + for (Int2ObjectMap.Entry<ItemStack> indexStack : displaySlots.int2ObjectEntrySet()) { + int index = indexStack.getIntKey(); ItemStack displayStack = indexStack.getValue(); ItemStack stack = getSlots().get(index); if (stack != null && !ItemStack.areEqual(stack, displayStack)) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java index 4e87b237..3f1fc72d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java @@ -2,6 +2,7 @@ package de.hysky.skyblocker.skyblock.experiment; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.inventory.Inventory; @@ -9,7 +10,6 @@ import net.minecraft.item.ItemStack; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class UltrasequencerSolver extends ExperimentSolver { public static final UltrasequencerSolver INSTANCE = new UltrasequencerSolver(); @@ -76,7 +76,7 @@ public class UltrasequencerSolver extends ExperimentSolver { } @Override - protected List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots) { + protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { return getState() == State.SHOW && ultrasequencerNextSlot != 0 ? List.of(ColorHighlight.green(ultrasequencerNextSlot)) : new ArrayList<>(); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java index a960c9af..2ee119fe 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java @@ -185,7 +185,7 @@ public class FancyStatusBars { // FIX SIZES int totalSize = 0; for (StatusBar statusBar : barRow) - totalSize += (statusBar.size = MathHelper.clamp(statusBar.size, sizeRule.minSize(), sizeRule.maxSize())); + totalSize += (statusBar.size = Math.clamp(statusBar.size, sizeRule.minSize(), sizeRule.maxSize())); whileLoop: while (totalSize != sizeRule.targetSize()) { @@ -240,7 +240,7 @@ public class FancyStatusBars { } } StatusBar statusBar = barRow.get(i); - statusBar.size = MathHelper.clamp(statusBar.size, sizeRule.minSize(), sizeRule.maxSize()); + statusBar.size = Math.clamp(statusBar.size, sizeRule.minSize(), sizeRule.maxSize()); float x = barAnchor.isRight() ? anchorPosition.x() + currSize * widthPerSize : diff --git a/src/main/java/de/hysky/skyblocker/skyblock/filters/AdFilter.java b/src/main/java/de/hysky/skyblocker/skyblock/filters/AdFilter.java index 5860b41e..5c9cd4a5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/filters/AdFilter.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/filters/AdFilter.java @@ -19,8 +19,8 @@ public class AdFilter extends ChatPatternListener { // Groups: // 1. Player name // 2. Message - // (?:§8\[[§feadbc0-9]+§8\] )?(?:[§76l]+[<INSERT EMBLEMS>] )?§[67abc](?:\[[§A-Za-z0-9+]+\] )?([A-Za-z0-9_]+)§[f7]: (.+) - super("(?:§8\\[[§feadbc0-9]+§8\\] )?(?:[§76l]+[" + Constants.LEVEL_EMBLEMS + "] )?§[67abc](?:\\[[§A-Za-z0-9+]+\\] )?([A-Za-z0-9_]+)§[f7]: (.+)"); + // (?:\[[0-9]+\] )?(?:[<INSERT EMBLEMS>] )?(?:\[[A-Z+]+\] )?([A-Za-z0-9_]+): (.+) + super("(?:\\[[0-9]+\\] )?(?:[" + Constants.LEVEL_EMBLEMS+ "] )?(?:\\[[A-Z+]+\\] )?([A-Za-z0-9_]+): (.+)"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/filters/AutopetFilter.java b/src/main/java/de/hysky/skyblocker/skyblock/filters/AutopetFilter.java index f97e8177..958be11e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/filters/AutopetFilter.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/filters/AutopetFilter.java @@ -11,7 +11,7 @@ import java.util.regex.Matcher; public class AutopetFilter extends ChatPatternListener { public AutopetFilter() { - super("^§cAutopet §eequipped your §7.*§e! §a§lVIEW RULE$"); + super("^Autopet equipped your .*! VIEW RULE$"); } @Override @@ -19,7 +19,7 @@ public class AutopetFilter extends ChatPatternListener { if (SkyblockerConfigManager.get().messages.hideAutopet == ChatFilterResult.ACTION_BAR) { Objects.requireNonNull(MinecraftClient.getInstance().player).sendMessage( Text.literal( - _message.getString().replace("§a§lVIEW RULE", "") + _message.getString().replace("VIEW RULE", "") ), true); } return true; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilter.java b/src/main/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilter.java index a9c551fb..84d32007 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilter.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilter.java @@ -8,7 +8,8 @@ public class ShowOffFilter extends SimpleChatFilter { private static final String[] SHOW_TYPES = { "is holding", "is wearing", "is friends with a", "has" }; public ShowOffFilter() { - super("(?:§8\\[[§feadbc0-9]+§8\\] )?(?:[§76l]+[" + Constants.LEVEL_EMBLEMS + "] )?§[67abc](?:\\[[§A-Za-z0-9+]+\\] )?([A-Za-z0-9_]+)[§f7]+ (?:" + String.join("|", SHOW_TYPES) + ") §8\\[(.+)§8\\]"); + //(?:\[[0-9]+\] )?(?:[<INSERT EMBLEMS>] )?(?:\[[A-Z+]+\] )?([A-Za-z0-9_]+) (?:<INSERT SHOW TYPES>) \[(.+)\] + super("(?:\\[[0-9]+\\] )?(?:[" + Constants.LEVEL_EMBLEMS + "] )?(?:\\[[A-Z+]+\\] )?([A-Za-z0-9_]+) (?:" + String.join("|", SHOW_TYPES) + ") \\[(.+)\\]"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/filters/ToggleSkyMallFilter.java b/src/main/java/de/hysky/skyblocker/skyblock/filters/ToggleSkyMallFilter.java index 94d10e3a..6ee13aff 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/filters/ToggleSkyMallFilter.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/filters/ToggleSkyMallFilter.java @@ -6,7 +6,7 @@ import de.hysky.skyblocker.utils.chat.ChatFilterResult; public class ToggleSkyMallFilter extends SimpleChatFilter { public ToggleSkyMallFilter() { - super("^§8§oYou can disable this messaging by toggling Sky Mall in your /hotm!$"); + super("^You can disable this messaging by toggling Sky Mall in your /hotm!$"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java index fe93813f..43fdf001 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java @@ -2,6 +2,7 @@ package de.hysky.skyblocker.skyblock.garden; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Location; import de.hysky.skyblocker.utils.Utils; @@ -12,7 +13,6 @@ import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; import it.unimi.dsi.fastutil.longs.LongPriorityQueue; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.item.ItemStack; @@ -41,7 +41,7 @@ public class FarmingHud { private static float farmingXpPercentProgress; public static void init() { - HudRenderCallback.EVENT.register((context, tickDelta) -> { + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickDelta) -> { if (shouldRender()) { if (!counter.isEmpty() && counter.peek().rightLong() + 10_000 < System.currentTimeMillis()) { counter.poll(); @@ -54,7 +54,7 @@ public class FarmingHud { } ItemStack stack = MinecraftClient.getInstance().player.getMainHandStack(); - Matcher matcher = ItemUtils.getNbtTooltip(stack, FarmingHud.COUNTER); + Matcher matcher = ItemUtils.getLoreLineIfMatch(stack, FarmingHud.COUNTER); if (matcher != null) { try { int count = NUMBER_FORMAT.parse(matcher.group("count")).intValue(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java index 6640d413..c855c3e3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java @@ -2,24 +2,24 @@ package de.hysky.skyblocker.skyblock.garden; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; +import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.NEURepoManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import io.github.moulberry.repo.data.NEUItem; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.component.DataComponentTypes; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.nbt.NbtList; import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Text; -import net.minecraft.text.Text.Serialization; import net.minecraft.util.Formatting; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory; import java.text.NumberFormat; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; @@ -34,7 +35,8 @@ import java.util.Map; public class VisitorHelper { private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Visitor Helper"); - private static final Map<String, Object2IntMap<String>> itemMap = new HashMap<>(); + // The pair contains the name of the visitor and the texture if the icon is a player head + private static final Map<Pair<String, String>, Object2IntMap<String>> itemMap = new HashMap<>(); private static final Map<String, ItemStack> itemCache = new HashMap<>(); private static final int TEXT_START_X = 4; private static final int TEXT_START_Y = 4; @@ -58,7 +60,7 @@ public class VisitorHelper { public static void onMouseClicked(double mouseX, double mouseY, int mouseButton, TextRenderer textRenderer) { int yPosition = TEXT_START_Y; - for (Map.Entry<String, Object2IntMap<String>> visitorEntry : itemMap.entrySet()) { + for (Map.Entry<Pair<String, String>, Object2IntMap<String>> visitorEntry : itemMap.entrySet()) { int textWidth; int textHeight = textRenderer.fontHeight; @@ -77,47 +79,50 @@ public class VisitorHelper { } } - public static void onSlotClick(Slot slot, int slotId, String title) { + public static void onSlotClick(Slot slot, int slotId, String title, ItemStack visitorHeadStack) { if (slotId == 29 || slotId == 13 || slotId == 33) { - itemMap.remove(title); + itemMap.remove(new ObjectObjectImmutablePair<>(title, getTextureOrNull(visitorHeadStack))); } } private static void processVisitorItem(String visitorName, ScreenHandler handler) { ItemStack visitorItem = handler.getSlot(13).getStack(); - if (visitorItem == null || !visitorItem.hasNbt() || !visitorItem.getNbt().asString().contains("Times Visited")) return; + if (visitorItem == null || !visitorItem.contains(DataComponentTypes.LORE) || ItemUtils.getLoreLineIf(visitorItem, t -> t.contains("Times Visited")) == null) return; ItemStack acceptButton = handler.getSlot(29).getStack(); if (acceptButton == null) return; - NbtCompound acceptButtonNbt = acceptButton.getSubNbt("display"); - if (acceptButtonNbt == null || !acceptButtonNbt.contains("Lore", NbtElement.LIST_TYPE)) return; - processLore(visitorName, acceptButtonNbt.getList("Lore", NbtElement.STRING_TYPE)); + processLore(visitorName, getTextureOrNull(visitorItem), ItemUtils.getLore(acceptButton)); } - private static void processLore(String visitorName, NbtList loreList) { + private static @Nullable String getTextureOrNull(ItemStack stack) { + String texture = ItemUtils.getHeadTexture(stack); + + return texture.isEmpty() ? null : texture; + } + + private static void processLore(String visitorName, @Nullable String visitorTexture, List<Text> loreList) { boolean saveRequiredItems = false; - for (int i = 0; i < loreList.size(); i++) { - String lore = loreList.getString(i); + for (Text text : loreList) { + String lore = text.getString(); if (lore.contains("Items Required")) saveRequiredItems = true; else if (lore.contains("Rewards")) break; else if (saveRequiredItems) - updateItemMap(visitorName, lore); + updateItemMap(visitorName, visitorTexture, text); } } - private static void updateItemMap(String visitorName, String lore) { - Text itemText = Serialization.fromJson(lore); - String[] splitItemText = itemText.getString().split(" x"); + private static void updateItemMap(String visitorName, @Nullable String visitorTexture, Text lore) { + String[] splitItemText = lore.getString().split(" x"); String itemName = splitItemText[0].trim(); if (itemName.isEmpty()) return; try { int amount = splitItemText.length == 2 ? NumberFormat.getInstance(Locale.US).parse(splitItemText[1].trim()).intValue() : 1; - Object2IntMap<String> visitorMap = itemMap.getOrDefault(visitorName, new Object2IntOpenHashMap<>()); - visitorMap.putIfAbsent(itemName, amount); - itemMap.putIfAbsent(visitorName, visitorMap); + Pair<String, String> key = Pair.of(visitorName, visitorTexture); + Object2IntMap<String> visitorMap = itemMap.computeIfAbsent(key, _key -> new Object2IntOpenHashMap<>()); + visitorMap.put(itemName, amount); } catch (Exception e) { - LOGGER.error("[Skyblocker Visitor Helper] Failed to parse item: " + itemText.getString(), e); + LOGGER.error("[Skyblocker Visitor Helper] Failed to parse item: {}", lore.getString(), e); } } @@ -125,9 +130,9 @@ public class VisitorHelper { context.getMatrices().push(); context.getMatrices().translate(0, 0, 200); int index = 0; - for (Map.Entry<String, Object2IntMap<String>> visitorEntry : itemMap.entrySet()) { - String visitorName = visitorEntry.getKey(); - drawTextWithOptionalUnderline(context, textRenderer, Text.literal(visitorName), TEXT_START_X, TEXT_START_Y + index * (LINE_SPACING + textRenderer.fontHeight), mouseX, mouseY); + for (Map.Entry<Pair<String, String>, Object2IntMap<String>> visitorEntry : itemMap.entrySet()) { + Pair<String, String> visitorName = visitorEntry.getKey(); + drawTextWithOptionalUnderline(context, textRenderer, Text.literal(visitorName.left()), TEXT_START_X, TEXT_START_Y + index * (LINE_SPACING + textRenderer.fontHeight), mouseX, mouseY); index++; for (Object2IntMap.Entry<String> itemEntry : visitorEntry.getValue().object2IntEntrySet()) { @@ -149,6 +154,7 @@ public class VisitorHelper { String strippedName = Formatting.strip(displayName); ItemStack cachedStack = itemCache.get(strippedName); if (cachedStack != null) return cachedStack; + if (NEURepoManager.isLoading() || !ItemRepository.filesImported()) return null; // Item repo might be taking its sweet time doing things and cause concurrent modification error Map<String, NEUItem> items = NEURepoManager.NEU_REPO.getItems().getItems(); if (items == null) return null; ItemStack stack = items.values().stream() @@ -163,7 +169,7 @@ public class VisitorHelper { } private static void drawItemEntryWithHover(DrawContext context, TextRenderer textRenderer, @Nullable ItemStack stack, String itemName, int amount, int index, int mouseX, int mousseY) { - Text text = stack != null ? Serialization.fromJson(stack.getSubNbt("display").getString("Name")).append(" x" + amount) : Text.literal(itemName + " x" + amount); + Text text = stack != null ? stack.getName().copy().append(" x" + amount) : Text.literal(itemName + " x" + amount); drawTextWithOptionalUnderline(context, textRenderer, text, TEXT_START_X + TEXT_INDENT, TEXT_START_Y + (index * (LINE_SPACING + textRenderer.fontHeight)), mouseX, mousseY); // drawItem adds 150 to the z, which puts our z at 350, above the item in the slot (250) and their text (300) and below the cursor stack (382) and their text (432) if (stack != null) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java index b011b2b0..4440cd84 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java @@ -22,8 +22,8 @@ import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallba import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.item.DyeableItem; import net.minecraft.item.ItemStack; +import net.minecraft.registry.tag.ItemTags; import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; @@ -62,7 +62,7 @@ public class CustomArmorAnimatedDyes { ItemStack heldItem = source.getPlayer().getMainHandStack(); if (Utils.isOnSkyblock() && heldItem != null && !heldItem.isEmpty()) { - if (heldItem.getItem() instanceof DyeableItem) { + if (heldItem.isIn(ItemTags.DYEABLE)) { String itemUuid = ItemUtils.getItemUuid(heldItem); if (!itemUuid.isEmpty()) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java index 639e98ed..97311220 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java @@ -12,8 +12,8 @@ import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.item.DyeableItem; import net.minecraft.item.ItemStack; +import net.minecraft.registry.tag.ItemTags; import net.minecraft.text.Text; public class CustomArmorDyeColors { @@ -40,7 +40,7 @@ public class CustomArmorDyeColors { } if (Utils.isOnSkyblock() && heldItem != null) { - if (heldItem.getItem() instanceof DyeableItem) { + if (heldItem.isIn(ItemTags.DYEABLE)) { String itemUuid = ItemUtils.getItemUuid(heldItem); if (!itemUuid.isEmpty()) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java index 3434f026..65e1b138 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java @@ -5,8 +5,8 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; - import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; @@ -17,6 +17,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.command.CommandRegistryAccess; @@ -25,20 +26,19 @@ import net.minecraft.command.argument.IdentifierArgumentType; import net.minecraft.item.ArmorItem; import net.minecraft.item.ItemStack; import net.minecraft.item.trim.ArmorTrim; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtOps; +import net.minecraft.item.trim.ArmorTrimMaterial; +import net.minecraft.item.trim.ArmorTrimPattern; import net.minecraft.registry.*; +import net.minecraft.registry.entry.RegistryEntry.Reference; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Optional; - public class CustomArmorTrims { private static final Logger LOGGER = LoggerFactory.getLogger(CustomArmorTrims.class); - public static final Object2ObjectOpenHashMap<ArmorTrimId, Optional<ArmorTrim>> TRIMS_CACHE = new Object2ObjectOpenHashMap<>(); + public static final Object2ObjectOpenHashMap<ArmorTrimId, ArmorTrim> TRIMS_CACHE = new Object2ObjectOpenHashMap<>(); private static boolean trimsInitialized = false; public static void init() { @@ -48,24 +48,18 @@ public class CustomArmorTrims { private static void initializeTrimCache() { ClientPlayerEntity player = MinecraftClient.getInstance().player; - if (trimsInitialized || player == null) { + FabricLoader loader = FabricLoader.getInstance(); + if (trimsInitialized || (player == null && !Debug.debugEnabled())) { return; } try { TRIMS_CACHE.clear(); - DynamicRegistryManager registryManager = player.networkHandler.getRegistryManager(); - for (Identifier material : registryManager.get(RegistryKeys.TRIM_MATERIAL).getIds()) { - for (Identifier pattern : registryManager.get(RegistryKeys.TRIM_PATTERN).getIds()) { - NbtCompound compound = new NbtCompound(); - compound.putString("material", material.toString()); - compound.putString("pattern", pattern.toString()); - - ArmorTrim trim = ArmorTrim.CODEC.parse(RegistryOps.of(NbtOps.INSTANCE, registryManager), compound).resultOrPartial(LOGGER::error).orElse(null); + RegistryWrapper.WrapperLookup wrapperLookup = getWrapperLookup(loader, player); + for (Reference<ArmorTrimMaterial> material : wrapperLookup.getWrapperOrThrow(RegistryKeys.TRIM_MATERIAL).streamEntries().toList()) { + for (Reference<ArmorTrimPattern> pattern : wrapperLookup.getWrapperOrThrow(RegistryKeys.TRIM_PATTERN).streamEntries().toList()) { + ArmorTrim trim = new ArmorTrim(material, pattern); - // Something went terribly wrong - if (trim == null) throw new IllegalStateException("Trim shouldn't be null! [" + "\"" + material + "\",\"" + pattern + "\"]"); - - TRIMS_CACHE.put(new ArmorTrimId(material, pattern), Optional.of(trim)); + TRIMS_CACHE.put(new ArmorTrimId(material.registryKey().getValue(), pattern.registryKey().getValue()), trim); } } @@ -76,6 +70,10 @@ public class CustomArmorTrims { } } + private static RegistryWrapper.WrapperLookup getWrapperLookup(FabricLoader loader, ClientPlayerEntity player) { + return !Debug.debugEnabled() ? player.networkHandler.getRegistryManager() : BuiltinRegistries.createWrapperLookup(); + } + private static void registerCommand(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) { dispatcher.register(ClientCommandManager.literal("skyblocker") .then(ClientCommandManager.literal("custom") diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java index e47444cf..e1af788e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java @@ -26,7 +26,7 @@ public class CustomItemNames { .then(ClientCommandManager.literal("custom") .then(ClientCommandManager.literal("renameItem") .executes(context -> renameItem(context.getSource(), null)) - .then(ClientCommandManager.argument("textComponent", TextArgumentType.text()) + .then(ClientCommandManager.argument("textComponent", TextArgumentType.text(registryAccess)) .executes(context -> renameItem(context.getSource(), context.getArgument("textComponent", Text.class))))))); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java index d4bf3d52..8a23ea6d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java @@ -17,7 +17,6 @@ import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.item.TooltipContext; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.texture.Sprite; import net.minecraft.item.ItemStack; @@ -48,7 +47,7 @@ public class ItemRarityBackgrounds { ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> { String title = screen.getTitle().getString(); - if (Utils.isOnSkyblock() && (title.equals("The Hex") || title.equals("Craft Item") || title.equals("Anvil") || title.equals("Reforge Anvil"))) { + if (Utils.isOnSkyblock() && (title.contains("The Hex") || title.equals("Craft Item") || title.equals("Anvil") || title.equals("Reforge Anvil"))) { ScreenEvents.remove(screen).register(screen1 -> CACHE.clear()); } }); @@ -74,8 +73,8 @@ public class ItemRarityBackgrounds { if (CACHE.containsKey(hashCode)) return CACHE.get(hashCode); - List<Text> tooltip = stack.getTooltip(player, TooltipContext.BASIC); - String[] stringifiedTooltip = tooltip.stream().map(Text::getString).toArray(String[]::new); + List<Text> lore = ItemUtils.getLore(stack); + String[] stringifiedTooltip = lore.stream().map(Text::getString).toArray(String[]::new); for (String rarityString : LORE_RARITIES.keySet()) { if (Arrays.stream(stringifiedTooltip).anyMatch(line -> line.contains(rarityString))) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java index ae908245..c78724ca 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java @@ -3,13 +3,16 @@ package de.hysky.skyblocker.skyblock.item; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.util.UndashedUuid; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.utils.Http; import de.hysky.skyblocker.utils.Http.ApiResponse; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.minecraft.client.MinecraftClient; @@ -21,7 +24,6 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.lang.reflect.Type; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; @@ -32,8 +34,7 @@ import java.util.concurrent.CompletableFuture; public class MuseumItemCache { private static final Logger LOGGER = LoggerFactory.getLogger(MuseumItemCache.class); private static final Path CACHE_FILE = SkyblockerMod.CONFIG_DIR.resolve("museum_item_cache.json"); - private static final Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> MUSEUM_ITEM_CACHE = new Object2ObjectOpenHashMap<>(); - private static final Type MAP_TYPE = new TypeToken<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>>>() {}.getType(); + private static final Map<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> MUSEUM_ITEM_CACHE = new Object2ObjectOpenHashMap<>(); private static final String ERROR_LOG_TEMPLATE = "[Skyblocker] Failed to refresh museum item data for profile {}"; private static CompletableFuture<Void> loaded; @@ -45,7 +46,7 @@ public class MuseumItemCache { private static void load(MinecraftClient client) { loaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = Files.newBufferedReader(CACHE_FILE)) { - Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> cachedData = SkyblockerMod.GSON.fromJson(reader, MAP_TYPE); + Map<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> cachedData = ProfileMuseumData.SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow(); MUSEUM_ITEM_CACHE.putAll(cachedData); LOGGER.info("[Skyblocker] Loaded museum items cache"); @@ -59,7 +60,7 @@ public class MuseumItemCache { private static void save() { CompletableFuture.runAsync(() -> { try (BufferedWriter writer = Files.newBufferedWriter(CACHE_FILE)) { - SkyblockerMod.GSON.toJson(MUSEUM_ITEM_CACHE, writer); + SkyblockerMod.GSON.toJson(ProfileMuseumData.SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, MUSEUM_ITEM_CACHE).getOrThrow(), writer); } catch (IOException e) { LOGGER.error("[Skyblocker] Failed to save cached museum items!", e); } @@ -68,7 +69,7 @@ public class MuseumItemCache { private static void updateData4ProfileMember(String uuid, String profileId) { CompletableFuture.runAsync(() -> { - try (ApiResponse response = Http.sendHypixelRequest("skyblock/museum", "?profile=" + profileId)) { + try (ApiResponse response = Http.sendHypixelRequest("skyblock/museum", "?profile=" + profileId)) { //The request was successful if (response.ok()) { JsonObject profileData = JsonParser.parseString(response.content()).getAsJsonObject(); @@ -86,7 +87,7 @@ public class MuseumItemCache { for (Map.Entry<String, JsonElement> donatedSet : donatedSets.entrySet()) { //Item is plural here because the nbt is a list String itemsData = donatedSet.getValue().getAsJsonObject().get("items").getAsJsonObject().get("data").getAsString(); - NbtList items = NbtIo.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(itemsData)), NbtTagSizeTracker.ofUnlimitedBytes()).getList("i", NbtElement.COMPOUND_TYPE); + NbtList items = NbtIo.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(itemsData)), NbtSizeTracker.ofUnlimitedBytes()).getList("i", NbtElement.COMPOUND_TYPE); for (int i = 0; i < items.size(); i++) { NbtCompound tag = items.getCompound(i).getCompound("tag"); @@ -135,7 +136,7 @@ public class MuseumItemCache { public static void tick(String profileId) { if (loaded.isDone()) { String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); - Object2ObjectOpenHashMap<String, ProfileMuseumData> playerData = MUSEUM_ITEM_CACHE.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()); + Map<String, ProfileMuseumData> playerData = MUSEUM_ITEM_CACHE.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()); playerData.putIfAbsent(profileId, ProfileMuseumData.EMPTY); if (playerData.get(profileId).stale()) updateData4ProfileMember(uuid, profileId); @@ -152,6 +153,17 @@ public class MuseumItemCache { private record ProfileMuseumData(long lastUpdated, ObjectOpenHashSet<String> collectedItemIds) { private static final ProfileMuseumData EMPTY = new ProfileMuseumData(0L, null); private static final long MAX_AGE = 86_400_000; + private static final Codec<ProfileMuseumData> CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.LONG.fieldOf("lastUpdated").forGetter(ProfileMuseumData::lastUpdated), + Codec.STRING.listOf() + .xmap(ObjectOpenHashSet::new, ObjectArrayList::new) + .fieldOf("collectedItemIds") + .forGetter(i -> new ObjectOpenHashSet<>(i.collectedItemIds())) + ).apply(instance, ProfileMuseumData::new)); + //Mojang's internal Codec implementation uses ImmutableMaps so we'll just xmap those away and type safety while we're at it :') + private static final Codec<Map<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, Codec.unboundedMap(Codec.STRING, CODEC) + .xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new) + ).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new); private boolean stale() { return System.currentTimeMillis() > lastUpdated + MAX_AGE; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/PlayerHeadHashCache.java b/src/main/java/de/hysky/skyblocker/skyblock/item/PlayerHeadHashCache.java index 2a1688fc..da832164 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/PlayerHeadHashCache.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/PlayerHeadHashCache.java @@ -1,7 +1,6 @@ package de.hysky.skyblocker.skyblock.item; -import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; import java.util.Base64; import java.util.concurrent.CompletableFuture; @@ -50,8 +49,8 @@ public class PlayerHeadHashCache { //From MinecraftProfileTexture#getHash public static String getSkinHash(String url) { try { - return FilenameUtils.getBaseName(new URL(url).getPath()); - } catch (MalformedURLException e) { + return FilenameUtils.getBaseName(new URI(url).getPath()); + } catch (Exception e) { LOGGER.error("[Skyblocker Player Head Hash Cache] Malformed Skin URL! URL: {}", url, e); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreen.java index 14ddb238..a09b260a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreen.java @@ -1,5 +1,7 @@ package de.hysky.skyblocker.skyblock.item; +import java.time.Duration; + import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.skyblock.itemlist.ItemListWidget; import net.minecraft.client.gui.DrawContext; @@ -21,6 +23,7 @@ import net.minecraft.screen.AbstractRecipeScreenHandler; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.text.OrderedText; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -54,11 +57,13 @@ public class SkyblockCraftingTableScreen extends HandledScreen<SkyblockCraftingT button.setPosition(this.x + 5, this.height / 2 - 49); if (moreCraftsButton != null) moreCraftsButton.setPosition(this.x + 174, this.y + 62); })); - moreCraftsButton = new TexturedButtonWidget(this.x + 174, y + 62, 16, 16, MORE_CRAFTS_TEXTURES, - button -> this.onMouseClick(handler.slots.get(26), handler.slots.get(26).id, 0, SlotActionType.PICKUP)); - moreCraftsButton.setTooltipDelay(250); - moreCraftsButton.setTooltip(Tooltip.of(Text.literal("More Crafts"))); - this.addDrawableChild(moreCraftsButton); + if (!handler.mirrorverse) { + moreCraftsButton = new TexturedButtonWidget(this.x + 174, y + 62, 16, 16, MORE_CRAFTS_TEXTURES, + button -> this.onMouseClick(handler.slots.get(26), handler.slots.get(26).id, 0, SlotActionType.PICKUP)); + moreCraftsButton.setTooltipDelay(Duration.ofMillis(250L)); + moreCraftsButton.setTooltip(Tooltip.of(Text.literal("More Crafts"))); + this.addDrawableChild(moreCraftsButton); + } assert (client != null ? client.player : null) != null; client.player.currentScreenHandler = handler; // recipe book replaces it with the Dummy one fucking DUMBASS this.addSelectableChild(this.recipeBook); @@ -101,7 +106,7 @@ public class SkyblockCraftingTableScreen extends HandledScreen<SkyblockCraftingT int i = this.x; int j = (this.height - this.backgroundHeight) / 2; context.drawTexture(TEXTURE, i, j, 0, 0, this.backgroundWidth, this.backgroundHeight); - context.drawGuiTexture(QUICK_CRAFT, i + 173, j, 0, 25, 84); + if (!handler.mirrorverse) context.drawGuiTexture(QUICK_CRAFT, i + 173, j, 0, 25, 84); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreenHandler.java b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreenHandler.java index 04974ade..c3704d8c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreenHandler.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockCraftingTableScreenHandler.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.skyblock.item; +import de.hysky.skyblocker.utils.Utils; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.Inventory; import net.minecraft.screen.GenericContainerScreenHandler; @@ -16,11 +17,22 @@ public class SkyblockCraftingTableScreenHandler extends GenericContainerScreenHa 28, 29, 30, 34 }; + private static final int[] riftNormalSlots = new int[]{ + 11, 12, 13, + 20, 21, 22, 24, + 29, 30, 31 + }; + + public final boolean mirrorverse; + public SkyblockCraftingTableScreenHandler(ScreenHandlerType<?> type, int syncId, PlayerInventory playerInventory, Inventory inventory, int rows) { super(type, syncId, playerInventory, inventory, rows); + mirrorverse = Utils.getIslandArea().toLowerCase().contains("mirrorverse"); + int[] activeSlots = mirrorverse ? riftNormalSlots: normalSlots; + for (int i = 0; i < rows * 9; i++) { Slot originalSlot = slots.get(i); - if (Arrays.binarySearch(normalSlots, i) >= 0) { + if (Arrays.binarySearch(activeSlots, i) >= 0) { int[] coords = getCoords(i); Slot slot = new Slot(originalSlot.inventory, originalSlot.getIndex(), coords[0], coords[1]); slot.id = i; @@ -45,14 +57,21 @@ public class SkyblockCraftingTableScreenHandler extends GenericContainerScreenHa } private int[] getCoords(int slot) { - if (slot == 23) return new int[]{124, 35}; - if (slot == 16 || slot == 25 || slot == 34) { - int y = (slot / 9 - 1) * 18 + 8; - return new int[]{174, y}; + if (mirrorverse) { + if (slot == 24) return new int[]{124, 35}; + int gridX = slot % 9 - 2; + int gridY = slot / 9 - 1; + return new int[]{30 + gridX * 18, 17 + gridY * 18}; + } else { + if (slot == 23) return new int[]{124, 35}; + if (slot == 16 || slot == 25 || slot == 34) { + int y = (slot / 9 - 1) * 18 + 8; + return new int[]{174, y}; + } + int gridX = slot % 9 - 1; + int gridY = slot / 9 - 1; + return new int[]{30 + gridX * 18, 17 + gridY * 18}; } - int gridX = slot % 9 - 1; - int gridY = slot / 9 - 1; - return new int[]{30 + gridX * 18, 17 + gridY * 18}; } public static class DisabledSlot extends Slot { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java b/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java index 5815c11f..109e5503 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java @@ -2,7 +2,9 @@ package de.hysky.skyblocker.skyblock.item; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; @@ -10,6 +12,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Text; import net.minecraft.util.Util; +import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +22,6 @@ import java.util.concurrent.CompletableFuture; public class WikiLookup { private static final Logger LOGGER = LoggerFactory.getLogger(WikiLookup.class); public static KeyBinding wikiLookup; - private static String id; public static void init() { wikiLookup = KeyBindingHelper.registerKeyBinding(new KeyBinding( @@ -30,24 +32,15 @@ public class WikiLookup { )); } - public static void getSkyblockId(Slot slot) { - //Grabbing the skyblock NBT data - ItemUtils.getItemIdOptional(slot.getStack()).ifPresent(newId -> id = newId); - } + public static void openWiki(@NotNull Slot slot, @NotNull PlayerEntity player) { + if (!Utils.isOnSkyblock() || !SkyblockerConfigManager.get().general.wikiLookup.enableWikiLookup) return; - public static void openWiki(Slot slot, PlayerEntity player) { - if (SkyblockerConfigManager.get().general.wikiLookup.enableWikiLookup) { - getSkyblockId(slot); - try { - String wikiLink = ItemRepository.getWikiLink(id, player); - if (wikiLink != null) CompletableFuture.runAsync(() -> Util.getOperatingSystem().open(wikiLink)); - } catch (IndexOutOfBoundsException | IllegalStateException e) { - LOGGER.error("[Skyblocker] Error while retrieving wiki article...", e); - if (player != null) { - player.sendMessage(Text.of("[Skyblocker] Error while retrieving wiki article, see logs..."), false); - } - } - } + ItemUtils.getItemIdOptional(slot.getStack()) + .map(ItemRepository::getWikiLink) + .ifPresentOrElse(wikiLink -> CompletableFuture.runAsync(() -> Util.getOperatingSystem().open(wikiLink)).exceptionally(e -> { + LOGGER.error("[Skyblocker] Error while retrieving wiki article...", e); + player.sendMessage(Constants.PREFIX.get().append("Error while retrieving wiki article, see logs..."), false); + return null; + }), () -> player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.wikiLookup.noArticleFound")), false)); } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java index b4d47617..06601f80 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -75,7 +75,7 @@ public class AccessoriesHelper { private static void load() { loaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = Files.newBufferedReader(FILE)) { - COLLECTED_ACCESSORIES.putAll(ProfileAccessoryData.SERIALIZATION_CODEC.parse(JsonOps.COMPRESSED, JsonParser.parseReader(reader)).result().orElseThrow()); + COLLECTED_ACCESSORIES.putAll(ProfileAccessoryData.SERIALIZATION_CODEC.parse(JsonOps.COMPRESSED, JsonParser.parseReader(reader)).getOrThrow()); } catch (NoSuchFileException ignored) { } catch (Exception e) { LOGGER.error("[Skyblocker Accessory Helper] Failed to load accessory file!", e); @@ -85,7 +85,7 @@ public class AccessoriesHelper { private static void save() { try (BufferedWriter writer = Files.newBufferedWriter(FILE)) { - SkyblockerMod.GSON.toJson(ProfileAccessoryData.SERIALIZATION_CODEC.encodeStart(JsonOps.COMPRESSED, COLLECTED_ACCESSORIES).result().orElseThrow(), writer); + SkyblockerMod.GSON.toJson(ProfileAccessoryData.SERIALIZATION_CODEC.encodeStart(JsonOps.COMPRESSED, COLLECTED_ACCESSORIES).getOrThrow(), writer); } catch (Exception e) { LOGGER.error("[Skyblocker Accessory Helper] Failed to save accessory file!", e); } @@ -166,7 +166,7 @@ public class AccessoriesHelper { static void refreshData(JsonObject data) { try { - ACCESSORY_DATA = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).result().orElseThrow(); + ACCESSORY_DATA = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).getOrThrow(); } catch (Exception e) { LOGGER.error("[Skyblocker Accessory Helper] Failed to parse data!", e); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java index 37de58e6..50772789 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java @@ -1,9 +1,13 @@ package de.hysky.skyblocker.skyblock.item.tooltip; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.ItemProtection; import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds; +import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.MinecraftClient; @@ -15,23 +19,26 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.inventory.Inventory; import net.minecraft.inventory.SimpleInventory; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtInt; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.StringNbtReader; +import net.minecraft.nbt.visitor.StringNbtWriter; import net.minecraft.util.Identifier; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Objects; +import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class BackpackPreview { private static final Logger LOGGER = LoggerFactory.getLogger(BackpackPreview.class); + private static final Identifier ITEM_PROTECTION = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/item_protection.png"); private static final Identifier TEXTURE = new Identifier("textures/gui/container/generic_54.png"); private static final Pattern ECHEST_PATTERN = Pattern.compile("Ender Chest.*\\((\\d+)/\\d+\\)"); private static final Pattern BACKPACK_PATTERN = Pattern.compile("Backpack.*\\(Slot #(\\d+)\\)"); @@ -61,8 +68,13 @@ public class BackpackPreview { String id = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", "") + "/" + Utils.getProfileId(); if (!id.equals(loaded)) { saveDir = SkyblockerMod.CONFIG_DIR.resolve("backpack-preview/" + id); - //noinspection ResultOfMethodCallIgnored - saveDir.toFile().mkdirs(); + + try { + Files.createDirectories(saveDir); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to create the backpack preview save directory! Path: {}", saveDir, e); + } + // load storage again because profile id changed loaded = id; loadStorages(); @@ -75,10 +87,10 @@ public class BackpackPreview { storages[index] = null; Path storageFile = saveDir.resolve(index + ".nbt"); if (Files.isRegularFile(storageFile)) { - try { - storages[index] = Storage.fromNbt(Objects.requireNonNull(NbtIo.read(storageFile))); + try (BufferedReader reader = Files.newBufferedReader(storageFile)) { + storages[index] = Storage.CODEC.parse(NbtOps.INSTANCE, StringNbtReader.parse(reader.lines().collect(Collectors.joining()))).getOrThrow(); } catch (Exception e) { - LOGGER.error("Failed to load backpack preview file: " + storageFile.getFileName().toString(), e); + LOGGER.error("Failed to load backpack preview file: {}", storageFile.getFileName().toString(), e); } } } @@ -93,11 +105,12 @@ public class BackpackPreview { } private static void saveStorage(int index) { - try { - NbtIo.write(storages[index].toNbt(), saveDir.resolve(index + ".nbt")); + Path storageFile = saveDir.resolve(index + ".nbt"); + try (BufferedWriter writer = Files.newBufferedWriter(storageFile)) { + writer.write(new StringNbtWriter().apply(Storage.CODEC.encodeStart(NbtOps.INSTANCE, storages[index]).getOrThrow())); storages[index].markClean(); } catch (Exception e) { - LOGGER.error("Failed to save backpack preview file: " + index + ".nbt", e); + LOGGER.error("Failed to save backpack preview file: {}", storageFile.getFileName().toString(), e); } } @@ -105,7 +118,7 @@ public class BackpackPreview { String title = handledScreen.getTitle().getString(); int index = getStorageIndexFromTitle(title); if (index != -1) { - storages[index] = new Storage(handledScreen.getScreenHandler().slots.get(0).inventory, title, true); + storages[index] = new Storage(handledScreen.getScreenHandler().slots.getFirst().inventory, title, true); } } @@ -129,7 +142,7 @@ public class BackpackPreview { context.drawTexture(TEXTURE, x, y + rows * 18 + 17, 0, 215, 176, 7); TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - context.drawText(textRenderer, storages[index].name, x + 8, y + 6, 0x404040, false); + context.drawText(textRenderer, storages[index].name(), x + 8, y + 6, 0x404040, false); matrices.translate(0f, 0f, 200f); for (int i = 9; i < storages[index].size(); ++i) { @@ -141,6 +154,12 @@ public class BackpackPreview { ItemRarityBackgrounds.tryDraw(currentStack, context, itemX, itemY); } + if (ItemProtection.isItemProtected(currentStack)) { + RenderSystem.enableBlend(); + context.drawTexture(ITEM_PROTECTION, itemX, itemY, 0, 0, 16, 16, 16, 16); + RenderSystem.disableBlend(); + } + context.drawItem(currentStack, itemX, itemY); context.drawItemInSlot(textRenderer, currentStack, itemX, itemY); } @@ -159,6 +178,10 @@ public class BackpackPreview { } static class Storage { + private static final Codec<Storage> CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("name").forGetter(Storage::name), + ItemUtils.EMPTY_ALLOWING_ITEMSTACK_CODEC.listOf().fieldOf("items").forGetter(Storage::getItemList) + ).apply(instance, Storage::create)); private final Inventory inventory; private final String name; private boolean dirty; @@ -169,6 +192,10 @@ public class BackpackPreview { this.dirty = dirty; } + private String name() { + return name; + } + private int size() { return inventory.size(); } @@ -181,23 +208,19 @@ public class BackpackPreview { dirty = false; } - @NotNull - private static Storage fromNbt(NbtCompound root) { - SimpleInventory inventory = new SimpleInventory(root.getList("list", NbtCompound.COMPOUND_TYPE).stream().map(NbtCompound.class::cast).map(ItemStack::fromNbt).toArray(ItemStack[]::new)); - return new Storage(inventory, root.getString("name"), false); + private static Storage create(String name, List<ItemStack> items) { + SimpleInventory inventory = new SimpleInventory(items.toArray(ItemStack[]::new)); + return new Storage(inventory, name, false); } - @NotNull - private NbtCompound toNbt() { - NbtCompound root = new NbtCompound(); - NbtList list = new NbtList(); + private List<ItemStack> getItemList() { + List<ItemStack> items = new ArrayList<>(); + for (int i = 0; i < size(); ++i) { - list.add(getStack(i).writeNbt(new NbtCompound())); + items.add(getStack(i)); } - root.put("list", list); - root.put("size", NbtInt.of(size())); - root.putString("name", name); - return root; + + return items; } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java index 657db0c9..c5279c61 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java @@ -1,6 +1,6 @@ package de.hysky.skyblocker.skyblock.item.tooltip; -import de.hysky.skyblocker.mixin.accessor.DrawContextInvoker; +import de.hysky.skyblocker.mixins.accessors.DrawContextInvoker; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.utils.ItemUtils; import it.unimi.dsi.fastutil.ints.IntIntPair; @@ -40,10 +40,9 @@ public class CompactorDeletorPreview { if (targetIndex == -1) return false; // Get items in compactor or deletor - NbtCompound extraAttributes = ItemUtils.getExtraAttributes(stack); - if (extraAttributes == null) return false; + NbtCompound customData = ItemUtils.getCustomData(stack); // Get the slots and their items from the nbt, which is in the format personal_compact_<slot_number> or personal_deletor_<slot_number> - List<IntObjectPair<ItemStack>> slots = extraAttributes.getKeys().stream().filter(slot -> slot.contains(type.toLowerCase().substring(0, 7))).map(slot -> IntObjectPair.of(Integer.parseInt(slot.substring(17)), ItemRepository.getItemStack(extraAttributes.getString(slot)))).toList(); + List<IntObjectPair<ItemStack>> slots = customData.getKeys().stream().filter(slot -> slot.contains(type.toLowerCase().substring(0, 7))).map(slot -> IntObjectPair.of(Integer.parseInt(slot.substring(17)), ItemRepository.getItemStack(customData.getString(slot)))).toList(); List<TooltipComponent> components = tooltips.stream().map(Text::asOrderedText).map(TooltipComponent::of).collect(Collectors.toList()); IntIntPair dimensions = DIMENSIONS.getOrDefault(size, DEFAULT_DIMENSION); @@ -60,9 +59,9 @@ public class CompactorDeletorPreview { // Add the preview tooltip component components.add(targetIndex, new CompactorPreviewTooltipComponent(slots, dimensions)); - if (extraAttributes.contains("PERSONAL_DELETOR_ACTIVE")) { + if (customData.contains("PERSONAL_DELETOR_ACTIVE")) { components.add(targetIndex, TooltipComponent.of(Text.literal("Active: ") - .append(extraAttributes.getBoolean("PERSONAL_DELETOR_ACTIVE") ? Text.literal("YES").formatted(Formatting.BOLD).formatted(Formatting.GREEN) : Text.literal("NO").formatted(Formatting.BOLD).formatted(Formatting.RED)).asOrderedText())); + .append(customData.getBoolean("PERSONAL_DELETOR_ACTIVE") ? Text.literal("YES").formatted(Formatting.BOLD).formatted(Formatting.GREEN) : Text.literal("NO").formatted(Formatting.BOLD).formatted(Formatting.RED)).asOrderedText())); } ((DrawContextInvoker) context).invokeDrawTooltip(client.textRenderer, components, x, y, HoveredTooltipPositioner.INSTANCE); return true; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java index 66d94890..46babc8b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java @@ -65,8 +65,8 @@ public class ExoticTooltip { return DyeType.EXOTIC; } - public static boolean intendedDyed(NbtCompound ItemData) { - return ItemData.getCompound("ExtraAttributes").contains("dye_item"); + public static boolean intendedDyed(NbtCompound customData) { + return customData.contains("dye_item"); } public enum DyeType implements StringIdentifiable { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index ea24dc63..0cffa05c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -12,14 +12,17 @@ import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.Pair; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.item.DyeableItem; +import net.minecraft.client.item.TooltipType; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.DyedColorComponent; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; + import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +36,7 @@ public class ItemTooltip { protected static final SkyblockerConfig.ItemTooltip config = SkyblockerConfigManager.get().general.itemTooltip; private static volatile boolean sentNullWarning = false; - public static void getTooltip(ItemStack stack, TooltipContext context, List<Text> lines) { + public static void getTooltip(ItemStack stack, Item.TooltipContext tooltipContext, TooltipType tooltipType, List<Text> lines) { if (!Utils.isOnSkyblock() || client.player == null) return; String name = getInternalNameFromNBT(stack, false); @@ -123,31 +126,31 @@ public class ItemTooltip { } } - final Map<Integer, String> itemTierFloors = new HashMap<>() {{ - put(1, "F1"); - put(2, "F2"); - put(3, "F3"); - put(4, "F4/M1"); - put(5, "F5/M2"); - put(6, "F6/M3"); - put(7, "F7/M4"); - put(8, "M5"); - put(9, "M6"); - put(10, "M7"); - }}; + final Map<Integer, String> itemTierFloors = Map.of( + 1, "F1", + 2, "F2", + 3, "F3", + 4, "F4/M1", + 5, "F5/M2", + 6, "F6/M3", + 7, "F7/M4", + 8, "M5", + 9, "M6", + 10, "M7" + ); if (SkyblockerConfigManager.get().general.dungeonQuality) { - NbtCompound ea = ItemUtils.getExtraAttributes(stack); - if (ea != null && ea.contains("baseStatBoostPercentage")) { - int baseStatBoostPercentage = ea.getInt("baseStatBoostPercentage"); + NbtCompound customData = ItemUtils.getCustomData(stack); + if (customData != null && customData.contains("baseStatBoostPercentage")) { + int baseStatBoostPercentage = customData.getInt("baseStatBoostPercentage"); boolean maxQuality = baseStatBoostPercentage == 50; if (maxQuality) { lines.add(Text.literal(String.format("%-17s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.RED).formatted(Formatting.BOLD)); } else { lines.add(Text.literal(String.format("%-21s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.BLUE)); } - if (ea.contains("item_tier")) { // sometimes it just isn't here? - int itemTier = ea.getInt("item_tier"); + if (customData.contains("item_tier")) { // sometimes it just isn't here? + int itemTier = customData.getInt("item_tier"); if (maxQuality) { lines.add(Text.literal(String.format("%-17s", "Floor Tier:") + itemTier + " (" + itemTierFloors.get(itemTier) + ")").formatted(Formatting.RED).formatted(Formatting.BOLD)); } else { @@ -186,8 +189,8 @@ public class ItemTooltip { lines.add(Text.literal(String.format(format, "Museum: (" + itemCategory + ")")) .formatted(Formatting.LIGHT_PURPLE)); } else { - NbtCompound extraAttributes = ItemUtils.getExtraAttributes(stack); - boolean isInMuseum = (extraAttributes.contains("donated_museum") && extraAttributes.getBoolean("donated_museum")) || MuseumItemCache.hasItemInMuseum(internalID); + NbtCompound customData = ItemUtils.getCustomData(stack); + boolean isInMuseum = (customData.contains("donated_museum") && customData.getBoolean("donated_museum")) || MuseumItemCache.hasItemInMuseum(internalID); Formatting donatedIndicatorFormatting = isInMuseum ? Formatting.GREEN : Formatting.RED; @@ -198,12 +201,16 @@ public class ItemTooltip { } } - if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.getNbt() != null) { + if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.contains(DataComponentTypes.DYED_COLOR)) { String uuid = ItemUtils.getItemUuid(stack); boolean hasCustomDye = SkyblockerConfigManager.get().general.customDyeColors.containsKey(uuid) || SkyblockerConfigManager.get().general.customAnimatedDyes.containsKey(uuid); + //DyedColorComponent#getColor returns ARGB so we mask out the alpha bits + int dyeColor = DyedColorComponent.getColor(stack, 0); - if (!hasCustomDye && stack.getItem() instanceof DyeableItem item && item.hasColor(stack)) { - String colorHex = String.format("%06X", item.getColor(stack)); + // dyeColor will have alpha = 255 if it's dyed, and alpha = 0 if it's not dyed, + if (!hasCustomDye && dyeColor != 0) { + dyeColor = dyeColor & 0x00FFFFFF; + String colorHex = String.format("%06X", dyeColor); String expectedHex = ExoticTooltip.getExpectedHex(internalID); boolean correctLine = false; @@ -212,13 +219,13 @@ public class ItemTooltip { if (existingTooltip.startsWith("Color: ")) { correctLine = true; - addExoticTooltip(lines, internalID, stack.getNbt(), colorHex, expectedHex, existingTooltip); + addExoticTooltip(lines, internalID, ItemUtils.getCustomData(stack), colorHex, expectedHex, existingTooltip); break; } } if (!correctLine) { - addExoticTooltip(lines, internalID, stack.getNbt(), colorHex, expectedHex, ""); + addExoticTooltip(lines, internalID, ItemUtils.getCustomData(stack), colorHex, expectedHex, ""); } } } @@ -271,8 +278,8 @@ public class ItemTooltip { return neuName; } - private static void addExoticTooltip(List<Text> lines, String internalID, NbtCompound nbt, String colorHex, String expectedHex, String existingTooltip) { - if (expectedHex != null && !colorHex.equalsIgnoreCase(expectedHex) && !ExoticTooltip.isException(internalID, colorHex) && !ExoticTooltip.intendedDyed(nbt)) { + private static void addExoticTooltip(List<Text> lines, String internalID, NbtCompound customData, String colorHex, String expectedHex, String existingTooltip) { + if (expectedHex != null && !colorHex.equalsIgnoreCase(expectedHex) && !ExoticTooltip.isException(internalID, colorHex) && !ExoticTooltip.intendedDyed(customData)) { final ExoticTooltip.DyeType type = ExoticTooltip.checkDyeType(colorHex); lines.add(1, Text.literal(existingTooltip + Formatting.DARK_GRAY + "(").append(type.getTranslatedText()).append(Formatting.DARK_GRAY + ")")); } @@ -287,57 +294,57 @@ public class ItemTooltip { // TODO What in the world is this? public static String getInternalNameFromNBT(ItemStack stack, boolean internalIDOnly) { - NbtCompound ea = ItemUtils.getExtraAttributes(stack); + NbtCompound customData = ItemUtils.getCustomData(stack); - if (ea == null || !ea.contains(ItemUtils.ID, NbtElement.STRING_TYPE)) { + if (customData == null || !customData.contains(ItemUtils.ID, NbtElement.STRING_TYPE)) { return null; } - String internalName = ea.getString(ItemUtils.ID); + String internalName = customData.getString(ItemUtils.ID); if (internalIDOnly) { return internalName; } // Transformation to API format. - if (ea.contains("is_shiny")) { + if (customData.contains("is_shiny")) { return "ISSHINY_" + internalName; } switch (internalName) { case "ENCHANTED_BOOK" -> { - if (ea.contains("enchantments")) { - NbtCompound enchants = ea.getCompound("enchantments"); + if (customData.contains("enchantments")) { + NbtCompound enchants = customData.getCompound("enchantments"); Optional<String> firstEnchant = enchants.getKeys().stream().findFirst(); String enchant = firstEnchant.orElse(""); return "ENCHANTMENT_" + enchant.toUpperCase(Locale.ENGLISH) + "_" + enchants.getInt(enchant); } } case "PET" -> { - if (ea.contains("petInfo")) { - JsonObject petInfo = SkyblockerMod.GSON.fromJson(ea.getString("petInfo"), JsonObject.class); + if (customData.contains("petInfo")) { + JsonObject petInfo = SkyblockerMod.GSON.fromJson(customData.getString("petInfo"), JsonObject.class); return "LVL_1_" + petInfo.get("tier").getAsString() + "_" + petInfo.get("type").getAsString(); } } case "POTION" -> { - String enhanced = ea.contains("enhanced") ? "_ENHANCED" : ""; - String extended = ea.contains("extended") ? "_EXTENDED" : ""; - String splash = ea.contains("splash") ? "_SPLASH" : ""; - if (ea.contains("potion") && ea.contains("potion_level")) { - return (ea.getString("potion") + "_" + internalName + "_" + ea.getInt("potion_level") + String enhanced = customData.contains("enhanced") ? "_ENHANCED" : ""; + String extended = customData.contains("extended") ? "_EXTENDED" : ""; + String splash = customData.contains("splash") ? "_SPLASH" : ""; + if (customData.contains("potion") && customData.contains("potion_level")) { + return (customData.getString("potion") + "_" + internalName + "_" + customData.getInt("potion_level") + enhanced + extended + splash).toUpperCase(Locale.ENGLISH); } } case "RUNE" -> { - if (ea.contains("runes")) { - NbtCompound runes = ea.getCompound("runes"); + if (customData.contains("runes")) { + NbtCompound runes = customData.getCompound("runes"); Optional<String> firstRunes = runes.getKeys().stream().findFirst(); String rune = firstRunes.orElse(""); return rune.toUpperCase(Locale.ENGLISH) + "_RUNE_" + runes.getInt(rune); } } case "ATTRIBUTE_SHARD" -> { - if (ea.contains("attributes")) { - NbtCompound shards = ea.getCompound("attributes"); + if (customData.contains("attributes")) { + NbtCompound shards = customData.getCompound("attributes"); Optional<String> firstShards = shards.getKeys().stream().findFirst(); String shard = firstShards.orElse(""); return internalName + "-" + shard.toUpperCase(Locale.ENGLISH) + "_" + shards.getInt(shard); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemFixerUpper.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemFixerUpper.java index 488c5f48..06230d4e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemFixerUpper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemFixerUpper.java @@ -169,7 +169,7 @@ public class ItemFixerUpper { private final static String[] TALLGRASS_VARIANTS = { "minecraft:dead_bush", - "minecraft:grass", + "minecraft:short_grass", "minecraft:fern" }; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java index 5570c4f7..6120528c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java @@ -1,7 +1,8 @@ package de.hysky.skyblocker.skyblock.itemlist; import com.mojang.blaze3d.systems.RenderSystem; -import de.hysky.skyblocker.mixin.accessor.RecipeBookWidgetAccessor; + +import de.hysky.skyblocker.mixins.accessors.RecipeBookWidgetAccessor; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java index 3379b693..4fd0f8cd 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java @@ -1,16 +1,13 @@ package de.hysky.skyblocker.skyblock.itemlist; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.NEURepoManager; import io.github.moulberry.repo.data.NEUCraftingRecipe; import io.github.moulberry.repo.data.NEUItem; import io.github.moulberry.repo.data.NEURecipe; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,10 +64,9 @@ public class ItemRepository { } } - public static String getWikiLink(String internalName, PlayerEntity player) { + public static String getWikiLink(String internalName) { NEUItem item = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(internalName); if (item == null || item.getInfo() == null || item.getInfo().isEmpty()) { - warnNoWikiLink(player); return null; } @@ -83,16 +79,9 @@ public class ItemRepository { } else if (wikiLink1.startsWith(wikiDomain)) { return wikiLink1; } - warnNoWikiLink(player); return null; } - private static void warnNoWikiLink(PlayerEntity player) { - if (player != null) { - player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.wikiLookup.noArticleFound")), false); - } - } - public static List<SkyblockCraftingRecipe> getRecipes(String internalName) { List<SkyblockCraftingRecipe> result = new ArrayList<>(); for (SkyblockCraftingRecipe recipe : recipes) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java index c1eea23a..6ee75161 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java @@ -5,10 +5,15 @@ import de.hysky.skyblocker.utils.NEURepoManager; import io.github.moulberry.repo.constants.PetNumbers; import io.github.moulberry.repo.data.NEUItem; import io.github.moulberry.repo.data.Rarity; -import net.minecraft.item.FireworkRocketItem; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.*; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.*; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtString; +import net.minecraft.registry.Registries; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import net.minecraft.util.Pair; import java.util.*; @@ -16,6 +21,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class ItemStackBuilder { + private static final Pattern SKULL_UUID_PATTERN = Pattern.compile("(?<=SkullOwner:\\{)Id:\"(.{36})\""); + private static final Pattern SKULL_TEXTURE_PATTERN = Pattern.compile("(?<=Properties:\\{textures:\\[0:\\{Value:)\"(.+?)\""); + private static final Pattern COLOR_PATTERN = Pattern.compile("color:(\\d+)"); + private static final Pattern EXPLOSION_COLOR_PATTERN = Pattern.compile("\\{Explosion:\\{(?:Type:[0-9a-z]+,)?Colors:\\[(?<color>[0-9]+)]\\}"); private static Map<String, Map<Rarity, PetNumbers>> petNums; public static void loadPetNums() { @@ -31,73 +40,60 @@ public class ItemStackBuilder { List<Pair<String, String>> injectors = new ArrayList<>(petData(internalName)); - NbtCompound root = new NbtCompound(); - root.put("Count", NbtByte.of((byte) 1)); + String legacyId = item.getMinecraftItemId(); + Identifier itemId = new Identifier(ItemFixerUpper.convertItemId(legacyId, item.getDamage())); - String id = item.getMinecraftItemId(); - int damage = item.getDamage(); - root.put("id", NbtString.of(ItemFixerUpper.convertItemId(id, damage))); + ItemStack stack = new ItemStack(Registries.ITEM.get(itemId)); - NbtCompound tag = new NbtCompound(); - root.put("tag", tag); + // Custom Data + NbtCompound customData = new NbtCompound(); - NbtCompound extra = new NbtCompound(); - tag.put(ItemUtils.EXTRA_ATTRIBUTES, extra); - extra.put(ItemUtils.ID, NbtString.of(internalName)); - - NbtCompound display = new NbtCompound(); - tag.put("display", display); + // Add Skyblock Item Id + customData.put(ItemUtils.ID, NbtString.of(internalName)); + // Item Name String name = injectData(item.getDisplayName(), injectors); - display.put("Name", NbtString.of(Text.Serialization.toJsonString(Text.of(name)))); + stack.set(DataComponentTypes.CUSTOM_NAME, Text.of(name)); - NbtList lore = new NbtList(); - display.put("Lore", lore); - item.getLore().forEach(el -> lore.add(NbtString.of(Text.Serialization.toJsonString(Text.of(injectData(el, injectors)))))); + // Lore + stack.set(DataComponentTypes.LORE, new LoreComponent(item.getLore().stream().map(line -> Text.of(injectData(line, injectors))).toList())); String nbttag = item.getNbttag(); // add skull texture - Matcher skullUuid = Pattern.compile("(?<=SkullOwner:\\{)Id:\"(.{36})\"").matcher(nbttag); - Matcher skullTexture = Pattern.compile("(?<=Properties:\\{textures:\\[0:\\{Value:)\"(.+?)\"").matcher(nbttag); + Matcher skullUuid = SKULL_UUID_PATTERN.matcher(nbttag); + Matcher skullTexture = SKULL_TEXTURE_PATTERN.matcher(nbttag); if (skullUuid.find() && skullTexture.find()) { - NbtCompound skullOwner = new NbtCompound(); - tag.put("SkullOwner", skullOwner); UUID uuid = UUID.fromString(skullUuid.group(1)); - skullOwner.put("Id", NbtHelper.fromUuid(uuid)); - skullOwner.put("Name", NbtString.of(internalName)); - - NbtCompound properties = new NbtCompound(); - skullOwner.put("Properties", properties); - NbtList textures = new NbtList(); - properties.put("textures", textures); - NbtCompound texture = new NbtCompound(); - textures.add(texture); - texture.put("Value", NbtString.of(skullTexture.group(1))); + String textureValue = skullTexture.group(1); + + stack.set(DataComponentTypes.PROFILE, new ProfileComponent(Optional.of(internalName), Optional.of(uuid), ItemUtils.propertyMapWithTexture(textureValue))); } + // add leather armor dye color - Matcher colorMatcher = Pattern.compile("color:(\\d+)").matcher(nbttag); + Matcher colorMatcher = COLOR_PATTERN.matcher(nbttag); if (colorMatcher.find()) { - NbtInt color = NbtInt.of(Integer.parseInt(colorMatcher.group(1))); - display.put("color", color); + int color = Integer.parseInt(colorMatcher.group(1)); + stack.set(DataComponentTypes.DYED_COLOR, new DyedColorComponent(color, false)); } // add enchantment glint if (nbttag.contains("ench:")) { - NbtList enchantments = new NbtList(); - enchantments.add(new NbtCompound()); - tag.put("Enchantments", enchantments); + stack.set(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, true); } + //Hide weapon damage and other useless info + stack.set(DataComponentTypes.ATTRIBUTE_MODIFIERS, new AttributeModifiersComponent(List.of(), false)); + // Add firework star color - Matcher explosionColorMatcher = Pattern.compile("\\{Explosion:\\{(?:Type:[0-9a-z]+,)?Colors:\\[(?<color>[0-9]+)]\\}").matcher(nbttag); + Matcher explosionColorMatcher = EXPLOSION_COLOR_PATTERN.matcher(nbttag); if (explosionColorMatcher.find()) { - NbtCompound explosion = new NbtCompound(); - - explosion.putInt("Type", FireworkRocketItem.Type.SMALL_BALL.getId()); //Forget about the actual ball type because it probably doesn't matter - explosion.putIntArray("Colors", new int[]{Integer.parseInt(explosionColorMatcher.group("color"))}); - tag.put("Explosion", explosion); + //Forget about the actual ball type because it probably doesn't matter + stack.set(DataComponentTypes.FIREWORK_EXPLOSION, new FireworkExplosionComponent(FireworkExplosionComponent.Type.SMALL_BALL, new IntArrayList(Integer.parseInt(explosionColorMatcher.group("color"))), new IntArrayList(), false, false)); } - return ItemStack.fromNbt(root); + // Attach custom nbt data + stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(customData)); + + return stack; } private static List<Pair<String, String>> petData(String internalName) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java index 44e336d9..961a2cc2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java @@ -8,10 +8,13 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Drawable; import net.minecraft.client.gui.screen.ButtonTextures; import net.minecraft.client.gui.widget.ToggleButtonWidget; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; + import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -74,11 +77,8 @@ public class SearchResultsWidget implements Drawable { this.searchResults.clear(); for (ItemStack entry : ItemRepository.getItems()) { String name = entry.getName().toString().toLowerCase(Locale.ENGLISH); - if (entry.getNbt() == null) { - continue; - } - String disp = entry.getNbt().getCompound("display").toString().toLowerCase(Locale.ENGLISH); - if (name.contains(this.searchText) || disp.contains(this.searchText)) + LoreComponent lore = entry.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT); + if (name.contains(this.searchText) || lore.lines().stream().map(Text::getString).anyMatch(s -> s.contains(this.searchText))) this.searchResults.add(entry); } this.currentPage = 0; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNav.java b/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNav.java index 51a3d409..8e203b84 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNav.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNav.java @@ -5,12 +5,12 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.datafixer.ItemStackComponentizationFixer; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.fabricmc.fabric.api.client.screen.v1.Screens; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.StringNbtReader; import net.minecraft.text.Text; import net.minecraft.util.Formatting; @@ -21,8 +21,6 @@ import java.util.Locale; import java.util.regex.PatternSyntaxException; public class QuickNav { - private static final String skyblockHubIconNbt = "{id:\"minecraft:player_head\",Count:1,tag:{SkullOwner:{Id:[I;-300151517,-631415889,-1193921967,-1821784279],Properties:{textures:[{Value:\"e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDdjYzY2ODc0MjNkMDU3MGQ1NTZhYzUzZTA2NzZjYjU2M2JiZGQ5NzE3Y2Q4MjY5YmRlYmVkNmY2ZDRlN2JmOCJ9fX0=\"}]}}}}"; - private static final String dungeonHubIconNbt = "{id:\"minecraft:player_head\",Count:1,tag:{SkullOwner:{Id:[I;1605800870,415127827,-1236127084,15358548],Properties:{textures:[{Value:\"e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg5MWQ1YjI3M2ZmMGJjNTBjOTYwYjJjZDg2ZWVmMWM0MGExYjk0MDMyYWU3MWU3NTQ3NWE1NjhhODI1NzQyMSJ9fX0=\"}]}}}}"; public static void init() { ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { @@ -74,7 +72,6 @@ public class QuickNav { return new QuickNavButton(id, uiTitleMatches, buttonInfo.clickEvent, - ItemStack.fromNbt(StringNbtReader.parse(nbtString)) - ); + ItemStackComponentizationFixer.fixUpItem(StringNbtReader.parse(nbtString))); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNavButton.java b/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNavButton.java index 28ffc930..7db78590 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNavButton.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/quicknav/QuickNavButton.java @@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.quicknav; import com.mojang.blaze3d.systems.RenderSystem; -import de.hysky.skyblocker.mixin.accessor.HandledScreenAccessor; +import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java index aa3b976e..3918037f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java @@ -47,17 +47,17 @@ public class ShortcutsConfigListWidget extends ElementListWidget<ShortcutsConfig } @Override - protected int getScrollbarPositionX() { - return super.getScrollbarPositionX() + 50; + protected int getScrollbarX() { + return super.getScrollbarX(); } protected Optional<ShortcutCategoryEntry> getCategory() { - if (getSelectedOrNull() instanceof ShortcutCategoryEntry category) { - return Optional.of(category); - } else if (getSelectedOrNull() instanceof ShortcutEntry shortcutEntry) { - return Optional.of(shortcutEntry.category); - } - return Optional.empty(); + return switch (getSelectedOrNull()) { + case ShortcutCategoryEntry category -> Optional.of(category); + case ShortcutEntry shortcutEntry -> Optional.of(shortcutEntry.category); + + case null, default -> Optional.empty(); + }; } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java b/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java index bc4f98c2..8e10086f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java @@ -1,42 +1,24 @@ package de.hysky.skyblocker.skyblock.special; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.minecraft.client.MinecraftClient; -import net.minecraft.enchantment.Enchantments; import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.nbt.StringNbtReader; import net.minecraft.particle.ParticleTypes; import net.minecraft.text.Text; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class SpecialEffects { private static final Logger LOGGER = LoggerFactory.getLogger(SpecialEffects.class); private static final Pattern DROP_PATTERN = Pattern.compile("(?:\\[[A-Z+]+] )?(?<player>[A-Za-z0-9_]+) unlocked (?<item>.+)!"); - private static final ItemStack NECRON_HANDLE = new ItemStack(Items.STICK); - private static final ItemStack SCROLL = new ItemStack(Items.WRITABLE_BOOK); - private static ItemStack TIER_5_SKULL; - private static ItemStack FIFTH_STAR; - - static { - NECRON_HANDLE.addEnchantment(Enchantments.PROTECTION, 1); - SCROLL.addEnchantment(Enchantments.PROTECTION, 1); - try { - TIER_5_SKULL = ItemStack.fromNbt(StringNbtReader.parse("{id:\"minecraft:player_head\",Count:1,tag:{SkullOwner:{Id:[I;-1613868903,-527154034,-1445577520,748807544],Properties:{textures:[{Value:\"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTEwZjlmMTA4NWQ0MDcxNDFlYjc3NjE3YTRhYmRhYWEwOGQ4YWYzM2I5NjAyMDBmZThjMTI2YzFkMTQ0NTY4MiJ9fX0=\"}]}}}}")); - FIFTH_STAR = ItemStack.fromNbt(StringNbtReader.parse("{id:\"minecraft:player_head\",Count:1,tag:{SkullOwner:{Id:[I;1904417095,756174249,-1302927470,1407004198],Properties:{textures:[{Value:\"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzFjODA0MjUyN2Y4MWM4ZTI5M2UyODEwMTEzNDg5ZjQzOTRjYzZlZmUxNWQxYWZhYzQzMTU3MWM3M2I2MmRjNCJ9fX0=\"}]}}}}")); - } catch (Exception e) { - TIER_5_SKULL = ItemStack.EMPTY; - FIFTH_STAR = ItemStack.EMPTY; - LOGGER.error("[Skyblocker Special Effects] Failed to parse NBT for a player head!", e); - } - } public static void init() { ClientReceiveMessageEvents.GAME.register(SpecialEffects::displayRareDropEffect); @@ -45,7 +27,7 @@ public class SpecialEffects { private static void displayRareDropEffect(Text message, boolean overlay) { //We don't check if we're in dungeons because that check doesn't work in m7 which defeats the point of this //It might also allow it to work with Croesus - if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.specialEffects.rareDungeonDropEffects) { + if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.specialEffects.rareDungeonDropEffects && !overlay) { try { String stringForm = message.getString(); Matcher matcher = DROP_PATTERN.matcher(stringForm); @@ -57,7 +39,7 @@ public class SpecialEffects { if (player.equals(client.getSession().getUsername())) { ItemStack stack = getStackFromName(matcher.group("item")); - if (!stack.isEmpty()) { + if (stack != null && !stack.isEmpty()) { RenderHelper.runOnRenderThread(() -> { client.particleManager.addEmitter(client.player, ParticleTypes.PORTAL, 30); client.gameRenderer.showFloatingItem(stack); @@ -72,20 +54,22 @@ public class SpecialEffects { } private static ItemStack getStackFromName(String itemName) { - return switch (itemName) { + String itemId = switch (itemName) { //M7 - case "Necron Dye" -> new ItemStack(Items.ORANGE_DYE); - case "Dark Claymore" -> new ItemStack(Items.STONE_SWORD); - case "Necron's Handle", "Shiny Necron's Handle" -> NECRON_HANDLE; - case "Enchanted Book (Thunderlord VII)" -> new ItemStack(Items.ENCHANTED_BOOK); - case "Master Skull - Tier 5" -> TIER_5_SKULL; - case "Shadow Warp", "Wither Shield", "Implosion" -> SCROLL; - case "Fifth Master Star" -> FIFTH_STAR; + case "Necron Dye" -> "NECRON_DYE"; + case "Dark Claymore" -> "DARK_CLAYMORE"; + case "Necron's Handle", "Shiny Necron's Handle" -> "NECRON_HANDLE"; + case "Enchanted Book (Thunderlord VII)" -> "ENCHANTED_BOOK"; + case "Master Skull - Tier 5" -> "MASTER_SKULL_TIER_5"; + case "Shadow Warp", "Wither Shield", "Implosion" -> "IMPLOSION_SCROLL"; + case "Fifth Master Star" -> "FIFTH_MASTER_STAR"; //M6 - case "Giant's Sword" -> new ItemStack(Items.IRON_SWORD); + case "Giant's Sword" -> "GIANTS_SWORD"; - default -> ItemStack.EMPTY; + default -> "NONE"; }; + + return ItemRepository.getItemStack(itemId); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java index 3ef968a3..472cf700 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java @@ -4,7 +4,7 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import de.hysky.skyblocker.mixin.accessor.PlayerListHudAccessor; +import de.hysky.skyblocker.mixins.accessors.PlayerListHudAccessor; import de.hysky.skyblocker.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/component/ProgressComponent.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/component/ProgressComponent.java index c4388178..9522be43 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/component/ProgressComponent.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/component/ProgressComponent.java @@ -5,7 +5,6 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.math.MathHelper; /** @@ -37,7 +36,7 @@ public class ProgressComponent extends Component { this.ico = (ico == null) ? Ico.BARRIER : ico; this.desc = d; this.bar = b; - this.pcnt = MathHelper.clamp(pcnt, 0f, 100f); + this.pcnt = Math.clamp(pcnt, 0f, 100f); this.color = 0xff000000 | color; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java index 93c6b3f4..b70bac47 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java @@ -58,7 +58,6 @@ import net.minecraft.command.argument.PosArgument; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class OrderedWaypoints { @@ -144,7 +143,7 @@ public class OrderedWaypoints { OrderedWaypoint waypoint = new OrderedWaypoint(pos, colorComponents); if (index != Integer.MIN_VALUE) { - int indexToAddAt = MathHelper.clamp(index, 0, group.waypoints().size()); + int indexToAddAt = Math.clamp(index, 0, group.waypoints().size()); group.waypoints().add(indexToAddAt, waypoint); INDEX_STORE.removeInt(group.name()); @@ -188,7 +187,7 @@ public class OrderedWaypoints { } if (index != Integer.MIN_VALUE) { - int indexToRemove = MathHelper.clamp(index, 0, group.waypoints().size() - 1); + int indexToRemove = Math.clamp(index, 0, group.waypoints().size() - 1); group.waypoints().remove(indexToRemove); INDEX_STORE.removeInt(group.name()); @@ -221,6 +220,7 @@ public class OrderedWaypoints { for (OrderedWaypointGroup group : WAYPOINTS.values()) { if (group.enabled()) { List<OrderedWaypoint> waypoints = group.waypoints(); + if (waypoints.isEmpty()) continue; ClientPlayerEntity player = MinecraftClient.getInstance().player; int centreIndex = INDEX_STORE.computeIfAbsent(group.name(), name -> 0); @@ -258,7 +258,7 @@ public class OrderedWaypoints { private static void load() { loaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = Files.newBufferedReader(PATH)) { - WAYPOINTS.putAll(SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow()); + WAYPOINTS.putAll(SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow()); } catch (NoSuchFileException ignored) { } catch (Exception e) { LOGGER.error("[Skyblocker Ordered Waypoints] Failed to load the waypoints! :(", e); @@ -268,7 +268,7 @@ public class OrderedWaypoints { private static void save() { try (BufferedWriter writer = Files.newBufferedWriter(PATH)) { - SkyblockerMod.GSON.toJson(SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, WAYPOINTS).result().orElseThrow(), writer); + SkyblockerMod.GSON.toJson(SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, WAYPOINTS).getOrThrow(), writer); } catch (Exception e) { LOGGER.error("[Skyblocker Ordered Waypoints] Failed to save the waypoints! :(", e); } @@ -276,7 +276,7 @@ public class OrderedWaypoints { private static int export(FabricClientCommandSource source) { try { - String json = new Gson().toJson(SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, WAYPOINTS).result().orElseThrow()); + String json = new Gson().toJson(SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, WAYPOINTS).getOrThrow()); ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(out); @@ -306,7 +306,7 @@ public class OrderedWaypoints { byte[] decoded = Base64.getDecoder().decode(encoded); String json = new String(new GZIPInputStream(new ByteArrayInputStream(decoded)).readAllBytes()); - Map<String, OrderedWaypointGroup> importedWaypoints = SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(json)).result().orElseThrow(); + Map<String, OrderedWaypointGroup> importedWaypoints = SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(json)).getOrThrow(); SEMAPHORE.acquireUninterruptibly(); WAYPOINTS.putAll(importedWaypoints); @@ -332,7 +332,7 @@ public class OrderedWaypoints { } String json = MinecraftClient.getInstance().keyboard.getClipboard(); - List<ColeWeightWaypoint> coleWeightWaypoints = ColeWeightWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(json)).result().orElseThrow(); + List<ColeWeightWaypoint> coleWeightWaypoints = ColeWeightWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(json)).getOrThrow(); ObjectArrayList<OrderedWaypoint> convertedWaypoints = new ObjectArrayList<>(); for (ColeWeightWaypoint waypoint : coleWeightWaypoints) { diff --git a/src/main/java/de/hysky/skyblocker/utils/Constants.java b/src/main/java/de/hysky/skyblocker/utils/Constants.java index 403689ac..d900f917 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Constants.java +++ b/src/main/java/de/hysky/skyblocker/utils/Constants.java @@ -12,7 +12,7 @@ import java.util.function.Supplier; * Holds generic static constants */ public interface Constants { - String LEVEL_EMBLEMS = "\u2E15\u273F\u2741\u2E19\u03B1\u270E\u2615\u2616\u2663\u213B\u2694\u27B6\u26A1\u2604\u269A\u2693\u2620\u269B\u2666\u2660\u2764\u2727\u238A\u1360\u262C\u269D\u29C9\uA214\u32D6\u2E0E\u26A0\uA541\u3020\u30C4\u2948\u2622\u2623\u273E\u269C\u0BD0\u0A6D\u2742\u16C3\u3023\u10F6\u0444\u266A\u266B\u04C3\u26C1\u26C3\u16DD\uA03E\u1C6A\u03A3\u09EB\u2603\u2654\u26C2\u0FC7\uA925\uA56A\u12DE"; + String LEVEL_EMBLEMS = "\u2E15\u273F\u2741\u2E19\u03B1\u270E\u2615\u2616\u2663\u213B\u2694\u27B6\u26A1\u2604\u269A\u2693\u2620\u269B\u2666\u2660\u2764\u2727\u238A\u1360\u262C\u269D\u29C9\uA214\u32D6\u2E0E\u26A0\uA541\u3020\u30C4\u2948\u2622\u2623\u273E\u269C\u0BD0\u0A6D\u2742\u16C3\u3023\u10F6\u0444\u266A\u266B\u04C3\u26C1\u26C3\u16DD\uA03E\u1C6A\u03A3\u09EB\u2603\u2654\u26C2\u0FC7\uA925\uA56A\u2592\u12DE"; Supplier<MutableText> PREFIX = () -> { LocalDate time = LocalDate.now(); return Text.empty() diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 70a8c241..086686a7 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -1,29 +1,41 @@ package de.hysky.skyblocker.utils; +import com.google.gson.Gson; +import com.google.gson.JsonParser; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import com.mojang.brigadier.Command; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import de.hysky.skyblocker.mixin.accessor.ItemStackAccessor; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.ints.IntIntPair; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.component.ComponentChanges; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.component.type.ProfileComponent; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; -import net.minecraft.nbt.StringNbtReader; +import net.minecraft.registry.Registries; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.text.Text; -import net.minecraft.text.Texts; import net.minecraft.util.Formatting; +import net.minecraft.util.dynamic.Codecs; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.time.temporal.TemporalAccessor; +import java.util.List; +import java.util.Locale; +import java.util.Optional; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,83 +43,72 @@ import java.util.regex.Pattern; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; public class ItemUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(ItemUtils.class); - public static final String EXTRA_ATTRIBUTES = "ExtraAttributes"; public static final String ID = "id"; public static final String UUID = "uuid"; private static final DateTimeFormatter OBTAINED_DATE_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy").withZone(ZoneId.systemDefault()).localizedBy(Locale.ENGLISH); - private static final SimpleDateFormat OLD_OBTAINED_DATE_FORMAT = new SimpleDateFormat("MM/dd/yy"); + private static final DateTimeFormatter OLD_OBTAINED_DATE_FORMAT = DateTimeFormatter.ofPattern("M/d/yy h:m a").withZone(ZoneId.of("UTC")).localizedBy(Locale.ENGLISH); public static final Pattern NOT_DURABILITY = Pattern.compile("[^0-9 /]"); public static final Predicate<String> FUEL_PREDICATE = line -> line.contains("Fuel: "); - - public static LiteralArgumentBuilder<FabricClientCommandSource> dumpHeldItemNbtCommand() { - return literal("dumpHeldItemNbt").executes(context -> { - context.getSource().sendFeedback(Text.literal("[Skyblocker Debug] Held Item Nbt: " + context.getSource().getPlayer().getMainHandStack().writeNbt(new NbtCompound()))); + private static final Gson GSON = new Gson(); //GSON Instance with no config + private static final Codec<RegistryEntry<Item>> EMPTY_ALLOWING_ITEM_CODEC = Registries.ITEM.getEntryCodec(); + public static final Codec<ItemStack> EMPTY_ALLOWING_ITEMSTACK_CODEC = Codec.lazyInitialized(() -> RecordCodecBuilder.create(instance -> instance.group( + EMPTY_ALLOWING_ITEM_CODEC.fieldOf("id").forGetter(ItemStack::getRegistryEntry), + Codec.INT.orElse(1).fieldOf("count").forGetter(ItemStack::getCount), + ComponentChanges.CODEC.optionalFieldOf("components", ComponentChanges.EMPTY).forGetter(ItemStack::getComponentChanges) + ).apply(instance, ItemStack::new))); + + public static LiteralArgumentBuilder<FabricClientCommandSource> dumpHeldItemCommand() { + return literal("dumpHeldItem").executes(context -> { + context.getSource().sendFeedback(Text.literal("[Skyblocker Debug] Held Item: " + GSON.toJson(ItemStack.CODEC.encodeStart(JsonOps.INSTANCE, context.getSource().getPlayer().getMainHandStack()).getOrThrow()))); return Command.SINGLE_SUCCESS; }); } - /** - * Gets the {@code ExtraAttributes} NBT tag from the item stack. - * - * @param stack the item stack to get the {@code ExtraAttributes} NBT tag from - * @return an optional containing the {@code ExtraAttributes} NBT tag of the item stack - */ - public static Optional<NbtCompound> getExtraAttributesOptional(@NotNull ItemStack stack) { - return Optional.ofNullable(stack.getSubNbt(EXTRA_ATTRIBUTES)); - } - - /** - * Gets the {@code ExtraAttributes} NBT tag from the item stack. - * - * @param stack the item stack to get the {@code ExtraAttributes} NBT tag from - * @return the {@code ExtraAttributes} NBT tag of the item stack, or null if the item stack is null or does not have an {@code ExtraAttributes} NBT tag - */ - @Nullable - public static NbtCompound getExtraAttributes(@NotNull ItemStack stack) { - return stack.getSubNbt(EXTRA_ATTRIBUTES); + @SuppressWarnings("deprecation") + public static NbtCompound getCustomData(@NotNull ItemStack stack) { + return stack.getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).getNbt(); } /** - * Gets the internal name of the item stack from the {@code ExtraAttributes} NBT tag. + * Gets the Skyblock item id of the item stack. * * @param stack the item stack to get the internal name from * @return an optional containing the internal name of the item stack */ - public static Optional<String> getItemIdOptional(@NotNull ItemStack stack) { - return getExtraAttributesOptional(stack).map(extraAttributes -> extraAttributes.getString(ID)); + public static Optional<String> getItemIdOptional(@NotNull ItemStack stack) { + NbtCompound customData = getCustomData(stack); + return customData.contains(ID) ? Optional.of(customData.getString(ID)) : Optional.empty(); } /** - * Gets the internal name of the item stack from the {@code ExtraAttributes} NBT tag. + * Gets the Skyblock item id of the item stack. * * @param stack the item stack to get the internal name from * @return the internal name of the item stack, or an empty string if the item stack is null or does not have an internal name */ - public static String getItemId(@NotNull ItemStack stack) { - NbtCompound extraAttributes = getExtraAttributes(stack); - return extraAttributes != null ? extraAttributes.getString(ID) : ""; + public static String getItemId(@NotNull ItemStack stack) { + return getCustomData(stack).getString(ID); } /** - * Gets the UUID of the item stack from the {@code ExtraAttributes} NBT tag. + * Gets the UUID of the item stack. * * @param stack the item stack to get the UUID from * @return an optional containing the UUID of the item stack */ - public static Optional<String> getItemUuidOptional(@NotNull ItemStack stack) { - return getExtraAttributesOptional(stack).map(extraAttributes -> extraAttributes.getString(UUID)); + public static Optional<String> getItemUuidOptional(@NotNull ItemStack stack) { + NbtCompound customData = getCustomData(stack); + return customData.contains(UUID) ? Optional.of(customData.getString(UUID)) : Optional.empty(); } /** - * Gets the UUID of the item stack from the {@code ExtraAttributes} NBT tag. + * Gets the UUID of the item stack. * * @param stack the item stack to get the UUID from * @return the UUID of the item stack, or an empty string if the item stack is null or does not have a UUID */ - public static String getItemUuid(@NotNull ItemStack stack) { - NbtCompound extraAttributes = getExtraAttributes(stack); - return extraAttributes != null ? extraAttributes.getString(UUID) : ""; + public static String getItemUuid(@NotNull ItemStack stack) { + return getCustomData(stack).getString(UUID); } /** @@ -126,47 +127,41 @@ public class ItemUtils { * @param stack the item under the pointer * @return if the item have a "Timestamp" it will be shown formated on the tooltip */ - public static String getTimestamp(ItemStack stack) { - NbtCompound ea = getExtraAttributes(stack); - - if (ea != null && ea.contains("timestamp", NbtElement.LONG_TYPE)) { - Instant date = Instant.ofEpochMilli(ea.getLong("timestamp")); + public static String getTimestamp(ItemStack stack) { + NbtCompound customData = getCustomData(stack); + if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { + Instant date = Instant.ofEpochMilli(customData.getLong("timestamp")); return OBTAINED_DATE_FORMATTER.format(date); } - if (ea != null && ea.contains("timestamp", NbtElement.STRING_TYPE)) { - try { - Instant date = OLD_OBTAINED_DATE_FORMAT.parse(ea.getString("timestamp")).toInstant(); - - return OBTAINED_DATE_FORMATTER.format(date); - } catch (ParseException e) { - LOGGER.warn("[Skyblocker Item Utils] Encountered an unknown exception while parsing time stamp of item {} with extra attributes {}", stack, ea, e); - } + if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { + TemporalAccessor date = OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); + return OBTAINED_DATE_FORMATTER.format(date); } return ""; } public static boolean hasCustomDurability(@NotNull ItemStack stack) { - NbtCompound extraAttributes = getExtraAttributes(stack); - return extraAttributes != null && (extraAttributes.contains("drill_fuel") || extraAttributes.getString(ID).equals("PICKONIMBUS")); + NbtCompound customData = getCustomData(stack); + return customData != null && (customData.contains("drill_fuel") || customData.getString(ID).equals("PICKONIMBUS")); } @Nullable public static IntIntPair getDurability(@NotNull ItemStack stack) { - NbtCompound extraAttributes = getExtraAttributes(stack); - if (extraAttributes == null) return null; + NbtCompound customData = getCustomData(stack); + if (customData == null) return null; // TODO Calculate drill durability based on the drill_fuel flag, fuel_tank flag, and hotm level // TODO Cache the max durability and only update the current durability on inventory tick - int pickonimbusDurability = extraAttributes.getInt("pickonimbus_durability"); + int pickonimbusDurability = customData.getInt("pickonimbus_durability"); if (pickonimbusDurability > 0) { return IntIntPair.of(pickonimbusDurability, 5000); } - String drillFuel = Formatting.strip(getNbtTooltip(stack, FUEL_PREDICATE)); + String drillFuel = Formatting.strip(getLoreLineIf(stack, FUEL_PREDICATE)); if (drillFuel != null) { String[] drillFuelStrings = NOT_DURABILITY.matcher(drillFuel).replaceAll("").trim().split("/"); return IntIntPair.of(Integer.parseInt(drillFuelStrings[0]), Integer.parseInt(drillFuelStrings[1]) * 1000); @@ -176,8 +171,8 @@ public class ItemUtils { } @Nullable - public static String getNbtTooltip(ItemStack item, Predicate<String> predicate) { - for (Text line : getNbtTooltips(item)) { + public static String getLoreLineIf(ItemStack item, Predicate<String> predicate) { + for (Text line : getLore(item)) { String string = line.getString(); if (predicate.test(string)) { return string; @@ -188,8 +183,8 @@ public class ItemUtils { } @Nullable - public static Matcher getNbtTooltip(ItemStack item, Pattern pattern) { - for (Text line : getNbtTooltips(item)) { + public static Matcher getLoreLineIfMatch(ItemStack item, Pattern pattern) { + for (Text line : getLore(item)) { String string = line.getString(); Matcher matcher = pattern.matcher(string); if (matcher.matches()) { @@ -200,19 +195,32 @@ public class ItemUtils { return null; } - public static List<Text> getNbtTooltips(ItemStack item) { - NbtCompound displayNbt = item.getSubNbt("display"); - if (displayNbt == null || !displayNbt.contains("Lore", NbtElement.LIST_TYPE)) { - return Collections.emptyList(); - } + public static List<Text> getLore(ItemStack item) { + return item.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT).styledLines(); + } + + public static PropertyMap propertyMapWithTexture(String textureValue) { + return Codecs.GAME_PROFILE_PROPERTY_MAP.parse(JsonOps.INSTANCE, JsonParser.parseString("[{\"name\":\"textures\",\"value\":\"" + textureValue + "\"}]")).getOrThrow(); + } + + public static String getHeadTexture(ItemStack stack) { + if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return ""; + + ProfileComponent profile = stack.get(DataComponentTypes.PROFILE); + String texture = profile.properties().get("textures").stream() + .map(Property::value) + .findFirst() + .orElse(""); - return displayNbt.getList("Lore", NbtElement.STRING_TYPE).stream().map(NbtElement::asString).map(Text.Serialization::fromJson).filter(Objects::nonNull).map(text -> Texts.setStyleIfAbsent(text, ItemStackAccessor.getLORE_STYLE())).map(Text.class::cast).toList(); + return texture; } public static ItemStack getSkyblockerStack() { try { - return ItemStack.fromNbt(StringNbtReader.parse("{id:\"minecraft:player_head\",Count:1,tag:{SkullOwner:{Id:[I;-300151517,-631415889,-1193921967,-1821784279],Properties:{textures:[{Value:\"e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDdjYzY2ODc0MjNkMDU3MGQ1NTZhYzUzZTA2NzZjYjU2M2JiZGQ5NzE3Y2Q4MjY5YmRlYmVkNmY2ZDRlN2JmOCJ9fX0=\"}]}}}}")); - } catch (CommandSyntaxException e) { + ItemStack stack = new ItemStack(Items.PLAYER_HEAD); + stack.set(DataComponentTypes.PROFILE, new ProfileComponent(Optional.of("SkyblockerStack"), Optional.of(java.util.UUID.randomUUID()), propertyMapWithTexture("e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDdjYzY2ODc0MjNkMDU3MGQ1NTZhYzUzZTA2NzZjYjU2M2JiZGQ5NzE3Y2Q4MjY5YmRlYmVkNmY2ZDRlN2JmOCJ9fX0="))); + return stack; + } catch (Exception e) { throw new RuntimeException(e); } } diff --git a/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java b/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java index cda92273..f8716ca4 100644 --- a/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java @@ -51,6 +51,10 @@ public class NEURepoManager { ); } + public static boolean isLoading() { + return REPO_LOADING != null && !REPO_LOADING.isDone(); + } + private static CompletableFuture<Boolean> loadRepository() { return CompletableFuture.supplyAsync(() -> { try { @@ -78,7 +82,7 @@ public class NEURepoManager { } private static void deleteAndDownloadRepository(PlayerEntity player) { - if (REPO_LOADING != null && !REPO_LOADING.isDone()) { + if (isLoading()) { sendMessage(player, Constants.PREFIX.get().append(Text.translatable("skyblocker.updateRepository.loading"))); return; } diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index bbee3ce1..dc13b61d 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.utils; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import de.hysky.skyblocker.events.SkyblockEvents; +import de.hysky.skyblocker.mixins.accessors.MessageHandlerAccessor; import de.hysky.skyblocker.skyblock.item.MuseumItemCache; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; @@ -25,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -217,7 +219,6 @@ public class Utils { } if (sidebar.isEmpty() && !fabricLoader.isDevelopmentEnvironment()) return; - String string = sidebar.toString(); if (fabricLoader.isDevelopmentEnvironment() || isConnectedToHypixel(client)) { if (!isOnHypixel) { @@ -466,4 +467,17 @@ public class Utils { }); } + + /** + * Used to avoid triggering things like chat rules or chat listeners infinitely, do not use otherwise. + * + * Bypasses MessageHandler#onGameMessage + */ + public static void sendMessageToBypassEvents(Text message) { + MinecraftClient client = MinecraftClient.getInstance(); + + client.inGameHud.getChatHud().addMessage(message); + ((MessageHandlerAccessor) client.getMessageHandler()).invokeAddToChatLog(message, Instant.now()); + client.getNarratorManager().narrateSystemMessage(message); + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java index bdff2d94..1f0caff5 100644 --- a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java +++ b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java @@ -15,6 +15,7 @@ import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; @FunctionalInterface public interface ChatMessageListener { @@ -68,7 +69,7 @@ public interface ChatMessageListener { if (!Utils.isOnSkyblock()) { return true; } - ChatFilterResult result = EVENT.invoker().onMessage(message, message.getString()); + ChatFilterResult result = EVENT.invoker().onMessage(message, Formatting.strip(message.getString())); switch (result) { case ACTION_BAR -> { if (overlay) { diff --git a/src/main/java/de/hysky/skyblocker/utils/datafixer/ItemStackComponentizationFixer.java b/src/main/java/de/hysky/skyblocker/utils/datafixer/ItemStackComponentizationFixer.java new file mode 100644 index 00000000..3543a2f1 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/datafixer/ItemStackComponentizationFixer.java @@ -0,0 +1,82 @@ +package de.hysky.skyblocker.utils.datafixer; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import com.mojang.brigadier.StringReader; +import com.mojang.serialization.Dynamic; + +import net.minecraft.command.argument.ItemStringReader; +import net.minecraft.command.argument.ItemStringReader.ItemResult; +import net.minecraft.component.DataComponentType; +import net.minecraft.datafixer.Schemas; +import net.minecraft.datafixer.TypeReferences; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtOps; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryOps; +import net.minecraft.util.Identifier; + +/** + * Contains a data fixer to convert legacy item NBT to the new components system, among other fixers related to the item components system. + * + * @see net.minecraft.datafixer.fix.ItemStackComponentizationFix + */ +public class ItemStackComponentizationFixer { + private static final int ITEM_NBT_DATA_VERSION = 3817; + private static final int ITEM_COMPONENTS_DATA_VERSION = 3825; + private static final DynamicRegistryManager REGISTRY_MANAGER = new DynamicRegistryManager.ImmutableImpl(List.of(Registries.ITEM, Registries.DATA_COMPONENT_TYPE)); + + public static ItemStack fixUpItem(NbtCompound nbt) { + Dynamic<NbtElement> dynamic = Schemas.getFixer().update(TypeReferences.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, nbt), ITEM_NBT_DATA_VERSION, ITEM_COMPONENTS_DATA_VERSION); + + return ItemStack.CODEC.parse(dynamic).getOrThrow(); + } + + /** + * Modified version of {@link net.minecraft.command.argument.ItemStackArgument#asString(net.minecraft.registry.RegistryWrapper.WrapperLookup)} to only care about changed components. + * + * @return The {@link ItemStack}'s components as a string which is in the format that the {@code /give} command accepts. + */ + public static String componentsAsString(ItemStack stack) { + RegistryOps<NbtElement> nbtRegistryOps = REGISTRY_MANAGER.getOps(NbtOps.INSTANCE); + + return Arrays.toString(stack.getComponentChanges().entrySet().stream().map(entry -> { + @SuppressWarnings("unchecked") + DataComponentType<Object> dataComponentType = (DataComponentType<Object>) entry.getKey(); + Identifier componentId = Registries.DATA_COMPONENT_TYPE.getId(dataComponentType); + Optional<NbtElement> encodedComponent = dataComponentType.getCodec().encodeStart(nbtRegistryOps, entry.getValue().orElseThrow()).result(); + + if (componentId == null || encodedComponent.isEmpty()) { + return null; + } + + return componentId + "=" + encodedComponent.orElseThrow(); + }).filter(Objects::nonNull).toArray()); + } + + /** + * Constructs an {@link ItemStack} from an {@code itemId}, with item components in string format as returned by {@link #componentsAsString(ItemStack)}, and with a specified stack count. + * + * @return an {@link ItemStack} or {@link ItemStack#EMPTY} if there was an exception thrown. + */ + public static ItemStack fromComponentsString(String itemId, int count, String componentsString) { + ItemStringReader reader = new ItemStringReader(REGISTRY_MANAGER); + + try { + ItemResult result = reader.consume(new StringReader(itemId + componentsString)); + ItemStack stack = new ItemStack(result.item(), count); + + stack.applyComponentsFrom(result.components()); + + return stack; + } catch (Exception ignored) {} + + return ItemStack.EMPTY; + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/render/FrustumUtils.java b/src/main/java/de/hysky/skyblocker/utils/render/FrustumUtils.java index 3fe79e43..d82b4497 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/FrustumUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/FrustumUtils.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.utils.render; -import de.hysky.skyblocker.mixin.accessor.FrustumInvoker; -import de.hysky.skyblocker.mixin.accessor.WorldRendererAccessor; +import de.hysky.skyblocker.mixins.accessors.FrustumInvoker; +import de.hysky.skyblocker.mixins.accessors.WorldRendererAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.Frustum; import net.minecraft.util.math.Box; diff --git a/src/main/java/de/hysky/skyblocker/utils/render/MatrixHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/MatrixHelper.java new file mode 100644 index 00000000..220dbf86 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/render/MatrixHelper.java @@ -0,0 +1,30 @@ +package de.hysky.skyblocker.utils.render; + +import org.joml.Matrix4f; + +import net.minecraft.client.util.math.MatrixStack; + +/** + * Matrix helper methods + */ +public interface MatrixHelper { + + /** + * Copies the {@code matrix} into a new {@link Matrix4f}. This is necessary otherwise + * any transformations applied will affect other uses of the same matrix. + */ + static Matrix4f copyOf(Matrix4f matrix) { + return new Matrix4f(matrix); + } + + /** + * Creates a blank {@link MatrixStack} and sets it's position matrix to the supplied + * {@code positionMatrix}. + */ + static MatrixStack toStack(Matrix4f positionMatrix) { + MatrixStack matrices = new MatrixStack(); + matrices.peek().getPositionMatrix().set(positionMatrix); + + return matrices; + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java index da179d0e..a6772fb2 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -3,8 +3,8 @@ package de.hysky.skyblocker.utils.render; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.logging.LogUtils; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.mixin.accessor.BeaconBlockEntityRendererInvoker; -import de.hysky.skyblocker.mixin.accessor.DrawContextInvoker; +import de.hysky.skyblocker.mixins.accessors.BeaconBlockEntityRendererInvoker; +import de.hysky.skyblocker.mixins.accessors.DrawContextInvoker; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; @@ -26,6 +26,7 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; + import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -243,15 +244,13 @@ public class RenderHelper { } public static void renderQuad(WorldRenderContext context, Vec3d[] points, float[] colorComponents, float alpha, boolean throughWalls) { + Matrix4f positionMatrix = new Matrix4f(); Vec3d camera = context.camera().getPos(); - MatrixStack matrices = context.matrixStack(); - matrices.push(); - matrices.translate(-camera.x, -camera.y, -camera.z); + positionMatrix.translate((float) -camera.x, (float) -camera.y, (float) -camera.z); Tessellator tessellator = RenderSystem.renderThreadTesselator(); BufferBuilder buffer = tessellator.getBuffer(); - Matrix4f positionMatrix = matrices.peek().getPositionMatrix(); RenderSystem.setShader(GameRenderer::getPositionColorProgram); RenderSystem.setShaderColor(1f, 1f, 1f, 1f); @@ -268,8 +267,6 @@ public class RenderHelper { RenderSystem.enableCull(); RenderSystem.depthFunc(GL11.GL_LEQUAL); - - matrices.pop(); } public static void renderText(WorldRenderContext context, Text text, Vec3d pos, boolean throughWalls) { @@ -290,19 +287,18 @@ public class RenderHelper { * @param throughWalls whether the text should be able to be seen through walls or not. */ public static void renderText(WorldRenderContext context, OrderedText text, Vec3d pos, float scale, float yOffset, boolean throughWalls) { - MatrixStack matrices = context.matrixStack(); - Vec3d camera = context.camera().getPos(); + Matrix4f positionMatrix = new Matrix4f(); + Camera camera = context.camera(); + Vec3d cameraPos = camera.getPos(); TextRenderer textRenderer = client.textRenderer; scale *= 0.025f; - matrices.push(); - matrices.translate(pos.getX() - camera.getX(), pos.getY() - camera.getY(), pos.getZ() - camera.getZ()); - matrices.peek().getPositionMatrix().mul(RenderSystem.getModelViewMatrix()); - matrices.multiply(context.camera().getRotation()); - matrices.scale(-scale, -scale, scale); + positionMatrix + .translate((float) (pos.getX() - cameraPos.getX()), (float) (pos.getY() - cameraPos.getY()), (float) (pos.getZ() - cameraPos.getZ())) + .rotate(camera.getRotation()) + .scale(-scale, -scale, scale); - Matrix4f positionMatrix = matrices.peek().getPositionMatrix(); float xOffset = -textRenderer.getWidth(text) / 2f; Tessellator tessellator = RenderSystem.renderThreadTesselator(); @@ -315,7 +311,6 @@ public class RenderHelper { consumers.draw(); RenderSystem.depthFunc(GL11.GL_LEQUAL); - matrices.pop(); } /** diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java index 4f648b8c..ef2e6bf9 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java @@ -1,6 +1,6 @@ package de.hysky.skyblocker.utils.render.gui; -import de.hysky.skyblocker.mixin.accessor.HandledScreenAccessor; +import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.skyblock.auction.AuctionHouseScreenHandler; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.entity.player.PlayerInventory; diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java index 80a1ba9d..e2e057b3 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java @@ -1,11 +1,11 @@ package de.hysky.skyblocker.utils.render.gui; import de.hysky.skyblocker.SkyblockerMod; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.item.ItemStack; import java.util.List; -import java.util.Map; import java.util.regex.Pattern; /** @@ -34,9 +34,12 @@ public abstract class ContainerSolver { SkyblockerMod.getInstance().containerSolverManager.markDirty(); } - protected abstract List<ColorHighlight> getColors(String[] groups, Map<Integer, ItemStack> slots); + protected void onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) { + } + + protected abstract List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots); - protected void trimEdges(Map<Integer, ItemStack> slots, int rows) { + protected void trimEdges(Int2ObjectMap<ItemStack> slots, int rows) { for (int i = 0; i < rows; i++) { slots.remove(9 * i); slots.remove(9 * i + 8); diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java index e5b2dddb..b37c57a4 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java @@ -1,7 +1,8 @@ package de.hysky.skyblocker.utils.render.gui; import com.mojang.blaze3d.systems.RenderSystem; -import de.hysky.skyblocker.mixin.accessor.HandledScreenAccessor; + +import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.skyblock.accessories.newyearcakes.NewYearCakeBagHelper; import de.hysky.skyblocker.skyblock.accessories.newyearcakes.NewYearCakesHelper; import de.hysky.skyblocker.skyblock.dungeon.CroesusHelper; @@ -13,6 +14,8 @@ import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver; import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver; import de.hysky.skyblocker.skyblock.experiment.UltrasequencerSolver; import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; @@ -22,8 +25,6 @@ import net.minecraft.screen.slot.Slot; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.Map; -import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -36,6 +37,10 @@ public class ContainerSolverManager { private ContainerSolver currentSolver = null; private String[] groups; private List<ColorHighlight> highlights; + /** + * Useful for keeping track of a solver's state in a Screen instance, such as if Hypixel closes & reopens a screen after every click (as they do with terminals). + */ + private int screenId = 0; public ContainerSolverManager() { solvers = new ContainerSolver[]{ @@ -82,6 +87,7 @@ public class ContainerSolverManager { matcher.usePattern(solver.getName()); matcher.reset(); if (matcher.matches()) { + ++screenId; currentSolver = solver; groups = new String[matcher.groupCount()]; for (int i = 0; i < groups.length; i++) { @@ -89,6 +95,7 @@ public class ContainerSolverManager { } currentSolver.start(screen); markDirty(); + return; } } @@ -107,6 +114,12 @@ public class ContainerSolverManager { highlights = null; } + public void onSlotClick(int slot, ItemStack stack) { + if (currentSolver != null) { + currentSolver.onClickSlot(slot, stack, screenId, groups); + } + } + public void onDraw(DrawContext context, List<Slot> slots) { if (currentSolver == null) return; @@ -122,8 +135,8 @@ public class ContainerSolverManager { RenderSystem.colorMask(true, true, true, true); } - private Map<Integer, ItemStack> slotMap(List<Slot> slots) { - Map<Integer, ItemStack> slotMap = new TreeMap<>(); + private Int2ObjectMap<ItemStack> slotMap(List<Slot> slots) { + Int2ObjectMap<ItemStack> slotMap = new Int2ObjectRBTreeMap<>(); for (int i = 0; i < slots.size(); i++) { slotMap.put(i, slots.get(i).getStack()); } diff --git a/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java b/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java index 487e3d8b..a115bb2b 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java @@ -2,10 +2,10 @@ package de.hysky.skyblocker.utils.render.title; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.events.HudRenderEvents; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -26,7 +26,7 @@ public class TitleContainer { private static final Set<Title> titles = new LinkedHashSet<>(); public static void init() { - HudRenderCallback.EVENT.register(TitleContainer::render); + HudRenderEvents.BEFORE_CHAT.register(TitleContainer::render); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker") .then(ClientCommandManager.literal("hud") .then(ClientCommandManager.literal("titleContainer") @@ -148,7 +148,7 @@ public class TitleContainer { //Translate the matrix to the texts position and scale context.getMatrices().push(); - context.getMatrices().translate(title.x, title.y, 200); + context.getMatrices().translate(title.x, title.y, 0); context.getMatrices().scale(scale, scale, scale); //Draw text diff --git a/src/main/java/de/hysky/skyblocker/utils/tictactoe/BoardIndex.java b/src/main/java/de/hysky/skyblocker/utils/tictactoe/BoardIndex.java new file mode 100644 index 00000000..bd9200ad --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tictactoe/BoardIndex.java @@ -0,0 +1,5 @@ +package de.hysky.skyblocker.utils.tictactoe; + +public record BoardIndex(int row, int column) { + +} diff --git a/src/main/java/de/hysky/skyblocker/utils/tictactoe/TicTacToeUtils.java b/src/main/java/de/hysky/skyblocker/utils/tictactoe/TicTacToeUtils.java index fde18f27..0725b2ce 100644 --- a/src/main/java/de/hysky/skyblocker/utils/tictactoe/TicTacToeUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/tictactoe/TicTacToeUtils.java @@ -1,105 +1,119 @@ package de.hysky.skyblocker.utils.tictactoe; +import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.Comparator; +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; public class TicTacToeUtils { - public static int getBestMove(char[][] board) { - HashMap<Integer, Integer> moves = new HashMap<>(); - for (int row = 0; row < board.length; row++) { - for (int col = 0; col < board[row].length; col++) { - if (board[row][col] != '\0') continue; - board[row][col] = 'O'; - int score = alphabeta(board, Integer.MIN_VALUE, Integer.MAX_VALUE, false, 0); - board[row][col] = '\0'; - moves.put(row * 3 + col + 1, score); - } - } - return Collections.max(moves.entrySet(), Map.Entry.comparingByValue()).getKey(); - } - - private static boolean hasMovesLeft(char[][] board) { - for (char[] rows : board) { - for (char col : rows) { - if (col == '\0') return true; - } - } - return false; - } - - private static int getBoardScore(char[][] board) { - for (int row = 0; row < 3; row++) { - if (board[row][0] == board[row][1] && board[row][0] == board[row][2]) { - if (board[row][0] == 'X') { - return -10; - } else if (board[row][0] == 'O') { - return 10; - } - } - } - - for (int col = 0; col < 3; col++) { - if (board[0][col] == board[1][col] && board[0][col] == board[2][col]) { - if (board[0][col] == 'X') { - return -10; - } else if (board[0][col] == 'O') { - return 10; - } - } - } - - if (board[0][0] == board[1][1] && board[0][0] == board[2][2]) { - if (board[0][0] == 'X') { - return -10; - } else if (board[0][0] == 'O') { - return 10; - } - } else if (board[0][2] == board[1][1] && board[0][2] == board[2][0]) { - if (board[0][2] == 'X') { - return -10; - } else if (board[0][2] == 'O') { - return 10; - } - } - - return 0; - } - - private static int alphabeta(char[][] board, int alpha, int beta, boolean max, int depth) { - int score = getBoardScore(board); - if (score == 10 || score == -10) return score; - if (!hasMovesLeft(board)) return 0; - - if (max) { - int bestScore = Integer.MIN_VALUE; - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - if (board[row][col] == '\0') { - board[row][col] = 'O'; - bestScore = Math.max(bestScore, alphabeta(board, alpha, beta, false, depth + 1)); - board[row][col] = '\0'; - alpha = Math.max(alpha, bestScore); - if (beta <= alpha) break; // Pruning - } - } - } - return bestScore - depth; - } else { - int bestScore = Integer.MAX_VALUE; - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - if (board[row][col] == '\0') { - board[row][col] = 'X'; - bestScore = Math.min(bestScore, alphabeta(board, alpha, beta, true, depth + 1)); - board[row][col] = '\0'; - beta = Math.min(beta, bestScore); - if (beta <= alpha) break; // Pruning - } - } - } - return bestScore + depth; - } - } + public static BoardIndex getBestMove(char[][] board) { + Object2IntOpenHashMap<BoardIndex> moves = new Object2IntOpenHashMap<>(); + + for (int row = 0; row < board.length; row++) { + for (int column = 0; column < board[row].length; column++) { + // Simulate the move as O if the square is empty to determine a solution + if (board[row][column] != '\0') continue; + board[row][column] = 'O'; + int score = alphabeta(board, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, false); + board[row][column] = '\0'; + + moves.put(new BoardIndex(row, column), score); + } + } + + return Collections.max(moves.object2IntEntrySet(), Comparator.comparingInt(Object2IntMap.Entry::getIntValue)).getKey(); + } + + private static boolean hasMovesAvailable(char[][] board) { + return Arrays.stream(board).flatMap(row -> Stream.of(row[0], row[1], row[2])).anyMatch(c -> c == '\0'); + } + + private static int getScore(char[][] board) { + // Check if X or O has won horizontally + for (int row = 0; row < 3; row++) { + if (board[row][0] == board[row][1] && board[row][0] == board[row][2]) { + switch (board[row][0]) { + case 'X': return -10; + case 'O': return 10; + } + } + } + + // Check if X or O has won vertically + for (int column = 0; column < 3; column++) { + if (board[0][column] == board[1][column] && board[0][column] == board[2][column]) { + switch (board[0][column]) { + case 'X': return -10; + case 'O': return 10; + } + } + } + + // Check if X or O has won diagonally + // Top left to bottom right + if (board[0][0] == board[1][1] && board[0][0] == board[2][2]) { + switch (board[0][0]) { + case 'X': return -10; + case 'O': return 10; + } + } + + // Top right to bottom left + if (board[0][2] == board[1][1] && board[0][2] == board[2][0]) { + switch (board[0][2]) { + case 'X': return -10; + case 'O': return 10; + } + } + + return 0; + } + + private static int alphabeta(char[][] board, int alpha, int beta, int depth, boolean maximizePlayer) { + int score = getScore(board); + + if (score == 10 || score == -10) return score; + if (!hasMovesAvailable(board)) return 0; + + if (maximizePlayer) { + int bestScore = Integer.MIN_VALUE; + + for (int row = 0; row < 3; row++) { + for (int column = 0; column < 3; column++) { + if (board[row][column] == '\0') { + board[row][column] = 'O'; + bestScore = Math.max(bestScore, alphabeta(board, alpha, beta, depth + 1, false)); + board[row][column] = '\0'; + alpha = Math.max(alpha, bestScore); + + //Is this correct? Well the algorithm seems to solve it so I will assume it is + if (beta <= alpha) break; // Pruning + } + } + } + + return bestScore - depth; + } else { + int bestScore = Integer.MAX_VALUE; + + for (int row = 0; row < 3; row++) { + for (int column = 0; column < 3; column++) { + if (board[row][column] == '\0') { + board[row][column] = 'X'; + bestScore = Math.min(bestScore, alphabeta(board, alpha, beta, depth + 1, true)); + board[row][column] = '\0'; + beta = Math.min(beta, bestScore); + + if (beta <= alpha) break; // Pruning + } + } + } + + return bestScore + depth; + } + } }
\ No newline at end of file diff --git a/src/main/resources/assets/skyblocker/lang/en_ca.json b/src/main/resources/assets/skyblocker/lang/en_ca.json index b7a6450f..5d8afbe9 100644 --- a/src/main/resources/assets/skyblocker/lang/en_ca.json +++ b/src/main/resources/assets/skyblocker/lang/en_ca.json @@ -41,5 +41,6 @@ "skyblocker.bars.config.defense": "Defence", "skyblocker.bars.config.mainColor": "Main Colour", "skyblocker.bars.config.overflowColor": "Overflow Colour", - "skyblocker.bars.config.textColor": "Text Colour" + "skyblocker.bars.config.textColor": "Text Colour", + "skyblocker.debug.toggledShowingInvisibleArmorStands": "Toggled showing invisible armour stands to %s" } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 96d3d6d8..53b66257 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -195,6 +195,7 @@ "text.autoconfig.skyblocker.option.quickNav.button.item.itemName": "Item ID", "text.autoconfig.skyblocker.option.quickNav.button.item.count": "Item Count", "text.autoconfig.skyblocker.option.quickNav.button.item.nbt": "NBT", + "text.autoconfig.skyblocker.option.quickNav.button.item.nbt.@Tooltip": "§c§lWARNING: THIS MUST BE CONFIGURED WITH ITEM NBT NOT ITEM COMPONENTS! \n\n§fIn the future we will automatically migrate your config to use item components!", "text.autoconfig.skyblocker.option.quickNav.button.uiTitle": "UI Title", "text.autoconfig.skyblocker.option.quickNav.button.clickEvent": "Click event", @@ -490,6 +491,8 @@ "text.autoconfig.skyblocker.option.general.dontStripSkinAlphaValues": "Correct Transparent Skin Pixels", "text.autoconfig.skyblocker.option.general.dontStripSkinAlphaValues.@Tooltip": "When enabled, the alpha values of pixels in skin textures are no longer stripped while in Skyblock.\n\nThis results in the \"filler\" pixels on items using Player Heads to now be completely transparent, although this may have some side effects in odd cases.", + "skyblocker.debug.toggledShowingInvisibleArmorStands": "Toggled showing invisible armor stands to %s", + "skyblocker.bars.config.health": "Health", "skyblocker.bars.config.defense": "Defense", "skyblocker.bars.config.intelligence": "Intelligence", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index dd6c2cd4..645eda34 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -33,13 +33,14 @@ ], "accessWidener": "skyblocker.accesswidener", "depends": { - "fabricloader": ">=0.15.0", - "fabric-api": ">=0.92.0+1.20.4", - "yet_another_config_lib_v3": ">=3.3.2+1.20.4", - "minecraft": "~1.20.3" + "fabricloader": ">=0.15.10", + "fabric-api": ">=0.97.8+1.20.6", + "yet_another_config_lib_v3": ">=3.4.1+1.20.5", + "minecraft": "~1.20.5", + "java": ">=21" }, "conflicts": { - "immediatelyfast": "<=1.2.11+1.20.4" + "immediatelyfast": "<=1.2.12+1.20.5" }, "breaks": { "forcecloseworldloadingscreen": "<=2.2.0" diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index 8169c0c4..0032a557 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -1,18 +1,18 @@ { "required": true, - "package": "de.hysky.skyblocker.mixin", + "package": "de.hysky.skyblocker.mixins", "plugin": "de.hysky.skyblocker.compatibility.MixinPlugin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_21", "client": [ "AbstractInventoryScreenMixin", - "ArmorTrimMixin", "BatEntityMixin", "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerMixin", "CommandTreeS2CPacketMixin", + "ComponentHolderMixin", "DataTrackerMixin", "DrawContextMixin", - "DyeableItemMixin", + "DyedColorComponentMixin", "EntityRenderDispatcherMixin", "FarmlandBlockMixin", "GenericContainerScreenHandlerMixin", @@ -21,7 +21,6 @@ "InGameHudMixin", "InGameOverlayRendererMixin", "InventoryScreenMixin", - "ItemMixin", "ItemStackMixin", "LeverBlockMixin", "LivingEntityRendererMixin", @@ -38,19 +37,18 @@ "WorldRendererMixin", "YggdrasilMinecraftSessionServiceMixin", "YggdrasilServicesKeyInfoMixin", - "accessor.BeaconBlockEntityRendererInvoker", - "accessor.DrawContextInvoker", - "accessor.EndermanEntityAccessor", - "accessor.FrustumInvoker", - "accessor.HandledScreenAccessor", - "accessor.ItemStackAccessor", - "accessor.MessageHandlerAccessor", - "accessor.PlayerListHudAccessor", - "accessor.RecipeBookWidgetAccessor", - "accessor.ScreenAccessor", - "accessor.SkullBlockEntityAccessor", - "accessor.SlotAccessor", - "accessor.WorldRendererAccessor", + "accessors.BeaconBlockEntityRendererInvoker", + "accessors.DrawContextInvoker", + "accessors.EndermanEntityAccessor", + "accessors.FrustumInvoker", + "accessors.HandledScreenAccessor", + "accessors.MessageHandlerAccessor", + "accessors.PlayerListHudAccessor", + "accessors.RecipeBookWidgetAccessor", + "accessors.ScreenAccessor", + "accessors.SkullBlockEntityAccessor", + "accessors.SlotAccessor", + "accessors.WorldRendererAccessor", "discordipc.ConnectionMixin" ], "injectors": { diff --git a/src/test/java/de/hysky/skyblocker/skyblock/StatusBarTrackerTest.java b/src/test/java/de/hysky/skyblocker/skyblock/StatusBarTrackerTest.java index c058da5d..9ab4e927 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/StatusBarTrackerTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/StatusBarTrackerTest.java @@ -15,13 +15,12 @@ class StatusBarTrackerTest { void assertStats(int hp, int maxHp, int def, int mana, int maxMana, int overflowMana) { int absorption = 0; - if(hp > maxHp) { - absorption = hp - maxHp; - hp -= absorption; - if(absorption > maxHp) - absorption = maxHp; + if (hp > maxHp) { + absorption = Math.min(hp - maxHp, maxHp); + hp = maxHp; } assertEquals(new StatusBarTracker.Resource(hp, maxHp, absorption), tracker.getHealth()); + assertEquals(def, tracker.getDefense()); assertEquals(new StatusBarTracker.Resource(mana, maxMana, overflowMana), tracker.getMana()); } diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdosTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdosTest.java index 22683698..38e795c3 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdosTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdosTest.java @@ -10,10 +10,10 @@ class ThreeWeirdosTest extends ChatPatternListenerTest<ThreeWeirdos> { @Test void test1() { - assertGroup("§e[NPC] §cBaxter§f: My chest doesn't have the reward. We are all telling the truth.", 1, "Baxter"); + assertGroup("[NPC] Baxter: My chest doesn't have the reward. We are all telling the truth.", 1, "Baxter"); } @Test void test2() { - assertGroup("§e[NPC] §cHope§f: The reward isn't in any of our chests.", 1, "Hope"); + assertGroup("[NPC] Hope: The reward isn't in any of our chests.", 1, "Hope"); } }
\ No newline at end of file diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TriviaTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TriviaTest.java index 55a59a68..52a7ad8c 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TriviaTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TriviaTest.java @@ -20,14 +20,14 @@ class TriviaTest extends ChatPatternListenerTest<Trivia> { @Test void answer1() { - assertGroup(" §6 ⓐ §aAnswer 1", 3, "Answer 1"); + assertGroup(" ⓐ Answer 1", 3, "Answer 1"); } @Test void answer2() { - assertGroup(" §6 ⓑ §aAnswer 2", 3, "Answer 2"); + assertGroup(" ⓑ Answer 2", 3, "Answer 2"); } @Test void answer3() { - assertGroup(" §6 ⓒ §aAnswer 3", 3, "Answer 3"); + assertGroup(" ⓒ Answer 3", 3, "Answer 3"); } }
\ No newline at end of file diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java index 12bfe98b..ef2a9e1b 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java @@ -25,7 +25,7 @@ public class SecretWaypointTest { @Test void testCodecSerialize() { SecretWaypoint waypoint = new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", new BlockPos(-1, 0, 1)); - JsonElement json = SecretWaypoint.CODEC.encodeStart(JsonOps.INSTANCE, waypoint).result().orElseThrow(); + JsonElement json = SecretWaypoint.CODEC.encodeStart(JsonOps.INSTANCE, waypoint).getOrThrow(); String expectedJson = "{\"secretIndex\":0,\"category\":\"default\",\"name\":\"name\",\"pos\":[-1,0,1]}"; Assertions.assertEquals(expectedJson, json.toString()); @@ -34,7 +34,7 @@ public class SecretWaypointTest { @Test void testCodecDeserialize() { String json = "{\"secretIndex\":0,\"category\":\"default\",\"name\":\"name\",\"pos\":[-1,0,1]}"; - SecretWaypoint waypoint = SecretWaypoint.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + SecretWaypoint waypoint = SecretWaypoint.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).getOrThrow(); SecretWaypoint expectedWaypoint = new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", new BlockPos(-1, 0, 1)); Assertions.assertEquals(expectedWaypoint, waypoint); @@ -43,7 +43,7 @@ public class SecretWaypointTest { @Test void testListCodecSerialize() { List<SecretWaypoint> waypoints = List.of(new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", new BlockPos(-1, 0, 1)), new SecretWaypoint(1, SecretWaypoint.Category.CHEST, "name", new BlockPos(2, 0, -2))); - JsonElement json = SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, waypoints).result().orElseThrow(); + JsonElement json = SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, waypoints).getOrThrow(); String expectedJson = "[{\"secretIndex\":0,\"category\":\"default\",\"name\":\"name\",\"pos\":[-1,0,1]},{\"secretIndex\":1,\"category\":\"chest\",\"name\":\"name\",\"pos\":[2,0,-2]}]"; Assertions.assertEquals(expectedJson, json.toString()); @@ -52,7 +52,7 @@ public class SecretWaypointTest { @Test void testListCodecDeserialize() { String json = "[{\"secretIndex\":0,\"category\":\"default\",\"name\":\"name\",\"pos\":[-1,0,1]},{\"secretIndex\":1,\"category\":\"chest\",\"name\":\"name\",\"pos\":[2,0,-2]}]"; - List<SecretWaypoint> waypoints = SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + List<SecretWaypoint> waypoints = SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).getOrThrow(); List<SecretWaypoint> expectedWaypoints = List.of(new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", new BlockPos(-1, 0, 1)), new SecretWaypoint(1, SecretWaypoint.Category.CHEST, "name", new BlockPos(2, 0, -2))); Assertions.assertEquals(expectedWaypoints.size(), waypoints.size()); diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/FetchurTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/FetchurTest.java index 08282972..12a194ee 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/FetchurTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/FetchurTest.java @@ -10,6 +10,6 @@ class FetchurTest extends ChatPatternListenerTest<Fetchur> { @Test public void patternCaptures() { - assertGroup("§e[NPC] Fetchur§f: its a hint", 1, "a hint"); + assertGroup("[NPC] Fetchur: its a hint", 1, "a hint"); } } diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/PuzzlerTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/PuzzlerTest.java index 9437a5c9..c32010cf 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/PuzzlerTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/PuzzlerTest.java @@ -10,6 +10,6 @@ class PuzzlerTest extends ChatPatternListenerTest<Puzzler> { @Test void puzzler() { - assertGroup("§e[NPC] §dPuzzler§f: §b◀§d▲§b◀§d▲§d▲§5▶§5▶§b◀§d▲§a▼", 1, "§b◀§d▲§b◀§d▲§d▲§5▶§5▶§b◀§d▲§a▼"); + assertGroup("[NPC] Puzzler: ◀▲◀▲▲▶▶◀▲▼", 1, "◀▲◀▲▲▶▶◀▲▼"); } }
\ No newline at end of file diff --git a/src/test/java/de/hysky/skyblocker/skyblock/filters/AdFilterTest.java b/src/test/java/de/hysky/skyblocker/skyblock/filters/AdFilterTest.java index 3eec1cd9..9f788cac 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/filters/AdFilterTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/filters/AdFilterTest.java @@ -15,47 +15,47 @@ class AdFilterTest extends ChatPatternListenerTest<AdFilter> { @Test void noRank() { - assertMatches("§8[§a86§8] §7Advertiser§7: advertisement"); + assertMatches("[86] Advertiser: advertisement"); } @Test void vip() { - assertMatches("§8[§b280§8] §a[VIP] Advertiser§f: advertisement"); + assertMatches("[280] [VIP] Advertiser: advertisement"); } @Test void mvp() { - assertMatches("§8[§d256§8] §6§l⚡ §b[MVP§c+§b] Advertiser§f: advertisement"); + assertMatches("[256] ⚡ [MVP+] Advertiser: advertisement"); } @Test void plusPlus() { - assertMatches("§8[§6222§8] §6[MVP§c++§6] Advertiser§f: advertisement"); + assertMatches("[222] [MVP++] Advertiser: advertisement"); } @Test void capturesMessage() { - assertGroup("§8[§c325§8] §b[MVP§c+§b] b2dderr§f: buying prismapump", 2, "buying prismapump"); + assertGroup("[325] [MVP+] b2dderr: buying prismapump", 2, "buying prismapump"); } @Test void simpleAd() { - assertFilters("§8[§e320§8] §b[MVP§c+§b] b2dderr§f: buying prismapump"); + assertFilters("[320] [MVP+] b2dderr: buying prismapump"); } @Test void uppercaseAd() { - assertFilters("§8[§f70§8] §a[VIP] Tecnoisnoob§f: SELLING REJUVENATE 5 Book on ah!"); + assertFilters("[70] [VIP] Tecnoisnoob: SELLING REJUVENATE 5 Book on ah!"); } @Test void characterSpam() { - assertFilters("§8[§9144§8] §a[VIP] Benyyy_§f: Hey, Visit my Island, i spent lots of time to build it! I also made donate room! <<<<<<<<<<<<<<<<<<<"); + assertFilters("[144] [VIP] Benyyy_: Hey, Visit my Island, i spent lots of time to build it! I also made donate room! <<<<<<<<<<<<<<<<<<<"); } @Test void notAd() { - Matcher matcher = listener.pattern.matcher("§8[§6200§8] §a[VIP] NotMatching§f: This message shouldn't match!"); + Matcher matcher = listener.pattern.matcher("[200] [VIP] NotMatching: This message shouldn't match!"); assertTrue(matcher.matches()); assertFalse(listener.onMatch(null, matcher)); } diff --git a/src/test/java/de/hysky/skyblocker/skyblock/filters/AutopetFilterTest.java b/src/test/java/de/hysky/skyblocker/skyblock/filters/AutopetFilterTest.java index 846acbb8..0e578082 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/filters/AutopetFilterTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/filters/AutopetFilterTest.java @@ -10,6 +10,6 @@ class AutopetFilterTest extends ChatPatternListenerTest<AutopetFilter> { @Test void testAutopet() { - assertMatches("§cAutopet §eequipped your §7[Lvl 85] §6Tiger§e! §a§lVIEW RULE"); + assertMatches("Autopet equipped your [Lvl 85] Tiger! VIEW RULE"); } }
\ No newline at end of file diff --git a/src/test/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilterTest.java b/src/test/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilterTest.java new file mode 100644 index 00000000..d510274c --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/skyblock/filters/ShowOffFilterTest.java @@ -0,0 +1,47 @@ +package de.hysky.skyblocker.skyblock.filters; + +import org.junit.jupiter.api.Test; + +import de.hysky.skyblocker.utils.chat.ChatPatternListenerTest; + +public class ShowOffFilterTest extends ChatPatternListenerTest<ShowOffFilter> { + + public ShowOffFilterTest() { + super(new ShowOffFilter()); + } + + @Test + void holding() { + assertMatches("[290] ⚡ [MVP+] Player is holding [Withered Dark Claymore ✪✪✪✪✪➎]"); + } + + @Test + void wearing() { + assertMatches("[290] ⚡ [MVP+] Player is wearing [Ancient Storm's Chestplate ✪✪✪✪✪➎]"); + } + + @Test + void isFriendsWith() { + assertMatches("[290] [MVP+] Player is friends with a [[Lvl 200] Golden Dragon]"); + } + + @Test + void has() { + assertMatches("[290] ⚡ [MVP+] Player has [Withered Hyperion ✪✪✪✪✪]"); + } + + @Test + void noLevelOrEmblem() { + assertMatches("[MVP+] Player is holding [Mithril Drill SX-R226]"); + } + + @Test + void noRank() { + assertMatches("[290] ⚡ Player is holding [Oak Leaves]"); + } + + @Test + void noLevelOrEmblemOrRank() { + assertMatches("Player is holding [Nether Star]"); + } +} diff --git a/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java b/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java index 2709aba4..5c52c3ad 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java @@ -15,7 +15,7 @@ public class ArmorTrimIdSerializationTest { @Test void serialize() { ArmorTrimId armorTrimId = new ArmorTrimId(new Identifier("material_id"), new Identifier("pattern_id")); - JsonElement json = ArmorTrimId.CODEC.encodeStart(JsonOps.INSTANCE, armorTrimId).result().orElseThrow(); + JsonElement json = ArmorTrimId.CODEC.encodeStart(JsonOps.INSTANCE, armorTrimId).getOrThrow(); String expectedJson = "{\"material\":\"minecraft:material_id\",\"pattern\":\"minecraft:pattern_id\"}"; Assertions.assertEquals(expectedJson, json.toString()); @@ -24,7 +24,7 @@ public class ArmorTrimIdSerializationTest { @Test void deserialize() { String json = "{\"material\":\"minecraft:material_id\",\"pattern\":\"minecraft:pattern_id\"}"; - ArmorTrimId armorTrimId = ArmorTrimId.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + ArmorTrimId armorTrimId = ArmorTrimId.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).getOrThrow(); ArmorTrimId expectedArmorTrimId = new ArmorTrimId(new Identifier("material_id"), new Identifier("pattern_id")); Assertions.assertEquals(expectedArmorTrimId, armorTrimId); diff --git a/src/test/java/de/hysky/skyblocker/utils/ItemUtilsTest.java b/src/test/java/de/hysky/skyblocker/utils/ItemUtilsTest.java index 71ff29ef..0f9f0e56 100644 --- a/src/test/java/de/hysky/skyblocker/utils/ItemUtilsTest.java +++ b/src/test/java/de/hysky/skyblocker/utils/ItemUtilsTest.java @@ -1,64 +1,64 @@ package de.hysky.skyblocker.utils; -import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; import it.unimi.dsi.fastutil.ints.IntIntPair; import net.minecraft.Bootstrap; import net.minecraft.SharedConstants; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.StringNbtReader; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -public class ItemUtilsTest { - private final ItemStack JUJU_SHORTBOW_OLD = ItemStack.fromNbt(StringNbtReader.parse("{Count:1b,id:\"minecraft:bow\",tag:{Damage:0,Enchantments:[{id:\"minecraft:protection\",lvl:0s}],ExtraAttributes:{art_of_war_count:1,dungeon_item_level:5,enchantments:{aiming:5,chance:4,cubism:5,impaling:3,infinite_quiver:10,overload:5,piercing:1,power:6,snipe:3,telekinesis:1,ultimate_soul_eater:5},hot_potato_count:15,id:\"JUJU_SHORTBOW\",modifier:\"spiritual\",originTag:\"QUICK_CRAFTING\",rarity_upgrades:1,runes:{DRAGON:3},stats_book:54778,timestamp:\"6/5/21 4:41 AM\",uuid:\"b06b8fe2-470a-43f3-b844-658472f20996\"},HideFlags:255,Unbreakable:1b,display:{Lore:['{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Gear Score: \"},{\"color\":\"light_purple\",\"text\":\"724 \"},{\"color\":\"dark_gray\",\"text\":\"(2297)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Damage: \"},{\"color\":\"red\",\"text\":\"+371 \"},{\"color\":\"yellow\",\"text\":\"(+30) \"},{\"color\":\"dark_gray\",\"text\":\"(+1,275)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Strength: \"},{\"color\":\"red\",\"text\":\"+107 \"},{\"color\":\"yellow\",\"text\":\"(+30) \"},{\"color\":\"gold\",\"text\":\"[+5] \"},{\"color\":\"blue\",\"text\":\"(+28) \"},{\"color\":\"dark_gray\",\"text\":\"(+386.25)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Crit Chance: \"},{\"color\":\"red\",\"text\":\"+28% \"},{\"color\":\"blue\",\"text\":\"(+12%) \"},{\"color\":\"dark_gray\",\"text\":\"(+40.5%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Crit Damage: \"},{\"color\":\"red\",\"text\":\"+181% \"},{\"color\":\"blue\",\"text\":\"(+55%) \"},{\"color\":\"dark_gray\",\"text\":\"(+637.5%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Shot Cooldown: \"},{\"color\":\"green\",\"text\":\"0.5s\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"color\":\"light_purple\",\"text\":\"\"},{\"bold\":true,\"color\":\"light_purple\",\"text\":\"Soul Eater V\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Chance IV\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Cubism V\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Dragon Tracer V\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Impaling III\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Infinite Quiver X\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Overload V\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Piercing I\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Power VI\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Snipe III\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_purple\",\"text\":\"◆ End Rune III\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Hits \"},{\"color\":\"red\",\"text\":\"3 \"},{\"color\":\"gray\",\"text\":\"mobs on impact.\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Can damage endermen.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"white\",\"text\":\"Kills: \"},{\"color\":\"gold\",\"text\":\"54,778\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Spiritual Bonus\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Grants a \"},{\"color\":\"green\",\"text\":\"10% \"},{\"color\":\"gray\",\"text\":\"chance to spawn\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"a Spirit Decoy when you kill an\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"enemy in a dungeon.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gold\",\"text\":\"Shortbow: Instantly shoots!\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"\"},{\"color\":\"dark_red\",\"text\":\"☠ \"},{\"color\":\"red\",\"text\":\"Requires \"},{\"color\":\"dark_purple\",\"text\":\"Enderman Slayer\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_purple\",\"text\":\"5\"},{\"color\":\"red\",\"text\":\".\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"obfuscated\":true,\"color\":\"gold\",\"text\":\"a\"},{\"text\":\"\"},{\"bold\":false,\"italic\":false,\"underlined\":false,\"obfuscated\":false,\"strikethrough\":false,\"extra\":[{\"text\":\" \"}],\"text\":\"\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"LEGENDARY DUNGEON BOW \"},{\"bold\":true,\"obfuscated\":true,\"color\":\"gold\",\"text\":\"a\"}],\"text\":\"\"}'],Name:'{\"italic\":false,\"extra\":[{\"color\":\"gold\",\"text\":\"Spiritual Juju Shortbow \"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"}],\"text\":\"\"}'}}}")); - private final ItemStack JUJU_SHORTBOW = ItemStack.fromNbt(StringNbtReader.parse("{Count:1b,id:\"minecraft:bow\",tag:{Damage:0,Enchantments:[{id:\"minecraft:protection\",lvl:0s}],ExtraAttributes:{art_of_war_count:1,dungeon_item_level:5,enchantments:{aiming:5,chance:4,cubism:5,impaling:3,infinite_quiver:10,overload:5,piercing:1,power:6,snipe:3,telekinesis:1,ultimate_soul_eater:5},hot_potato_count:15,id:\"JUJU_SHORTBOW\",modifier:\"spiritual\",originTag:\"QUICK_CRAFTING\",rarity_upgrades:1,runes:{DRAGON:3},stats_book:54778,timestamp:1622882460000L,uuid:\"b06b8fe2-470a-43f3-b844-658472f20996\"},HideFlags:255,Unbreakable:1b,display:{Lore:['{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Gear Score: \"},{\"color\":\"light_purple\",\"text\":\"724 \"},{\"color\":\"dark_gray\",\"text\":\"(2297)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Damage: \"},{\"color\":\"red\",\"text\":\"+371 \"},{\"color\":\"yellow\",\"text\":\"(+30) \"},{\"color\":\"dark_gray\",\"text\":\"(+1,275)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Strength: \"},{\"color\":\"red\",\"text\":\"+107 \"},{\"color\":\"yellow\",\"text\":\"(+30) \"},{\"color\":\"gold\",\"text\":\"[+5] \"},{\"color\":\"blue\",\"text\":\"(+28) \"},{\"color\":\"dark_gray\",\"text\":\"(+386.25)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Crit Chance: \"},{\"color\":\"red\",\"text\":\"+28% \"},{\"color\":\"blue\",\"text\":\"(+12%) \"},{\"color\":\"dark_gray\",\"text\":\"(+40.5%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Crit Damage: \"},{\"color\":\"red\",\"text\":\"+181% \"},{\"color\":\"blue\",\"text\":\"(+55%) \"},{\"color\":\"dark_gray\",\"text\":\"(+637.5%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Shot Cooldown: \"},{\"color\":\"green\",\"text\":\"0.5s\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"color\":\"light_purple\",\"text\":\"\"},{\"bold\":true,\"color\":\"light_purple\",\"text\":\"Soul Eater V\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Chance IV\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Cubism V\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Dragon Tracer V\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Impaling III\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Infinite Quiver X\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Overload V\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Piercing I\"},{\"color\":\"blue\",\"text\":\", \"},{\"color\":\"blue\",\"text\":\"Power VI\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Snipe III\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_purple\",\"text\":\"◆ End Rune III\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Hits \"},{\"color\":\"red\",\"text\":\"3 \"},{\"color\":\"gray\",\"text\":\"mobs on impact.\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Can damage endermen.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gold\",\"text\":\"Shortbow: Instantly shoots!\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"white\",\"text\":\"Kills: \"},{\"color\":\"gold\",\"text\":\"54,778\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Spiritual Bonus\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Grants a \"},{\"color\":\"green\",\"text\":\"10% \"},{\"color\":\"gray\",\"text\":\"chance to spawn a\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Spirit Decoy when you kill an enemy\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"in a dungeon.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"\"},{\"color\":\"dark_red\",\"text\":\"☠ \"},{\"color\":\"red\",\"text\":\"Requires \"},{\"color\":\"dark_purple\",\"text\":\"Enderman Slayer 5\"},{\"color\":\"red\",\"text\":\".\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"obfuscated\":true,\"color\":\"gold\",\"text\":\"a\"},{\"text\":\"\"},{\"bold\":false,\"italic\":false,\"underlined\":false,\"obfuscated\":false,\"strikethrough\":false,\"extra\":[{\"text\":\" \"}],\"text\":\"\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"LEGENDARY DUNGEON BOW \"},{\"bold\":true,\"obfuscated\":true,\"color\":\"gold\",\"text\":\"a\"}],\"text\":\"\"}'],Name:'{\"italic\":false,\"extra\":[{\"color\":\"gold\",\"text\":\"Spiritual Juju Shortbow \"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"}],\"text\":\"\"}'}}}")); - private final ItemStack LIVID_DAGGER = ItemStack.fromNbt(StringNbtReader.parse("{Count:1b,id:\"minecraft:iron_sword\",tag:{Damage:0,Enchantments:[{id:\"minecraft:protection\",lvl:0s}],ExtraAttributes:{dungeon_item_level:5,enchantments:{telekinesis:1,ultimate_one_for_all:1},gems:{JASPER_0:\"FLAWLESS\"},hot_potato_count:15,id:\"LIVID_DAGGER\",modifier:\"fabled\",originTag:\"UNKNOWN\",rarity_upgrades:1,timestamp:\"2/20/21 3:09 PM\",uuid:\"214333db-d71c-4080-8487-00b4666bb9a4\"},HideFlags:255,Unbreakable:1b,display:{Lore:['{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Gear Score: \"},{\"color\":\"light_purple\",\"text\":\"933 \"},{\"color\":\"dark_gray\",\"text\":\"(2389)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Damage: \"},{\"color\":\"red\",\"text\":\"+261 \"},{\"color\":\"yellow\",\"text\":\"(+30) \"},{\"color\":\"dark_gray\",\"text\":\"(+900)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Strength: \"},{\"color\":\"red\",\"text\":\"+183 \"},{\"color\":\"yellow\",\"text\":\"(+30) \"},{\"color\":\"blue\",\"text\":\"(+75) \"},{\"color\":\"light_purple\",\"text\":\"(+12) \"},{\"color\":\"dark_gray\",\"text\":\"(+663.75)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Crit Chance: \"},{\"color\":\"red\",\"text\":\"+100% \"},{\"color\":\"dark_gray\",\"text\":\"(+150%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Crit Damage: \"},{\"color\":\"red\",\"text\":\"+105% \"},{\"color\":\"blue\",\"text\":\"(+50%) \"},{\"color\":\"dark_gray\",\"text\":\"(+375%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Bonus Attack Speed: \"},{\"color\":\"red\",\"text\":\"+55% \"},{\"color\":\"dark_gray\",\"text\":\"(+75%)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"text\":\" \"},{\"color\":\"dark_purple\",\"text\":\"[\"},{\"color\":\"light_purple\",\"text\":\"❁\"},{\"color\":\"dark_purple\",\"text\":\"]\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"color\":\"light_purple\",\"text\":\"\"},{\"bold\":true,\"color\":\"light_purple\",\"text\":\"One For All I\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gold\",\"text\":\"Ability: Throw \"},{\"bold\":true,\"color\":\"yellow\",\"text\":\"RIGHT CLICK\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Throw your dagger at your\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"enemies!\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_gray\",\"text\":\"Mana Cost: \"},{\"color\":\"dark_aqua\",\"text\":\"150\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_gray\",\"text\":\"Cooldown: \"},{\"color\":\"green\",\"text\":\"5s\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Your Critical Hits deal \"},{\"color\":\"blue\",\"text\":\"100%\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"\"},{\"color\":\"gray\",\"text\":\"more damage if you are behind\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"your target.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Fabled Bonus\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Critical hits have a chance to\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"deal up to \"},{\"color\":\"green\",\"text\":\"15% \"},{\"color\":\"gray\",\"text\":\"extra damage.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"obfuscated\":true,\"color\":\"light_purple\",\"text\":\"a\"},{\"text\":\"\"},{\"bold\":false,\"italic\":false,\"underlined\":false,\"obfuscated\":false,\"strikethrough\":false,\"extra\":[{\"text\":\" \"}],\"text\":\"\"},{\"bold\":true,\"color\":\"light_purple\",\"text\":\"\"},{\"bold\":true,\"color\":\"light_purple\",\"text\":\"MYTHIC DUNGEON SWORD \"},{\"bold\":true,\"obfuscated\":true,\"color\":\"light_purple\",\"text\":\"a\"}],\"text\":\"\"}'],Name:'{\"italic\":false,\"extra\":[{\"color\":\"light_purple\",\"text\":\"Fabled Livid Dagger \"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"},{\"color\":\"gold\",\"text\":\"✪\"}],\"text\":\"\"}'}}}")); - private final ItemStack MITHRIL_DRILL_1 = ItemStack.fromNbt(StringNbtReader.parse("{Count:1b,id:\"minecraft:prismarine_shard\",tag:{Damage:21,Enchantments:[{id:\"minecraft:protection\",lvl:0s}],ExtraAttributes:{compact_blocks:97683,drill_fuel:2979,enchantments:{compact:7,efficiency:5,experience:3,fortune:3,telekinesis:1},id:\"MITHRIL_DRILL_1\",modifier:\"fleet\",originTag:\"UNKNOWN\",timestamp:\"1/30/21 5:52 AM\",uuid:\"575ce2c9-251e-4435-9020-de1a2e24b1d0\"},HideFlags:255,display:{Lore:['{\"italic\":false,\"extra\":[{\"color\":\"dark_gray\",\"text\":\"Breaking Power 5\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Damage: \"},{\"color\":\"red\",\"text\":\"+65\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Mining Speed: \"},{\"color\":\"green\",\"text\":\"+585 \"},{\"color\":\"blue\",\"text\":\"(+25)\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Mining Fortune: \"},{\"color\":\"green\",\"text\":\"+30\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Mining Wisdom: \"},{\"color\":\"green\",\"text\":\"+7\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Compact VII \"},{\"color\":\"dark_gray\",\"text\":\"97,683\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Gain \"},{\"color\":\"dark_aqua\",\"text\":\"+7☯ Mining Wisdom \"},{\"color\":\"gray\",\"text\":\"and a \"},{\"color\":\"green\",\"text\":\"0.4%\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"green\",\"text\":\"\"},{\"color\":\"gray\",\"text\":\"chance to drop an enchanted item.\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_gray\",\"text\":\"150k blocks to tier up!\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Efficiency V\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Grants \"},{\"color\":\"green\",\"text\":\"+110 \"},{\"color\":\"gold\",\"text\":\"⸕ Mining Speed\"},{\"color\":\"gray\",\"text\":\".\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Experience III\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Grants a \"},{\"color\":\"green\",\"text\":\"37.5% \"},{\"color\":\"gray\",\"text\":\"chance for mobs and\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"ores to drop double experience.\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Fortune III\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Grants \"},{\"color\":\"gold\",\"text\":\"+30☘ Mining Fortune\"},{\"color\":\"gray\",\"text\":\", which\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"increases your chance for multiple\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"drops.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Gain \"},{\"color\":\"green\",\"text\":\"+15% \"},{\"color\":\"dark_green\",\"text\":\"Mithril Powder\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"when using this Drill!\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Fuel Tank: \"},{\"color\":\"red\",\"text\":\"Not Installed\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"\"},{\"color\":\"gray\",\"text\":\"Increases fuel capacity with part\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"installed.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Drill Engine: \"},{\"color\":\"red\",\"text\":\"Not Installed\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"\"},{\"color\":\"gray\",\"text\":\"Increases \"},{\"color\":\"gold\",\"text\":\"⸕ Mining Speed \"},{\"color\":\"gray\",\"text\":\"with part\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"installed.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Upgrade Module: \"},{\"color\":\"red\",\"text\":\"Not Installed\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"\"},{\"color\":\"gray\",\"text\":\"Applies a passive upgrade with part\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"installed.\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Apply Drill Parts to this Drill by\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"talking to a \"},{\"color\":\"dark_green\",\"text\":\"Drill Mechanic\"},{\"color\":\"gray\",\"text\":\"!\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Fuel: \"},{\"color\":\"dark_green\",\"text\":\"2,979\"},{\"color\":\"dark_gray\",\"text\":\"/3k\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gold\",\"text\":\"Ability: Mining Speed Boost \"},{\"bold\":true,\"color\":\"yellow\",\"text\":\"RIGHT CLICK\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"Grants \"},{\"color\":\"green\",\"text\":\"+\"},{\"color\":\"green\",\"text\":\"200% \"},{\"color\":\"gold\",\"text\":\"⸕ Mining Speed \"},{\"color\":\"gray\",\"text\":\"for\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"gray\",\"text\":\"\"},{\"color\":\"green\",\"text\":\"15s\"},{\"color\":\"gray\",\"text\":\".\"}],\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"color\":\"dark_gray\",\"text\":\"Cooldown: \"},{\"color\":\"green\",\"text\":\"120s\"}],\"text\":\"\"}','{\"italic\":false,\"text\":\"\"}','{\"italic\":false,\"extra\":[{\"bold\":true,\"color\":\"blue\",\"text\":\"RARE DRILL\"}],\"text\":\"\"}'],Name:'{\"italic\":false,\"extra\":[{\"color\":\"blue\",\"text\":\"Fleet Mithril Drill SX-R226\"}],\"text\":\"\"}'}}}")); +import java.util.TimeZone; - public ItemUtilsTest() throws CommandSyntaxException { - } +public class ItemUtilsTest { + private final ItemStack DARK_CLAYMORE = ItemStack.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString("{\"id\":\"minecraft:stone_sword\",\"count\":1,\"components\":{\"minecraft:attribute_modifiers\":{\"modifiers\":[],\"show_in_tooltip\":false},\"minecraft:unbreakable\":{\"show_in_tooltip\":false},\"minecraft:lore\":[\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Gear Score: \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"1561 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(5000)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+580 \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+3,339)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Strength: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+517 \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[+5] \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+220) \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+32) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+3,194.1)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Crit Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+133% \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+819%)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Bonus Attack Speed: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+50% \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+77.5%)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Magic Find: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+30 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+46.5)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Ferocity: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+5 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+7.75)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Swing Range: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+2 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+2.1)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[\\\" \\\",{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"❁\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"] \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"❁\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"]\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Chimera V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Champion X\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Cleave VI\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Critical VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Cubism VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Divine Gift III\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Dragon Hunter V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Ender Slayer VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Experience V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Fire Aspect III\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"First Strike V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Impaling III\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Lethality VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Looting V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Luck VII\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Prosecute VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Scavenger V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Sharpness VII\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Smoldering V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Syphon V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Tabasco III\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Thunderlord VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Titan Killer VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Vampirism VI\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Venomous VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Vicious V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"gray\\\",\\\"italic\\\":true,\\\"text\\\":\\\"That thing was too big to be called a\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"italic\\\":true,\\\"text\\\":\\\"sword, it was more like a large hunk\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"italic\\\":true,\\\"text\\\":\\\"of stone.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Withered Bonus\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Grants \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+1 \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"❁ Strength \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"per\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"Catacombs \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"level.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"},\\\"\\\",{\\\"bold\\\":false,\\\"extra\\\":[\\\" \\\"],\\\"italic\\\":false,\\\"obfuscated\\\":false,\\\"strikethrough\\\":false,\\\"text\\\":\\\"\\\",\\\"underlined\\\":false},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"MYTHIC DUNGEON LONGSWORD \\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\"],\"minecraft:enchantment_glint_override\":true,\"minecraft:custom_name\":\"{\\\"extra\\\":[{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Withered Dark Claymore \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"➎\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"minecraft:custom_data\":{\"rarity_upgrades\":1,\"hot_potato_count\":15,\"gems\":{\"JASPER_0\":{\"uuid\":\"e9881031-1b36-4c41-8d13-739685b700aa\",\"quality\":\"PERFECT\"},\"JASPER_1\":{\"uuid\":\"afb95bac-0269-4978-a3ed-f5a3e4e57338\",\"quality\":\"PERFECT\"},\"unlocked_slots\":[\"JASPER_0\",\"JASPER_1\"]},\"champion_combat_xp\":4.8087379696333125E7,\"modifier\":\"withered\",\"art_of_war_count\":1,\"upgrade_level\":10,\"id\":\"DARK_CLAYMORE\",\"enchantments\":{\"impaling\":3,\"luck\":7,\"critical\":7,\"scavenger\":5,\"ender_slayer\":7,\"fire_aspect\":3,\"experience\":5,\"divine_gift\":3,\"venomous\":6,\"dragon_hunter\":5,\"tabasco\":3,\"thunderlord\":7,\"sharpness\":7,\"cubism\":6,\"titan_killer\":7,\"lethality\":6,\"PROSECUTE\":6,\"vicious\":5,\"cleave\":6,\"smoldering\":5,\"looting\":5,\"syphon\":5,\"ultimate_chimera\":5,\"vampirism\":6,\"first_strike\":5,\"champion\":10},\"uuid\":\"098f4ac1-bf99-4829-a183-70e3a6bc8b2a\",\"timestamp\":1671157200000}}}")).getOrThrow(); + private final ItemStack DARK_CLAYMORE_OLD = ItemStack.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString("{\"id\":\"minecraft:stone_sword\",\"count\":1,\"components\":{\"minecraft:attribute_modifiers\":{\"modifiers\":[],\"show_in_tooltip\":false},\"minecraft:unbreakable\":{\"show_in_tooltip\":false},\"minecraft:lore\":[\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Gear Score: \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"1561 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(5000)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+580 \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+3,339)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Strength: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+517 \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[+5] \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+220) \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+32) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+3,194.1)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Crit Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+133% \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+819%)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Bonus Attack Speed: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+50% \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+77.5%)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Magic Find: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+30 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+46.5)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Ferocity: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+5 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+7.75)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Swing Range: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+2 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+2.1)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[\\\" \\\",{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"❁\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"] \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"❁\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"]\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Chimera V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Champion X\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Cleave VI\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Critical VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Cubism VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Divine Gift III\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Dragon Hunter V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Ender Slayer VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Experience V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Fire Aspect III\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"First Strike V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Impaling III\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Lethality VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Looting V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Luck VII\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Prosecute VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Scavenger V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Sharpness VII\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Smoldering V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Syphon V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Tabasco III\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Thunderlord VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Titan Killer VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Vampirism VI\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Venomous VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Vicious V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"gray\\\",\\\"italic\\\":true,\\\"text\\\":\\\"That thing was too big to be called a\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"italic\\\":true,\\\"text\\\":\\\"sword, it was more like a large hunk\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"italic\\\":true,\\\"text\\\":\\\"of stone.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Withered Bonus\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Grants \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+1 \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"❁ Strength \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"per\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"Catacombs \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"level.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"},\\\"\\\",{\\\"bold\\\":false,\\\"extra\\\":[\\\" \\\"],\\\"italic\\\":false,\\\"obfuscated\\\":false,\\\"strikethrough\\\":false,\\\"text\\\":\\\"\\\",\\\"underlined\\\":false},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"MYTHIC DUNGEON LONGSWORD \\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\"],\"minecraft:enchantment_glint_override\":true,\"minecraft:custom_name\":\"{\\\"extra\\\":[{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Withered Dark Claymore \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"➎\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"minecraft:custom_data\":{\"rarity_upgrades\":1,\"hot_potato_count\":15,\"gems\":{\"JASPER_0\":{\"uuid\":\"e9881031-1b36-4c41-8d13-739685b700aa\",\"quality\":\"PERFECT\"},\"JASPER_1\":{\"uuid\":\"afb95bac-0269-4978-a3ed-f5a3e4e57338\",\"quality\":\"PERFECT\"},\"unlocked_slots\":[\"JASPER_0\",\"JASPER_1\"]},\"champion_combat_xp\":4.8087379696333125E7,\"modifier\":\"withered\",\"art_of_war_count\":1,\"upgrade_level\":10,\"id\":\"DARK_CLAYMORE\",\"enchantments\":{\"impaling\":3,\"luck\":7,\"critical\":7,\"scavenger\":5,\"ender_slayer\":7,\"fire_aspect\":3,\"experience\":5,\"divine_gift\":3,\"venomous\":6,\"dragon_hunter\":5,\"tabasco\":3,\"thunderlord\":7,\"sharpness\":7,\"cubism\":6,\"titan_killer\":7,\"lethality\":6,\"PROSECUTE\":6,\"vicious\":5,\"cleave\":6,\"smoldering\":5,\"looting\":5,\"syphon\":5,\"ultimate_chimera\":5,\"vampirism\":6,\"first_strike\":5,\"champion\":10},\"uuid\":\"098f4ac1-bf99-4829-a183-70e3a6bc8b2a\",\"timestamp\":\"2/5/22 2:20 AM\"}}}")).getOrThrow(); + private final ItemStack TITANIUM_DRILL_DR_X655 = ItemStack.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString("{\"id\":\"minecraft:prismarine_shard\",\"count\":1,\"components\":{\"minecraft:attribute_modifiers\":{\"modifiers\":[],\"show_in_tooltip\":false},\"minecraft:enchantments\":{\"levels\":{\"minecraft:efficiency\":5}},\"minecraft:lore\":[\"{\\\"extra\\\":[{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"Breaking Power 10\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+75\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Mining Speed: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+1,810 \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"[+50] \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+60) \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+100)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Mining Fortune: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+273 \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+8) \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+50)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Pristine: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+7 \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+2)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Mining Wisdom: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+4\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[\\\" \\\",{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"⸕\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"] \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"☘\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"] \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"✦\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"]\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Compact IV \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"4,481\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Efficiency V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Experience IV\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Fortune IV\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Pristine V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Smelting Touch I\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"Mithril-Infused Fuel Tank\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Increases the fuel capacity to \\\"},{\\\"color\\\":\\\"dark_green\\\",\\\"text\\\":\\\"10,000\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\".\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Drill Engine: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"Not Installed\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Increases \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"⸕ Mining Speed \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"with part\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"installed.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"Sunny Side Goblin Egg Part\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Grants \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+50 \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"☘ Mining Fortune\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\", but fuel\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"consumption is doubled.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Fuel: \\\"},{\\\"color\\\":\\\"dark_green\\\",\\\"text\\\":\\\"5,395\\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"/10k\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"Ability: Mining Speed Boost \\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"RIGHT CLICK\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Grants \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+\\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"300% \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"⸕ Mining Speed \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"for\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"20s\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\".\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"Cooldown: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"120s\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Auspicious Bonus\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Grants \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+8 \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"☘ Mining Fortune\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\", which\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"increases your chance for multiple\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"drops.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"},\\\"\\\",{\\\"bold\\\":false,\\\"extra\\\":[\\\" \\\"],\\\"italic\\\":false,\\\"obfuscated\\\":false,\\\"strikethrough\\\":false,\\\"text\\\":\\\"\\\",\\\"underlined\\\":false},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"MYTHIC DRILL \\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\"],\"minecraft:custom_name\":\"{\\\"extra\\\":[{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Auspicious Titanium Drill DR-X655\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"minecraft:custom_data\":{\"rarity_upgrades\":1,\"drill_part_upgrade_module\":\"goblin_omelette_sunny_side\",\"gems\":{\"AMBER_0\":\"PERFECT\",\"JADE_0\":\"PERFECT\",\"MINING_0_gem\":\"TOPAZ\",\"MINING_0\":\"PERFECT\",\"unlocked_slots\":[\"JADE_0\",\"MINING_0\"]},\"polarvoid\":5,\"drill_fuel\":5395,\"modifier\":\"auspicious\",\"compact_blocks\":4481,\"id\":\"TITANIUM_DRILL_4\",\"enchantments\":{\"pristine\":5,\"efficiency\":5,\"fortune\":4,\"smelting_touch\":1,\"compact\":4,\"experience\":4},\"drill_part_fuel_tank\":\"mithril_fuel_tank\",\"uuid\":\"24404cec-7249-4612-b43e-0bc897384dd2\",\"timestamp\":1712894721557},\"minecraft:damage\":4605}}")).getOrThrow(); + private final ItemStack ASTRAEA = ItemStack.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString("{\"id\":\"minecraft:iron_sword\",\"count\":1,\"components\":{\"minecraft:attribute_modifiers\":{\"modifiers\":[],\"show_in_tooltip\":false},\"minecraft:unbreakable\":{\"show_in_tooltip\":false},\"minecraft:lore\":[\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Gear Score: \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"1851 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(5000)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+377 \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+2,205)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Strength: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+250 \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[+5] \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+50) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+1,480.5)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Crit Damage: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+70% \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+441%)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Bonus Attack Speed: \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+7% \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+7%) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+10.85%)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Defense: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+405 \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+2,394)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Intelligence: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+210 \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"(+125) \\\"},{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"(+30) \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+1,291.5)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"True Defense: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+22 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+31)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Ferocity: \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+33 \\\"},{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"(+46.5)\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[\\\" \\\",{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"dark_purple\\\",\\\"text\\\":\\\"☤\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"] \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"[\\\"},{\\\"color\\\":\\\"aqua\\\",\\\"text\\\":\\\"⚔\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"]\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Ultimate Wise V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Champion X\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Cleave VI\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Critical VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Cubism V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Dragon Hunter V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Ender Slayer VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Execute V\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Experience V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Fire Aspect III\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"First Strike IV\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Giant Killer VI\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Impaling III\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Lethality VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Life Steal V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Looting IV\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Luck VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Scavenger V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Smite VII\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Tabasco III\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Thunderlord VII\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"#AA5500\\\",\\\"text\\\":\\\"Vampirism VI\\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\", \\\"},{\\\"color\\\":\\\"blue\\\",\\\"text\\\":\\\"Venomous V\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Deals +\\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"50% \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"damage to Withers.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Grants \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"+1 \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"❁ Damage \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"and \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"+2 \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"❈\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"Defense \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"per \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"Catacombs \\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"level.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"Scroll Abilities:\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"Ability: Wither Impact \\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"RIGHT CLICK\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Teleport \\\"},{\\\"color\\\":\\\"green\\\",\\\"text\\\":\\\"10 blocks\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\" ahead of you.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"Then implode dealing \\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"109,088.2\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"damage to nearby enemies. Also\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"applies the wither shield scroll\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"ability reducing damage taken and\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"granting an absorption shield for \\\"},{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"5\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"yellow\\\",\\\"text\\\":\\\"\\\"},{\\\"color\\\":\\\"gray\\\",\\\"text\\\":\\\"seconds.\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"color\\\":\\\"dark_gray\\\",\\\"text\\\":\\\"Mana Cost: \\\"},{\\\"color\\\":\\\"dark_aqua\\\",\\\"text\\\":\\\"150\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"{\\\"extra\\\":[{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"},\\\"\\\",{\\\"bold\\\":false,\\\"extra\\\":[\\\" \\\"],\\\"italic\\\":false,\\\"obfuscated\\\":false,\\\"strikethrough\\\":false,\\\"text\\\":\\\"\\\",\\\"underlined\\\":false},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"\\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"MYTHIC DUNGEON SWORD \\\"},{\\\"bold\\\":true,\\\"color\\\":\\\"light_purple\\\",\\\"obfuscated\\\":true,\\\"text\\\":\\\"a\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\"],\"minecraft:enchantment_glint_override\":true,\"minecraft:custom_name\":\"{\\\"extra\\\":[{\\\"color\\\":\\\"light_purple\\\",\\\"text\\\":\\\"Heroic Astraea \\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"gold\\\",\\\"text\\\":\\\"✪\\\"},{\\\"color\\\":\\\"red\\\",\\\"text\\\":\\\"➎\\\"}],\\\"italic\\\":false,\\\"text\\\":\\\"\\\"}\",\"minecraft:custom_data\":{\"rarity_upgrades\":1,\"modifier\":\"heroic\",\"art_of_war_count\":1,\"dungeon_item_level\":5,\"upgrade_level\":10,\"originTag\":\"ASTRAEA_UPGRADE\",\"enchantments\":{\"impaling\":3,\"luck\":7,\"critical\":6,\"cleave\":6,\"looting\":4,\"smite\":7,\"telekinesis\":1,\"ender_slayer\":6,\"scavenger\":5,\"experience\":5,\"vampirism\":6,\"fire_aspect\":3,\"execute\":5,\"life_steal\":5,\"giant_killer\":6,\"first_strike\":4,\"venomous\":5,\"dragon_hunter\":5,\"tabasco\":3,\"thunderlord\":7,\"ultimate_wise\":5,\"cubism\":5,\"champion\":10,\"lethality\":6},\"uuid\":\"38d58369-401c-4cda-945d-759cb652c718\",\"ability_scroll\":[\"WITHER_SHIELD_SCROLL\",\"SHADOW_WARP_SCROLL\",\"IMPLOSION_SCROLL\"],\"hot_potato_count\":15,\"gems\":{\"DEFENSIVE_0\":{\"uuid\":\"1ed969b4-372e-4692-a994-4026ec480668\",\"quality\":\"PERFECT\"},\"DEFENSIVE_0_gem\":\"AMETHYST\",\"COMBAT_0\":{\"uuid\":\"77d8ef8f-2142-4a01-a6ec-1fa6352d62e4\",\"quality\":\"PERFECT\"},\"COMBAT_0_gem\":\"SAPPHIRE\"},\"champion_combat_xp\":1.381000444237401E8,\"id\":\"ASTRAEA\",\"timestamp\":1614631200000}}}")).getOrThrow(); - @BeforeAll - public static void setup() { - SharedConstants.createGameVersion(); - Bootstrap.initialize(); - } + @BeforeAll + public static void setup() { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + SharedConstants.createGameVersion(); + Bootstrap.initialize(); + } - @Test - void testGetExtraAttributes() { - Assertions.assertEquals("{art_of_war_count:1,dungeon_item_level:5,enchantments:{aiming:5,chance:4,cubism:5,impaling:3,infinite_quiver:10,overload:5,piercing:1,power:6,snipe:3,telekinesis:1,ultimate_soul_eater:5},hot_potato_count:15,id:\"JUJU_SHORTBOW\",modifier:\"spiritual\",originTag:\"QUICK_CRAFTING\",rarity_upgrades:1,runes:{DRAGON:3},stats_book:54778,timestamp:1622882460000L,uuid:\"b06b8fe2-470a-43f3-b844-658472f20996\"}", ItemUtils.getExtraAttributes(JUJU_SHORTBOW).toString()); - Assertions.assertEquals("{dungeon_item_level:5,enchantments:{telekinesis:1,ultimate_one_for_all:1},gems:{JASPER_0:\"FLAWLESS\"},hot_potato_count:15,id:\"LIVID_DAGGER\",modifier:\"fabled\",originTag:\"UNKNOWN\",rarity_upgrades:1,timestamp:\"2/20/21 3:09 PM\",uuid:\"214333db-d71c-4080-8487-00b4666bb9a4\"}", ItemUtils.getExtraAttributes(LIVID_DAGGER).toString()); - Assertions.assertEquals("{compact_blocks:97683,drill_fuel:2979,enchantments:{compact:7,efficiency:5,experience:3,fortune:3,telekinesis:1},id:\"MITHRIL_DRILL_1\",modifier:\"fleet\",originTag:\"UNKNOWN\",timestamp:\"1/30/21 5:52 AM\",uuid:\"575ce2c9-251e-4435-9020-de1a2e24b1d0\"}", ItemUtils.getExtraAttributes(MITHRIL_DRILL_1).toString()); - } + @Test + void testGetCustomData() { + Assertions.assertEquals("{art_of_war_count:1b,champion_combat_xp:4.8087379696333125E7d,enchantments:{PROSECUTE:6b,champion:10b,cleave:6b,critical:7b,cubism:6b,divine_gift:3b,dragon_hunter:5b,ender_slayer:7b,experience:5b,fire_aspect:3b,first_strike:5b,impaling:3b,lethality:6b,looting:5b,luck:7b,scavenger:5b,sharpness:7b,smoldering:5b,syphon:5b,tabasco:3b,thunderlord:7b,titan_killer:7b,ultimate_chimera:5b,vampirism:6b,venomous:6b,vicious:5b},gems:{JASPER_0:{quality:\"PERFECT\",uuid:\"e9881031-1b36-4c41-8d13-739685b700aa\"},JASPER_1:{quality:\"PERFECT\",uuid:\"afb95bac-0269-4978-a3ed-f5a3e4e57338\"},unlocked_slots:[\"JASPER_0\",\"JASPER_1\"]},hot_potato_count:15b,id:\"DARK_CLAYMORE\",modifier:\"withered\",rarity_upgrades:1b,timestamp:1671157200000L,upgrade_level:10b,uuid:\"098f4ac1-bf99-4829-a183-70e3a6bc8b2a\"}", ItemUtils.getCustomData(DARK_CLAYMORE).toString()); + Assertions.assertEquals("{compact_blocks:4481s,drill_fuel:5395s,drill_part_fuel_tank:\"mithril_fuel_tank\",drill_part_upgrade_module:\"goblin_omelette_sunny_side\",enchantments:{compact:4b,efficiency:5b,experience:4b,fortune:4b,pristine:5b,smelting_touch:1b},gems:{AMBER_0:\"PERFECT\",JADE_0:\"PERFECT\",MINING_0:\"PERFECT\",MINING_0_gem:\"TOPAZ\",unlocked_slots:[\"JADE_0\",\"MINING_0\"]},id:\"TITANIUM_DRILL_4\",modifier:\"auspicious\",polarvoid:5b,rarity_upgrades:1b,timestamp:1712894721557L,uuid:\"24404cec-7249-4612-b43e-0bc897384dd2\"}", ItemUtils.getCustomData(TITANIUM_DRILL_DR_X655).toString()); + Assertions.assertEquals("{ability_scroll:[\"WITHER_SHIELD_SCROLL\",\"SHADOW_WARP_SCROLL\",\"IMPLOSION_SCROLL\"],art_of_war_count:1b,champion_combat_xp:1.381000444237401E8d,dungeon_item_level:5b,enchantments:{champion:10b,cleave:6b,critical:6b,cubism:5b,dragon_hunter:5b,ender_slayer:6b,execute:5b,experience:5b,fire_aspect:3b,first_strike:4b,giant_killer:6b,impaling:3b,lethality:6b,life_steal:5b,looting:4b,luck:7b,scavenger:5b,smite:7b,tabasco:3b,telekinesis:1b,thunderlord:7b,ultimate_wise:5b,vampirism:6b,venomous:5b},gems:{COMBAT_0:{quality:\"PERFECT\",uuid:\"77d8ef8f-2142-4a01-a6ec-1fa6352d62e4\"},COMBAT_0_gem:\"SAPPHIRE\",DEFENSIVE_0:{quality:\"PERFECT\",uuid:\"1ed969b4-372e-4692-a994-4026ec480668\"},DEFENSIVE_0_gem:\"AMETHYST\"},hot_potato_count:15b,id:\"ASTRAEA\",modifier:\"heroic\",originTag:\"ASTRAEA_UPGRADE\",rarity_upgrades:1b,timestamp:1614631200000L,upgrade_level:10b,uuid:\"38d58369-401c-4cda-945d-759cb652c718\"}", ItemUtils.getCustomData(ASTRAEA).toString()); + } - @Test - void testGetItemId() { - Assertions.assertEquals("JUJU_SHORTBOW", ItemUtils.getItemId(JUJU_SHORTBOW)); - Assertions.assertEquals("LIVID_DAGGER", ItemUtils.getItemId(LIVID_DAGGER)); - Assertions.assertEquals("MITHRIL_DRILL_1", ItemUtils.getItemId(MITHRIL_DRILL_1)); - } + @Test + void testGetItemId() { + Assertions.assertEquals("DARK_CLAYMORE", ItemUtils.getItemId(DARK_CLAYMORE)); + Assertions.assertEquals("TITANIUM_DRILL_4", ItemUtils.getItemId(TITANIUM_DRILL_DR_X655)); + Assertions.assertEquals("ASTRAEA", ItemUtils.getItemId(ASTRAEA)); + } - @Test - void testGetItemUuid() { - Assertions.assertEquals("b06b8fe2-470a-43f3-b844-658472f20996", ItemUtils.getItemUuid(JUJU_SHORTBOW)); - Assertions.assertEquals("214333db-d71c-4080-8487-00b4666bb9a4", ItemUtils.getItemUuid(LIVID_DAGGER)); - Assertions.assertEquals("575ce2c9-251e-4435-9020-de1a2e24b1d0", ItemUtils.getItemUuid(MITHRIL_DRILL_1)); - } + @Test + void testGetItemUuid() { + Assertions.assertEquals("098f4ac1-bf99-4829-a183-70e3a6bc8b2a", ItemUtils.getItemUuid(DARK_CLAYMORE)); + Assertions.assertEquals("24404cec-7249-4612-b43e-0bc897384dd2", ItemUtils.getItemUuid(TITANIUM_DRILL_DR_X655)); + Assertions.assertEquals("38d58369-401c-4cda-945d-759cb652c718", ItemUtils.getItemUuid(ASTRAEA)); + } - @Test - void testGetTimestamp() { - Assertions.assertEquals("June 5, 2021", ItemUtils.getTimestamp(JUJU_SHORTBOW_OLD)); - Assertions.assertEquals("June 5, 2021", ItemUtils.getTimestamp(JUJU_SHORTBOW)); - Assertions.assertEquals("February 20, 2021", ItemUtils.getTimestamp(LIVID_DAGGER)); - Assertions.assertEquals("January 30, 2021", ItemUtils.getTimestamp(MITHRIL_DRILL_1)); - } + @Test + void testGetTimestamp() { + Assertions.assertEquals("February 5, 2022", ItemUtils.getTimestamp(DARK_CLAYMORE_OLD)); + Assertions.assertEquals("December 16, 2022", ItemUtils.getTimestamp(DARK_CLAYMORE)); // The timestamp is 1671157200000 which is December 16, 2022 in UTC + Assertions.assertEquals("April 12, 2024", ItemUtils.getTimestamp(TITANIUM_DRILL_DR_X655)); + Assertions.assertEquals("March 1, 2021", ItemUtils.getTimestamp(ASTRAEA)); + } - @Test - void testGetDurability() { - IntIntPair durability = ItemUtils.getDurability(MITHRIL_DRILL_1); - Assertions.assertNotNull(durability); - Assertions.assertEquals(durability.leftInt(), 2979); - Assertions.assertEquals(durability.rightInt(), 3000); - } + @Test + void testGetDurability() { + IntIntPair durability = ItemUtils.getDurability(TITANIUM_DRILL_DR_X655); + Assertions.assertNotNull(durability); + Assertions.assertEquals(durability.leftInt(), 5395); + Assertions.assertEquals(durability.rightInt(), 10_000); + } } diff --git a/src/test/java/de/hysky/skyblocker/utils/datafixer/ItemStackComponentizationFixerTest.java b/src/test/java/de/hysky/skyblocker/utils/datafixer/ItemStackComponentizationFixerTest.java new file mode 100644 index 00000000..d791fd72 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/utils/datafixer/ItemStackComponentizationFixerTest.java @@ -0,0 +1,89 @@ +package de.hysky.skyblocker.utils.datafixer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; + +import net.minecraft.Bootstrap; +import net.minecraft.SharedConstants; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ItemEnchantmentsComponent; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.StringNbtReader; +import net.minecraft.util.Util; + +public class ItemStackComponentizationFixerTest { + private final NbtCompound NBT = convertToNbt("{id:\"minecraft:diamond_sword\",Count:1,tag:{ExtraAttributes:{id:\"TEST\"}}}"); + private final Gson GSON = new Gson(); + private final ItemStack TEST_STACK = Util.make(new ItemStack(Items.DIAMOND_SWORD, 1), item -> { + ItemEnchantmentsComponent.Builder builder = new ItemEnchantmentsComponent.Builder(ItemEnchantmentsComponent.DEFAULT); + + builder.add(Enchantments.SHARPNESS, 1); + item.set(DataComponentTypes.ENCHANTMENTS, builder.build()); + }); + + @BeforeAll + public static void setup() { + SharedConstants.createGameVersion(); + Bootstrap.initialize(); + } + + @Test + void testNbtConversion() { + Assertions.assertNotEquals(NBT, new NbtCompound()); + } + + @Test + void testDataFixer() { + ItemStack fixedStack = ItemStackComponentizationFixer.fixUpItem(NBT); + JsonElement stackJson = ItemStack.CODEC.encodeStart(JsonOps.INSTANCE, fixedStack).getOrThrow(); + + Assertions.assertEquals("{\"id\":\"minecraft:diamond_sword\",\"count\":1,\"components\":{\"minecraft:custom_data\":{\"ExtraAttributes\":{\"id\":\"TEST\"}}}}", GSON.toJson(stackJson)); + } + + @Test + void testComponentsAsString() { + String componentString = ItemStackComponentizationFixer.componentsAsString(TEST_STACK); + + Assertions.assertEquals("[minecraft:enchantments={levels:{\"minecraft:sharpness\":1}}]", componentString); + } + + @Test + void testFromComponentsString() { + String componentString = "[minecraft:enchantments={levels:{\"minecraft:sharpness\":1}}]"; + ItemStack stack = ItemStackComponentizationFixer.fromComponentsString("minecraft:diamond_sword", 1, componentString); + + Assertions.assertTrue(ItemStack.areItemsAndComponentsEqual(stack, TEST_STACK)); + } + + @Test + void testFromComponentsStringWithInvalidItem() { + String componentString = "[minecraft:enchantments={levels:{\"minecraft:sharpness\":1}}]"; + ItemStack stack = ItemStackComponentizationFixer.fromComponentsString("minecraft:does_not_exist", 1, componentString); + + Assertions.assertEquals(stack, ItemStack.EMPTY); + } + + @Test + void testNbtToComponentsString() { + ItemStack fixedStack = ItemStackComponentizationFixer.fixUpItem(NBT); + String componentsString = ItemStackComponentizationFixer.componentsAsString(fixedStack); + + Assertions.assertEquals("[minecraft:custom_data={ExtraAttributes:{id:\"TEST\"}}]", componentsString); + } + + private static NbtCompound convertToNbt(String nbt) { + try { + return StringNbtReader.parse(nbt); + } catch (Exception e) { + return new NbtCompound(); + } + } +} |