diff options
Diffstat (limited to 'src/main/java')
15 files changed, 348 insertions, 79 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java index cda0b823..6f4276e9 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java +++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java @@ -4,6 +4,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; import me.xmrvizzy.skyblocker.skyblock.*; +import me.xmrvizzy.skyblocker.skyblock.item.ItemCooldowns; import me.xmrvizzy.skyblocker.skyblock.dungeon.*; import me.xmrvizzy.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; import me.xmrvizzy.skyblocker.skyblock.dwarven.DwarvenHud; @@ -78,6 +79,7 @@ public class SkyblockerMod implements ClientModInitializer { Relics.init(); BackpackPreview.init(); QuickNav.init(); + ItemCooldowns.init(); DwarvenHud.init(); ChatMessageListener.init(); Shortcuts.init(); diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java index a32dcbfe..8e014124 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java @@ -177,6 +177,9 @@ public class SkyblockerConfig { public FairySouls fairySouls = new FairySouls(); @SerialEntry + public ItemCooldown itemCooldown = new ItemCooldown(); + + @SerialEntry public Shortcuts shortcuts = new Shortcuts(); @SerialEntry @@ -313,6 +316,11 @@ public class SkyblockerConfig { public boolean highlightOnlyNearbySouls = false; } + public static class ItemCooldown { + @SerialEntry + public boolean enableItemCooldowns = true; + } + public static class Shortcuts { @SerialEntry public boolean enableShortcuts = true; 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 e5b7d92d..318d579c 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/categories/GeneralCategory.java @@ -201,6 +201,19 @@ public class GeneralCategory { .build()) .build()) + //Item Cooldown + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemCooldown")) + .collapsed(true) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemCooldown.enableItemCooldowns")) + .binding(defaults.general.itemCooldown.enableItemCooldowns, + () -> config.general.itemCooldown.enableItemCooldowns, + newValue -> config.general.itemCooldown.enableItemCooldowns = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) + //Shortcuts .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.shortcuts")) diff --git a/src/main/java/me/xmrvizzy/skyblocker/events/ClientPlayerBlockBreakEvent.java b/src/main/java/me/xmrvizzy/skyblocker/events/ClientPlayerBlockBreakEvent.java new file mode 100644 index 00000000..76298612 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/events/ClientPlayerBlockBreakEvent.java @@ -0,0 +1,23 @@ +package me.xmrvizzy.skyblocker.events; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +// Fabric API currently doesn't have an event for this +public class ClientPlayerBlockBreakEvent { + public static final Event<AfterBlockBreak> AFTER = EventFactory.createArrayBacked(AfterBlockBreak.class, + (listeners) -> (world, player, pos, state) -> { + for (AfterBlockBreak listener : listeners) { + listener.afterBlockBreak(world, player, pos, state); + } + }); + + @FunctionalInterface + public interface AfterBlockBreak { + void afterBlockBreak(World world, PlayerEntity player, BlockPos pos, BlockState state); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/SkyblockEvents.java b/src/main/java/me/xmrvizzy/skyblocker/events/SkyblockEvents.java index 2dd83ffa..477d68b0 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/utils/SkyblockEvents.java +++ b/src/main/java/me/xmrvizzy/skyblocker/events/SkyblockEvents.java @@ -1,4 +1,4 @@ -package me.xmrvizzy.skyblocker.utils; +package me.xmrvizzy.skyblocker.events; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerInteractionManagerMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerInteractionManagerMixin.java new file mode 100644 index 00000000..3963f9d3 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerInteractionManagerMixin.java @@ -0,0 +1,27 @@ +package me.xmrvizzy.skyblocker.mixin; + +import me.xmrvizzy.skyblocker.events.ClientPlayerBlockBreakEvent; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(ClientPlayerInteractionManager.class) +public class ClientPlayerInteractionManagerMixin { + @Shadow + @Final + private MinecraftClient client; + + @Inject(method = "breakBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;onBroken(Lnet/minecraft/world/WorldAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V"), locals = LocalCapture.CAPTURE_FAILHARD) + private void skyblocker$onBlockBroken(BlockPos pos, CallbackInfoReturnable<Boolean> cir, World world, BlockState blockState) { + ClientPlayerBlockBreakEvent.AFTER.invoker().afterBlockBreak(world, this.client.player, pos, blockState); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/DrawContextMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/DrawContextMixin.java index 356095ab..257a5127 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/DrawContextMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/DrawContextMixin.java @@ -1,33 +1,27 @@ package me.xmrvizzy.skyblocker.mixin; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.ref.LocalRef; -import com.mojang.blaze3d.systems.RenderSystem; - import dev.cbyrne.betterinject.annotations.Arg; import dev.cbyrne.betterinject.annotations.Inject; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; import me.xmrvizzy.skyblocker.skyblock.item.AttributeShards; +import me.xmrvizzy.skyblocker.skyblock.item.ItemCooldowns; import me.xmrvizzy.skyblocker.utils.ItemUtils; import me.xmrvizzy.skyblocker.utils.Utils; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.RenderLayer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.Formatting; -import net.minecraft.util.math.ColorHelper; - 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.injection.At; -import java.awt.Color; -import java.util.regex.Pattern; - @Mixin(DrawContext.class) public abstract class DrawContextMixin { @Shadow @@ -35,69 +29,9 @@ public abstract class DrawContextMixin { private MatrixStack matrices; @Shadow - public abstract void fill(RenderLayer layer, int x1, int x2, int y1, int y2, int color); - - @Shadow public abstract int drawText(TextRenderer textRenderer, @Nullable String text, int x, int y, int color, boolean shadow); @Inject(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", at = @At("HEAD")) - public void skyblocker$renderItemBar(@Arg ItemStack stack, @Arg(ordinal = 0) int x, @Arg(ordinal = 1) int y) { - if (!Utils.isOnSkyblock() || !SkyblockerConfigManager.get().locations.dwarvenMines.enableDrillFuel || stack.isEmpty()) { - return; - } - - NbtCompound tag = stack.getNbt(); - if (tag == null || !tag.contains("ExtraAttributes")) { - return; - } - - NbtCompound extraAttributes = tag.getCompound("ExtraAttributes"); - if (!extraAttributes.contains("drill_fuel") && !extraAttributes.getString("id").equals("PICKONIMBUS")) { - return; - } - matrices.push(); - matrices.translate(0f, 0f, 200f); - RenderSystem.disableDepthTest(); - - float current = 0.0F; - float max = 0.0F; - String clearFormatting = ""; - - for (String line : ItemUtils.getTooltipStrings(stack)) { - clearFormatting = Formatting.strip(line); - if (line.contains("Fuel: ")) { - if (clearFormatting != null) { - String clear = Pattern.compile("[^0-9 /]").matcher(clearFormatting).replaceAll("").trim(); - String[] split = clear.split("/"); - current = Integer.parseInt(split[0]); - max = Integer.parseInt(split[1]) * 1000; - } - break; - } else if (line.contains("uses.")) { - if (clearFormatting != null) { - int startIndex = clearFormatting.lastIndexOf("after") + 6; - int endIndex = clearFormatting.indexOf("uses", startIndex); - if (startIndex >= 0 && endIndex > startIndex) { - String usesString = clearFormatting.substring(startIndex, endIndex).trim(); - current = Integer.parseInt(usesString); - max = 5000; - } - } - break; - } - } - - float hue = Math.max(0.0F, 1.0F - (max - current) / max); - int width = Math.round(current / max * 13.0F); - Color color = Color.getHSBColor(hue / 3.0F, 1.0F, 1.0F); - this.fill(RenderLayer.getGuiOverlay(), x + 2, y + 13, x + 15, y + 15, 0xFF000000); - this.fill(RenderLayer.getGuiOverlay(), x + 2, y + 13, x + 2 + width, y + 14, ColorHelper.Argb.getArgb(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue())); - - matrices.pop(); - RenderSystem.enableDepthTest(); - } - - @Inject(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", at = @At("HEAD")) private void skyblocker$renderAttributeShardDisplay(@Arg TextRenderer textRenderer, @Arg ItemStack stack, @Arg(ordinal = 0) int x, @Arg(ordinal = 1) int y, @Local(argsOnly = true) LocalRef<String> countOverride) { if (!SkyblockerConfigManager.get().general.itemInfoDisplay.attributeShardInfo) return; @@ -130,4 +64,10 @@ public abstract class DrawContextMixin { } } } -}
\ No newline at end of file + + @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) { + return Utils.isOnSkyblock() && ItemCooldowns.isOnCooldown(stack) ? ItemCooldowns.getItemCooldownEntry(stack).getRemainingCooldownPercent() : cooldownProgress; + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java index 0425b0b8..3376907b 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java @@ -1,19 +1,24 @@ package me.xmrvizzy.skyblocker.mixin; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; import me.xmrvizzy.skyblocker.SkyblockerMod; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; import me.xmrvizzy.skyblocker.skyblock.FancyStatusBars; import me.xmrvizzy.skyblocker.skyblock.HotbarSlotLock; +import me.xmrvizzy.skyblocker.skyblock.item.ItemCooldowns; 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.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -34,6 +39,10 @@ public abstract class InGameHudMixin { @Shadow private int scaledWidth; + @Shadow + @Final + private MinecraftClient client; + @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) { if (Utils.isOnSkyblock()) { @@ -64,9 +73,21 @@ public abstract class InGameHudMixin { if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.bars.enableBars && !Utils.isInTheRift()) ci.cancel(); } - + @Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"), cancellable = true) private void skyblocker$dontRenderStatusEffects(CallbackInfo ci) { if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.hideStatusEffectOverlay) ci.cancel(); } -}
\ No newline at end of file + + @ModifyExpressionValue(method = "renderCrosshair", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getAttackCooldownProgress(F)F")) + private float skyblocker$modifyAttackIndicatorCooldown(float cooldownProgress) { + if (Utils.isOnSkyblock() && client.player != null) { + ItemStack stack = client.player.getMainHandStack(); + if (ItemCooldowns.isOnCooldown(stack)) { + return ItemCooldowns.getItemCooldownEntry(stack).getRemainingCooldownPercent(); + } + } + + return cooldownProgress; + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemMixin.java new file mode 100644 index 00000000..99d42640 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemMixin.java @@ -0,0 +1,22 @@ +package me.xmrvizzy.skyblocker.mixin; + +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +@Mixin(Item.class) +public abstract class ItemMixin { + @WrapOperation( + method = {"getItemBarColor", "getItemBarStep"}, + at = @At(value = "FIELD", target = "Lnet/minecraft/item/Item;maxDamage:I", opcode = Opcodes.GETFIELD) + ) + private int skyblocker$handlePickoDrillBar(Item item, Operation<Integer> original, ItemStack stack) { + return stack.getMaxDamage(); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemStackMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemStackMixin.java index 063c048e..280c01ba 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemStackMixin.java +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/ItemStackMixin.java @@ -8,6 +8,8 @@ import org.spongepowered.asm.mixin.injection.At; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; +import me.xmrvizzy.skyblocker.utils.ItemUtils; +import me.xmrvizzy.skyblocker.utils.ItemUtils.Durability; import me.xmrvizzy.skyblocker.utils.Utils; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; @@ -30,4 +32,31 @@ public abstract class ItemStackMixin { return original; } + + @ModifyReturnValue(method = "getDamage", at = @At("RETURN")) + private int skyblocker$handleDamage(int original) { + Durability dur = ItemUtils.getDurability((ItemStack) (Object) this); + if (dur != null) { + return dur.max() - dur.current(); + } + return original; + } + + @ModifyReturnValue(method = "getMaxDamage", at = @At("RETURN")) + private int skyblocker$handleMaxDamage(int original) { + Durability dur = ItemUtils.getDurability((ItemStack) (Object) this); + if (dur != null) { + return dur.max(); + } + return original; + } + + @ModifyReturnValue(method = "isDamageable", at = @At("RETURN")) + private boolean skyblocker$handleDamageable(boolean original) { + Durability dur = ItemUtils.getDurability((ItemStack) (Object) this); + if (dur != null) { + return true; + } + return original; + } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/CustomArmorTrims.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/CustomArmorTrims.java index dba066a5..6eb0623c 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/CustomArmorTrims.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/CustomArmorTrims.java @@ -8,7 +8,7 @@ import dev.isxander.yacl3.config.v2.api.SerialEntry; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; -import me.xmrvizzy.skyblocker.utils.SkyblockEvents; +import me.xmrvizzy.skyblocker.events.SkyblockEvents; import me.xmrvizzy.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemCooldowns.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemCooldowns.java new file mode 100644 index 00000000..dbe0c16e --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/ItemCooldowns.java @@ -0,0 +1,115 @@ +package me.xmrvizzy.skyblocker.skyblock.item; + +import com.google.common.collect.ImmutableList; +import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; +import me.xmrvizzy.skyblocker.events.ClientPlayerBlockBreakEvent; +import me.xmrvizzy.skyblocker.utils.ItemUtils; +import net.fabricmc.fabric.api.event.player.UseItemCallback; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.HashMap; +import java.util.Map; + +public class ItemCooldowns { + private static final String JUNGLE_AXE_ID = "JUNGLE_AXE"; + private static final String TREECAPITATOR_ID = "TREECAPITATOR_AXE"; + private static final String GRAPPLING_HOOK_ID = "GRAPPLING_HOOK"; + private static final ImmutableList<String> BAT_ARMOR_IDS = ImmutableList.of("BAT_PERSON_HELMET", "BAT_PERSON_CHESTPLATE", "BAT_PERSON_LEGGINGS", "BAT_PERSON_BOOTS"); + + private static final Map<String, CooldownEntry> ITEM_COOLDOWNS = new HashMap<>(); + + public static void init() { + ClientPlayerBlockBreakEvent.AFTER.register(ItemCooldowns::afterBlockBreak); + UseItemCallback.EVENT.register(ItemCooldowns::onItemInteract); + } + + public static void afterBlockBreak(World world, PlayerEntity player, BlockPos pos, BlockState state) { + if (!SkyblockerConfigManager.get().general.itemCooldown.enableItemCooldowns) return; + + String usedItemId = ItemUtils.getItemId(player.getMainHandStack()); + if (usedItemId == null) return; + + if (state.isIn(BlockTags.LOGS)) { + if (usedItemId.equals(JUNGLE_AXE_ID)) { + if (!isOnCooldown(JUNGLE_AXE_ID)) { + ITEM_COOLDOWNS.put(JUNGLE_AXE_ID, new CooldownEntry(2000)); + } + } else if (usedItemId.equals(TREECAPITATOR_ID)) { + if (!isOnCooldown(TREECAPITATOR_ID)) { + ITEM_COOLDOWNS.put(TREECAPITATOR_ID, new CooldownEntry(2000)); + } + } + } + } + + private static TypedActionResult<ItemStack> onItemInteract(PlayerEntity player, World world, Hand hand) { + if (!SkyblockerConfigManager.get().general.itemCooldown.enableItemCooldowns) return TypedActionResult.pass(ItemStack.EMPTY); + + String usedItemId = ItemUtils.getItemId(player.getMainHandStack()); + if (usedItemId != null && usedItemId.equals(GRAPPLING_HOOK_ID) && player.fishHook != null) { + if (!isOnCooldown(GRAPPLING_HOOK_ID) && !isWearingBatArmor(player)) { + ITEM_COOLDOWNS.put(GRAPPLING_HOOK_ID, new CooldownEntry(2000)); + } + } + + return TypedActionResult.pass(ItemStack.EMPTY); + } + + public static boolean isOnCooldown(ItemStack itemStack) { + return isOnCooldown(ItemUtils.getItemId(itemStack)); + } + + private static boolean isOnCooldown(String itemId) { + if (ITEM_COOLDOWNS.containsKey(itemId)) { + CooldownEntry cooldownEntry = ITEM_COOLDOWNS.get(itemId); + if (cooldownEntry.isOnCooldown()) { + return true; + } else { + ITEM_COOLDOWNS.remove(itemId); + return false; + } + } + + return false; + } + + public static CooldownEntry getItemCooldownEntry(ItemStack itemStack) { + return ITEM_COOLDOWNS.get(ItemUtils.getItemId(itemStack)); + } + + private static boolean isWearingBatArmor(PlayerEntity player) { + for (ItemStack stack : player.getArmorItems()) { + String itemId = ItemUtils.getItemId(stack); + if (!BAT_ARMOR_IDS.contains(itemId)) { + return false; + } + } + return true; + } + + public record CooldownEntry(int cooldown, long startTime) { + public CooldownEntry(int cooldown) { + this(cooldown, System.currentTimeMillis()); + } + + public boolean isOnCooldown() { + return (this.startTime + this.cooldown) > System.currentTimeMillis(); + } + + public long getRemainingCooldown() { + long time = (this.startTime + this.cooldown) - System.currentTimeMillis(); + return Math.max(time, 0); + } + + public float getRemainingCooldownPercent() { + return this.isOnCooldown() ? (float) this.getRemainingCooldown() / cooldown : 0.0f; + } + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/ItemUtils.java b/src/main/java/me/xmrvizzy/skyblocker/utils/ItemUtils.java index 5c12b777..b8192b45 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/utils/ItemUtils.java +++ b/src/main/java/me/xmrvizzy/skyblocker/utils/ItemUtils.java @@ -1,11 +1,15 @@ package me.xmrvizzy.skyblocker.utils; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; import net.minecraft.client.MinecraftClient; import net.minecraft.client.item.TooltipContext; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.StringNbtReader; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -33,6 +37,53 @@ public class ItemUtils { return list; } + @Nullable + public static Durability getDurability(ItemStack stack) { + if (!Utils.isOnSkyblock() || !SkyblockerConfigManager.get().locations.dwarvenMines.enableDrillFuel || stack.isEmpty()) { + return null; + } + + NbtCompound tag = stack.getNbt(); + if (tag == null || !tag.contains("ExtraAttributes")) { + return null; + } + + NbtCompound extraAttributes = tag.getCompound("ExtraAttributes"); + if (!extraAttributes.contains("drill_fuel") && !extraAttributes.getString("id").equals("PICKONIMBUS")) { + return null; + } + + int current = 0; + int max = 0; + String clearFormatting; + + for (String line : ItemUtils.getTooltipStrings(stack)) { + clearFormatting = Formatting.strip(line); + if (line.contains("Fuel: ")) { + if (clearFormatting != null) { + String clear = Pattern.compile("[^0-9 /]").matcher(clearFormatting).replaceAll("").trim(); + String[] split = clear.split("/"); + current = Integer.parseInt(split[0]); + max = Integer.parseInt(split[1]) * 1000; + return new Durability(current, max); + } + } else if (line.contains("uses.")) { + if (clearFormatting != null) { + int startIndex = clearFormatting.lastIndexOf("after") + 6; + int endIndex = clearFormatting.indexOf("uses", startIndex); + if (startIndex >= 0 && endIndex > startIndex) { + String usesString = clearFormatting.substring(startIndex, endIndex).trim(); + current = Integer.parseInt(usesString); + max = 5000; + } + return new Durability(current, max); + } + } + } + + return null; + } + 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=\"}]}}}}")); @@ -40,4 +91,21 @@ public class ItemUtils { throw new RuntimeException(e); } } + + public static String getItemId(ItemStack itemStack) { + if (itemStack == null) return null; + + NbtCompound nbt = itemStack.getNbt(); + if (nbt != null && nbt.contains("ExtraAttributes")) { + NbtCompound extraAttributes = nbt.getCompound("ExtraAttributes"); + if (extraAttributes.contains("id")) { + return extraAttributes.getString("id"); + } + } + + return null; + } + + public record Durability(int current, int max) { + } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java b/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java index f21307b7..cee2f2ad 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java +++ b/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import me.xmrvizzy.skyblocker.events.SkyblockEvents; import me.xmrvizzy.skyblocker.skyblock.item.PriceInfoTooltip; import me.xmrvizzy.skyblocker.skyblock.rift.TheRift; import me.xmrvizzy.skyblocker.utils.scheduler.MessageScheduler; diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/discord/DiscordRPCManager.java b/src/main/java/me/xmrvizzy/skyblocker/utils/discord/DiscordRPCManager.java index 39d91bba..6196fec0 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/utils/discord/DiscordRPCManager.java +++ b/src/main/java/me/xmrvizzy/skyblocker/utils/discord/DiscordRPCManager.java @@ -2,7 +2,7 @@ package me.xmrvizzy.skyblocker.utils.discord; import me.xmrvizzy.skyblocker.config.SkyblockerConfigManager; -import me.xmrvizzy.skyblocker.utils.SkyblockEvents; +import me.xmrvizzy.skyblocker.events.SkyblockEvents; import me.xmrvizzy.skyblocker.utils.Utils; import meteordevelopment.discordipc.DiscordIPC; import meteordevelopment.discordipc.RichPresence; @@ -34,7 +34,7 @@ public class DiscordRPCManager { } /** - * Checks the {@link SkyblockerConfigManager.RichPresence#customMessage custom message}, updates {@link #cycleCount} if enabled, and updates rich presence. + * Checks the {@link me.xmrvizzy.skyblocker.config.SkyblockerConfig.RichPresence#customMessage custom message}, updates {@link #cycleCount} if enabled, and updates rich presence. */ public static void updateDataAndPresence() { // If the custom message is empty, discord will keep the last message, this is can serve as a default if the user doesn't want a custom message @@ -58,16 +58,16 @@ public class DiscordRPCManager { * <p> * When the {@link #updateTask previous update} does not exist or {@link CompletableFuture#isDone() has completed}: * <p> - * Connects to discord if {@link SkyblockerConfigManager.RichPresence#enableRichPresence rich presence is enabled}, + * Connects to discord if {@link me.xmrvizzy.skyblocker.config.SkyblockerConfig.RichPresence#enableRichPresence rich presence is enabled}, * the player {@link Utils#isOnSkyblock() is on Skyblock}, and {@link DiscordIPC#isConnected() discord is not already connected}. - * Updates the presence if {@link SkyblockerConfigManager.RichPresence#enableRichPresence rich presence is enabled} + * Updates the presence if {@link me.xmrvizzy.skyblocker.config.SkyblockerConfig.RichPresence#enableRichPresence rich presence is enabled} * and the player {@link Utils#isOnSkyblock() is on Skyblock}. - * Stops the connection if {@link SkyblockerConfigManager.RichPresence#enableRichPresence rich presence is disabled} + * Stops the connection if {@link me.xmrvizzy.skyblocker.config.SkyblockerConfig.RichPresence#enableRichPresence rich presence is disabled} * or the player {@link Utils#isOnSkyblock() is not on Skyblock} and {@link DiscordIPC#isConnected() discord is connected}. * Saves the update task in {@link #updateTask} * * @param initialization whether this is the first time the presence is being updates. If {@code true}, a message will be logged - * if {@link SkyblockerConfigManager.RichPresence#enableRichPresence rich presence is disabled}. + * if {@link me.xmrvizzy.skyblocker.config.SkyblockerConfig.RichPresence#enableRichPresence rich presence is disabled}. */ private static void initAndUpdatePresence(boolean initialization) { if (updateTask == null || updateTask.isDone()) { |