From db65cbaa4fb46d61e7bade1ee0c0b11c92a0863c Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:00:02 -0400 Subject: Item Protection --- .../skyblocker/mixin/ClientPlayerEntityMixin.java | 6 +- .../skyblocker/mixin/HandledScreenMixin.java | 67 +++++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) (limited to 'src/main/java/me/xmrvizzy/skyblocker/mixin') diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java index ee1fc5b8..531fa3c5 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java @@ -4,6 +4,7 @@ import com.mojang.authlib.GameProfile; import dev.cbyrne.betterinject.annotations.Inject; import me.xmrvizzy.skyblocker.skyblock.HotbarSlotLock; +import me.xmrvizzy.skyblocker.skyblock.ItemProtection; import me.xmrvizzy.skyblocker.skyblock.rift.HealingMelonIndicator; import me.xmrvizzy.skyblocker.utils.Utils; import net.minecraft.client.network.AbstractClientPlayerEntity; @@ -21,7 +22,10 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity @Inject(method = "dropSelectedItem", at = @At("HEAD"), cancellable = true) public void skyblocker$dropSelectedItem(CallbackInfoReturnable cir) { - if (Utils.isOnSkyblock()) HotbarSlotLock.handleDropSelectedItem(this.getInventory().selectedSlot, cir); + if (Utils.isOnSkyblock()) { + if (ItemProtection.isItemProtected(this.getInventory().getMainHandStack())) cir.setReturnValue(false); + HotbarSlotLock.handleDropSelectedItem(this.getInventory().selectedSlot, cir); + } } @Inject(method = "updateHealth", at = @At("RETURN")) diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java index 17497ded..fcdcb10e 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java @@ -2,6 +2,7 @@ package me.xmrvizzy.skyblocker.mixin; import me.xmrvizzy.skyblocker.SkyblockerMod; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; +import me.xmrvizzy.skyblocker.skyblock.ItemProtection; import me.xmrvizzy.skyblocker.skyblock.experiment.ChronomatronSolver; import me.xmrvizzy.skyblocker.skyblock.experiment.ExperimentSolver; import me.xmrvizzy.skyblocker.skyblock.experiment.SuperpairsSolver; @@ -12,16 +13,21 @@ import me.xmrvizzy.skyblocker.skyblock.item.WikiLookup; import me.xmrvizzy.skyblocker.skyblock.itemlist.ItemRegistry; import me.xmrvizzy.skyblocker.utils.Utils; import me.xmrvizzy.skyblocker.utils.render.gui.ContainerSolver; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.item.TooltipContext; import net.minecraft.inventory.SimpleInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -36,10 +42,20 @@ import java.util.Map; import java.util.regex.Matcher; @Mixin(HandledScreen.class) -public abstract class HandledScreenMixin extends Screen { +public abstract class HandledScreenMixin extends Screen { + /** + * This is the slot id returned for when a click is outside of the screen's bounds + */ + @Unique + private static final int OUT_OF_BOUNDS_SLOT = -999; + @Shadow @Nullable protected Slot focusedSlot; + + @Shadow + @Final + protected T handler; protected HandledScreenMixin(Text title) { super(title); @@ -120,4 +136,53 @@ public abstract class HandledScreenMixin 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 + */ + @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At("HEAD"), cancellable = true) + private void skyblocker$onSlotInteract(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { + if (Utils.isOnSkyblock()) { + // When you try and drop the item by picking it up then clicking outside of the screen + if (slotId == OUT_OF_BOUNDS_SLOT) { + ItemStack cursorStack = this.handler.getCursorStack(); + + if (ItemProtection.isItemProtected(cursorStack)) ci.cancel(); + } + + if (slot != null) { + // When you click your drop key while hovering over an item + if (actionType == SlotActionType.THROW) { + ItemStack stack = slot.getStack(); + + if (ItemProtection.isItemProtected(stack)) ci.cancel(); + } + + //Prevent salvaging + if (this.getTitle().getString().equals("Salvage Items")) { + ItemStack stack = slot.getStack(); + + if (ItemProtection.isItemProtected(stack)) ci.cancel(); + } + + //Prevent selling to NPC shops + if (this.handler instanceof GenericContainerScreenHandler handler && handler.getRows() == 6) { + ItemStack sellItem = this.handler.slots.get(49).getStack(); + + if (sellItem.getName().getString().equals("Sell Item") || skyblocker$doesLoreContain(sellItem, this.client, "buyback")) { + ItemStack stack = slot.getStack(); + + if (ItemProtection.isItemProtected(stack)) ci.cancel(); + } + } + } + } + } + + //TODO make this a util method somewhere else, eventually + private static boolean skyblocker$doesLoreContain(ItemStack stack, MinecraftClient client, String searchString) { + return stack.getTooltip(client.player, TooltipContext.BASIC).stream().map(Text::getString).anyMatch(line -> line.contains(searchString)); + } } -- cgit From 14f21e10f0e0f96d2e879316c116b848a23f0cbe Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Tue, 3 Oct 2023 22:07:32 -0400 Subject: Suggestions! --- src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/main/java/me/xmrvizzy/skyblocker/mixin') diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java index fcdcb10e..95748333 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java @@ -139,7 +139,6 @@ public abstract class HandledScreenMixin 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 */ @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At("HEAD"), cancellable = true) @@ -168,7 +167,7 @@ public abstract class HandledScreenMixin extends Screen } //Prevent selling to NPC shops - if (this.handler instanceof GenericContainerScreenHandler handler && handler.getRows() == 6) { + if (this.client != null && this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) { ItemStack sellItem = this.handler.slots.get(49).getStack(); if (sellItem.getName().getString().equals("Sell Item") || skyblocker$doesLoreContain(sellItem, this.client, "buyback")) { -- cgit From 8e19196990e3e0f2ec39aa9311cebe3a77ff6677 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Wed, 4 Oct 2023 01:31:52 -0400 Subject: Move file --- .../skyblocker/mixin/ClientPlayerEntityMixin.java | 2 +- .../skyblocker/mixin/HandledScreenMixin.java | 2 +- .../skyblocker/skyblock/ItemProtection.java | 75 ---------------------- .../skyblocker/skyblock/item/ItemProtection.java | 75 ++++++++++++++++++++++ 4 files changed, 77 insertions(+), 77 deletions(-) delete mode 100644 src/main/java/me/xmrvizzy/skyblocker/skyblock/ItemProtection.java create mode 100644 src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemProtection.java (limited to 'src/main/java/me/xmrvizzy/skyblocker/mixin') diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java index 531fa3c5..8b2ec417 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java @@ -4,7 +4,7 @@ import com.mojang.authlib.GameProfile; import dev.cbyrne.betterinject.annotations.Inject; import me.xmrvizzy.skyblocker.skyblock.HotbarSlotLock; -import me.xmrvizzy.skyblocker.skyblock.ItemProtection; +import me.xmrvizzy.skyblocker.skyblock.item.ItemProtection; import me.xmrvizzy.skyblocker.skyblock.rift.HealingMelonIndicator; import me.xmrvizzy.skyblocker.utils.Utils; import net.minecraft.client.network.AbstractClientPlayerEntity; diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java index 95748333..9ba2107b 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java @@ -2,13 +2,13 @@ package me.xmrvizzy.skyblocker.mixin; import me.xmrvizzy.skyblocker.SkyblockerMod; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; -import me.xmrvizzy.skyblocker.skyblock.ItemProtection; import me.xmrvizzy.skyblocker.skyblock.experiment.ChronomatronSolver; import me.xmrvizzy.skyblocker.skyblock.experiment.ExperimentSolver; import me.xmrvizzy.skyblocker.skyblock.experiment.SuperpairsSolver; import me.xmrvizzy.skyblocker.skyblock.experiment.UltrasequencerSolver; import me.xmrvizzy.skyblocker.skyblock.item.BackpackPreview; import me.xmrvizzy.skyblocker.skyblock.item.CompactorDeletorPreview; +import me.xmrvizzy.skyblocker.skyblock.item.ItemProtection; import me.xmrvizzy.skyblocker.skyblock.item.WikiLookup; import me.xmrvizzy.skyblocker.skyblock.itemlist.ItemRegistry; import me.xmrvizzy.skyblocker.utils.Utils; diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/ItemProtection.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/ItemProtection.java deleted file mode 100644 index 25be4a55..00000000 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/ItemProtection.java +++ /dev/null @@ -1,75 +0,0 @@ -package me.xmrvizzy.skyblocker.skyblock; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.CommandDispatcher; - -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; -import me.xmrvizzy.skyblocker.utils.Utils; -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.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; - -public class ItemProtection { - - public static void init() { - ClientCommandRegistrationCallback.EVENT.register(ItemProtection::registerCommand); - } - - public static boolean isItemProtected(ItemStack stack) { - if (stack == null || stack.isEmpty()) return false; - - NbtCompound nbt = stack.getNbt(); - - if (nbt != null && nbt.contains("ExtraAttributes")) { - NbtCompound extraAttributes = nbt.getCompound("ExtraAttributes"); - String itemUuid = extraAttributes.contains("uuid") ? extraAttributes.getString("uuid") : ""; - - return SkyblockerConfigManager.get().general.protectedItems.contains(itemUuid); - } - - return false; - } - - private static void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { - dispatcher.register(ClientCommandManager.literal("skyblocker") - .then(ClientCommandManager.literal("protectItem") - .executes(context -> protectMyItem(context.getSource())))); - } - - private static int protectMyItem(FabricClientCommandSource source) { - ItemStack heldItem = source.getPlayer().getMainHandStack(); - NbtCompound nbt = (heldItem != null) ? heldItem.getNbt() : null; - - if (Utils.isOnSkyblock() && nbt != null && nbt.contains("ExtraAttributes")) { - NbtCompound extraAttributes = nbt.getCompound("ExtraAttributes"); - String itemUuid = extraAttributes.contains("uuid") ? extraAttributes.getString("uuid") : null; - - if (itemUuid != null) { - ObjectOpenHashSet protectedItems = SkyblockerConfigManager.get().general.protectedItems; - - if (!protectedItems.contains(itemUuid)) { - protectedItems.add(itemUuid); - SkyblockerConfigManager.save(); - - source.sendFeedback(Text.translatable("skyblocker.itemProtection.added", heldItem.getName())); - } else { - protectedItems.remove(itemUuid); - SkyblockerConfigManager.save(); - - source.sendFeedback(Text.translatable("skyblocker.itemProtection.removed", heldItem.getName())); - } - } else { - source.sendFeedback(Text.translatable("skyblocker.itemProtection.noItemUuid")); - } - } else { - source.sendFeedback(Text.translatable("skyblocker.itemProtection.unableToProtect")); - } - - return Command.SINGLE_SUCCESS; - } -} diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemProtection.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemProtection.java new file mode 100644 index 00000000..db671787 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemProtection.java @@ -0,0 +1,75 @@ +package me.xmrvizzy.skyblocker.skyblock.item; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; + +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; +import me.xmrvizzy.skyblocker.utils.Utils; +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.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; + +public class ItemProtection { + + public static void init() { + ClientCommandRegistrationCallback.EVENT.register(ItemProtection::registerCommand); + } + + public static boolean isItemProtected(ItemStack stack) { + if (stack == null || stack.isEmpty()) return false; + + NbtCompound nbt = stack.getNbt(); + + if (nbt != null && nbt.contains("ExtraAttributes")) { + NbtCompound extraAttributes = nbt.getCompound("ExtraAttributes"); + String itemUuid = extraAttributes.contains("uuid") ? extraAttributes.getString("uuid") : ""; + + return SkyblockerConfigManager.get().general.protectedItems.contains(itemUuid); + } + + return false; + } + + private static void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(ClientCommandManager.literal("skyblocker") + .then(ClientCommandManager.literal("protectItem") + .executes(context -> protectMyItem(context.getSource())))); + } + + private static int protectMyItem(FabricClientCommandSource source) { + ItemStack heldItem = source.getPlayer().getMainHandStack(); + NbtCompound nbt = (heldItem != null) ? heldItem.getNbt() : null; + + if (Utils.isOnSkyblock() && nbt != null && nbt.contains("ExtraAttributes")) { + NbtCompound extraAttributes = nbt.getCompound("ExtraAttributes"); + String itemUuid = extraAttributes.contains("uuid") ? extraAttributes.getString("uuid") : null; + + if (itemUuid != null) { + ObjectOpenHashSet protectedItems = SkyblockerConfigManager.get().general.protectedItems; + + if (!protectedItems.contains(itemUuid)) { + protectedItems.add(itemUuid); + SkyblockerConfigManager.save(); + + source.sendFeedback(Text.translatable("skyblocker.itemProtection.added", heldItem.getName())); + } else { + protectedItems.remove(itemUuid); + SkyblockerConfigManager.save(); + + source.sendFeedback(Text.translatable("skyblocker.itemProtection.removed", heldItem.getName())); + } + } else { + source.sendFeedback(Text.translatable("skyblocker.itemProtection.noItemUuid")); + } + } else { + source.sendFeedback(Text.translatable("skyblocker.itemProtection.unableToProtect")); + } + + return Command.SINGLE_SUCCESS; + } +} -- cgit From 21d6e2edb48ea7aa88287a5595c5a42511c9785f Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Fri, 6 Oct 2023 00:43:47 -0400 Subject: Item Rarity Backgrounds --- .../java/me/xmrvizzy/skyblocker/SkyblockerMod.java | 1 + .../skyblocker/config/SkyblockerConfig.java | 3 + .../config/categories/GeneralCategory.java | 8 ++ .../skyblocker/mixin/HandledScreenMixin.java | 6 ++ .../xmrvizzy/skyblocker/mixin/InGameHudMixin.java | 9 ++- .../skyblock/item/ItemRarityBackgrounds.java | 86 +++++++++++++++++++++ .../skyblock/item/SkyblockItemRarity.java | 28 +++++++ .../resources/assets/skyblocker/lang/en_us.json | 2 + .../gui/sprites/item_rarity_background.png | Bin 0 -> 198 bytes 9 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemRarityBackgrounds.java create mode 100644 src/main/java/me/xmrvizzy/skyblocker/skyblock/item/SkyblockItemRarity.java create mode 100644 src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background.png (limited to 'src/main/java/me/xmrvizzy/skyblocker/mixin') diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java index 07a5be76..cda0b823 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java +++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java @@ -101,6 +101,7 @@ public class SkyblockerMod implements ClientModInitializer { QuiverWarning.init(); SpecialEffects.init(); ItemProtection.init(); + ItemRarityBackgrounds.init(); containerSolverManager.init(); statusBarTracker.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java index e40c3f21..17967c53 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java @@ -461,6 +461,9 @@ public class SkyblockerConfig { public static class ItemInfoDisplay { @SerialEntry public boolean attributeShardInfo = true; + + @SerialEntry + public boolean itemRarityBackgrounds = false; } public static class SpecialEffects { diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/categories/GeneralCategory.java b/src/main/java/me/xmrvizzy/skyblocker/config/categories/GeneralCategory.java index c5e2d34c..cd0fe65c 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/categories/GeneralCategory.java @@ -348,6 +348,14 @@ public class GeneralCategory { newValue -> config.general.itemInfoDisplay.attributeShardInfo = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds.@Tooltip"))) + .binding(defaults.general.itemInfoDisplay.itemRarityBackgrounds, + () -> config.general.itemInfoDisplay.itemRarityBackgrounds, + newValue -> config.general.itemInfoDisplay.itemRarityBackgrounds = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) //Special Effects diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java index 9ba2107b..7e94d660 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java @@ -9,6 +9,7 @@ import me.xmrvizzy.skyblocker.skyblock.experiment.UltrasequencerSolver; import me.xmrvizzy.skyblocker.skyblock.item.BackpackPreview; import me.xmrvizzy.skyblocker.skyblock.item.CompactorDeletorPreview; import me.xmrvizzy.skyblocker.skyblock.item.ItemProtection; +import me.xmrvizzy.skyblocker.skyblock.item.ItemRarityBackgrounds; import me.xmrvizzy.skyblocker.skyblock.item.WikiLookup; import me.xmrvizzy.skyblocker.skyblock.itemlist.ItemRegistry; import me.xmrvizzy.skyblocker.utils.Utils; @@ -184,4 +185,9 @@ public abstract class HandledScreenMixin extends Screen private static boolean skyblocker$doesLoreContain(ItemStack stack, MinecraftClient client, String searchString) { return stack.getTooltip(client.player, TooltipContext.BASIC).stream().map(Text::getString).anyMatch(line -> line.contains(searchString)); } + + @Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V")) + private void skyblocker$drawItemRarityBackground(DrawContext context, Slot slot, CallbackInfo ci) { + if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y); + } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java index c73ca2aa..0425b0b8 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java @@ -6,11 +6,13 @@ import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; import me.xmrvizzy.skyblocker.skyblock.FancyStatusBars; import me.xmrvizzy.skyblocker.skyblock.HotbarSlotLock; import me.xmrvizzy.skyblocker.skyblock.dungeon.DungeonMap; +import me.xmrvizzy.skyblocker.skyblock.item.ItemRarityBackgrounds; import me.xmrvizzy.skyblocker.utils.Utils; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -33,9 +35,10 @@ public abstract class InGameHudMixin { private int scaledWidth; @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$renderHotbarItemLock(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) { - if (Utils.isOnSkyblock() && HotbarSlotLock.isLocked(index)) { - context.drawTexture(SLOT_LOCK, x, y, 0, 0, 16, 16); + 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) { + if (Utils.isOnSkyblock()) { + if (SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) ItemRarityBackgrounds.tryDraw(player.getInventory().main.get(index), context, x, y); + if (HotbarSlotLock.isLocked(index)) context.drawTexture(SLOT_LOCK, x, y, 0, 0, 16, 16); } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemRarityBackgrounds.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemRarityBackgrounds.java new file mode 100644 index 00000000..b6020e6e --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemRarityBackgrounds.java @@ -0,0 +1,86 @@ +package me.xmrvizzy.skyblocker.skyblock.item; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableMap; +import com.mojang.blaze3d.systems.RenderSystem; + +import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; +import me.xmrvizzy.skyblocker.SkyblockerMod; +import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler; +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; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class ItemRarityBackgrounds { + private static final Identifier RARITY_BG_TEX = new Identifier(SkyblockerMod.NAMESPACE, "item_rarity_background"); + private static final Supplier SPRITE = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(RARITY_BG_TEX); + private static final ImmutableMap LORE_RARITIES = ImmutableMap.ofEntries( + Map.entry("ADMIN", SkyblockItemRarity.ADMIN), + Map.entry("SPECIAL", SkyblockItemRarity.SPECIAL), //Very special is the same color so this will cover it + Map.entry("DIVINE", SkyblockItemRarity.DIVINE), + Map.entry("MYTHIC", SkyblockItemRarity.MYTHIC), + Map.entry("LEGENDARY", SkyblockItemRarity.LEGENDARY), + Map.entry("LEGENJERRY", SkyblockItemRarity.LEGENDARY), + Map.entry("EPIC", SkyblockItemRarity.EPIC), + Map.entry("RARE", SkyblockItemRarity.RARE), + Map.entry("UNCOMMON", SkyblockItemRarity.UNCOMMON), + Map.entry("COMMON", SkyblockItemRarity.COMMON)); + + private static final Int2ReferenceOpenHashMap CACHE = new Int2ReferenceOpenHashMap<>(); + + public static void init() { + //Clear the cache every 5 minutes, ints are very compact! + Scheduler.INSTANCE.scheduleCyclic(() -> CACHE.clear(), 4800); + } + + public static void tryDraw(ItemStack stack, DrawContext context, int x, int y) { + MinecraftClient client = MinecraftClient.getInstance(); + + if (client.player != null) { + SkyblockItemRarity itemRarity = getItemRarity(stack, client.player); + + if (itemRarity != null) draw(context, x, y, itemRarity); + } + } + + private static SkyblockItemRarity getItemRarity(ItemStack stack, ClientPlayerEntity player) { + if (stack == null || stack.isEmpty()) return null; + + int hashCode = System.identityHashCode(stack); + if (CACHE.containsKey(hashCode)) return CACHE.get(hashCode); + + List tooltip = stack.getTooltip(player, TooltipContext.BASIC); + String[] stringifiedTooltip = tooltip.stream().map(Text::getString).toArray(String[]::new); + + for (String rarity : LORE_RARITIES.keySet()) { + if (Arrays.stream(stringifiedTooltip).anyMatch(line -> line.contains(rarity))) { + SkyblockItemRarity foundRarity = LORE_RARITIES.get(rarity); + + CACHE.put(hashCode, foundRarity); + return LORE_RARITIES.get(rarity); + } + } + + CACHE.put(hashCode, null); + return null; + } + + private static void draw(DrawContext context, int x, int y, SkyblockItemRarity rarity) { + //Enable blending to handle HUD translucency + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + context.drawSprite(x, y, 0, 16, 16, SPRITE.get(), rarity.r, rarity.g, rarity.b, 1f); + + RenderSystem.disableBlend(); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/SkyblockItemRarity.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/SkyblockItemRarity.java new file mode 100644 index 00000000..da722196 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/SkyblockItemRarity.java @@ -0,0 +1,28 @@ +package me.xmrvizzy.skyblocker.skyblock.item; + +import net.minecraft.util.Formatting; + +public enum SkyblockItemRarity { + ADMIN(Formatting.DARK_RED), + VERY_SPECIAL(Formatting.RED), + SPECIAL(Formatting.RED), + DIVINE(Formatting.AQUA), + MYTHIC(Formatting.LIGHT_PURPLE), + LEGENDARY(Formatting.GOLD), + EPIC(Formatting.DARK_PURPLE), + RARE(Formatting.BLUE), + UNCOMMON(Formatting.GREEN), + COMMON(Formatting.WHITE); + + public final float r; + public final float g; + public final float b; + + private SkyblockItemRarity(Formatting formatting) { + int rgb = formatting.getColorValue(); + + this.r = ((rgb >> 16) & 0xFF) / 255f; + this.g = ((rgb >> 8) & 0xFF) / 255f; + this.b = (rgb & 0xFF) / 255f; + } +} diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 76b6e768..053e31d2 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -76,6 +76,8 @@ "text.autoconfig.skyblocker.option.general.itemInfoDisplay": "Item Info Display", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo": "Attribute Shard Info", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo.@Tooltip": "Displays the attribute's level as the stack count and the initials of the attribute's name.", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds": "Item Rarity Backgrounds", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds.@Tooltip": "Displays a colored background behind an item, the color represents the item's rarity.", "text.autoconfig.skyblocker.option.general.specialEffects": "Special Effects", "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects": "Rare Dungeon Drop Effects", "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects.@Tooltip": "Adds a special visual effect triggered upon obtaining rare dungeon loot!", diff --git a/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background.png b/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background.png new file mode 100644 index 00000000..fd8e8604 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background.png differ -- cgit