diff options
author | Linnea Gräf <nea@nea.moe> | 2024-04-26 10:11:23 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-04-26 10:12:18 +0200 |
commit | 041da7c7d179df01c4048a81ddf40a9f13c3ce77 (patch) | |
tree | 6e6933320c8e96a22bfe433b1e33b184948b8fbd | |
parent | c264ca9e8f9f2b0aed457753c43bb4e25edb0ef1 (diff) | |
download | Firmament-041da7c7d179df01c4048a81ddf40a9f13c3ce77.tar.gz Firmament-041da7c7d179df01c4048a81ddf40a9f13c3ce77.tar.bz2 Firmament-041da7c7d179df01c4048a81ddf40a9f13c3ce77.zip |
Add fuel durability bar
6 files changed, 179 insertions, 15 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java new file mode 100644 index 0000000..f396ce6 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import moe.nea.firmament.util.DurabilityBarEvent; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(DrawContext.class) +public class CustomDurabilityBarPatch { + @WrapOperation( + method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isItemBarVisible()Z") + ) + private boolean onIsItemBarVisible( + ItemStack instance, Operation<Boolean> original, + @Share("barOverride") LocalRef<DurabilityBarEvent.DurabilityBar> barOverride + ) { + if (original.call(instance)) + return true; + DurabilityBarEvent event = new DurabilityBarEvent(instance); + DurabilityBarEvent.Companion.publish(event); + barOverride.set(event.getBarOverride()); + return barOverride.get() != null; + } + + @WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarStep()I")) + private int overrideItemStep( + ItemStack instance, Operation<Integer> original, + @Share("barOverride") LocalRef<DurabilityBarEvent.DurabilityBar> barOverride + ) { + if (barOverride.get() != null) + return Math.round(barOverride.get().getPercentage() * 13); + return original.call(instance); + } + + @WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarColor()I")) + private int overrideItemColor( + ItemStack instance, Operation<Integer> original, + @Share("barOverride") LocalRef<DurabilityBarEvent.DurabilityBar> barOverride + ) { + if (barOverride.get() != null) + return barOverride.get().getColor().getColor(); + return original.call(instance); + } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt b/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt index 4c23e04..24a39e0 100644 --- a/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt +++ b/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt @@ -7,11 +7,10 @@ package moe.nea.firmament.features.mining import java.util.regex.Pattern -import org.intellij.lang.annotations.Language import kotlin.time.Duration -import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import net.minecraft.item.ItemStack +import net.minecraft.util.DyeColor import net.minecraft.util.Hand import net.minecraft.util.Identifier import moe.nea.firmament.events.HudRenderEvent @@ -20,11 +19,19 @@ import moe.nea.firmament.events.SlotClickEvent import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.DurabilityBarEvent import moe.nea.firmament.util.MC +import moe.nea.firmament.util.SHORT_NUMBER_FORMAT +import moe.nea.firmament.util.TIME_PATTERN import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.extraAttributes import moe.nea.firmament.util.item.displayNameAccordingToNbt import moe.nea.firmament.util.item.loreAccordingToNbt +import moe.nea.firmament.util.parseShortNumber +import moe.nea.firmament.util.parseTimePattern import moe.nea.firmament.util.render.RenderCircleProgress +import moe.nea.firmament.util.render.lerp +import moe.nea.firmament.util.toShedaniel import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.useMatch @@ -36,6 +43,7 @@ object PickaxeAbility : FirmamentFeature { object TConfig : ManagedConfig(identifier) { val cooldownEnabled by toggle("ability-cooldown") { true } val cooldownScale by integer("ability-scale", 16, 64) { 16 } + val drillFuelBar by toggle("fuel-bar") { true } } var lobbyJoinTime = TimeMark.farPast() @@ -73,13 +81,36 @@ object PickaxeAbility : FirmamentFeature { abilityOverride = null } ProcessChatEvent.subscribe { - pattern.useMatch(it.unformattedString) { + abilityUsePattern.useMatch(it.unformattedString) { lastUsage[group("name")] = TimeMark.now() } abilitySwitchPattern.useMatch(it.unformattedString) { abilityOverride = group("ability") } } + DurabilityBarEvent.subscribe { + if (!TConfig.drillFuelBar) return@subscribe + val lore = it.item.loreAccordingToNbt + if (lore.lastOrNull()?.value?.unformattedString?.contains("DRILL") != true) return@subscribe + val maxFuel = lore.firstNotNullOfOrNull { + fuelPattern.useMatch( + it.value?.unformattedString ?: return@firstNotNullOfOrNull null + ) { + parseShortNumber(group("maxFuel")) + } + } ?: return@subscribe + val extra = it.item.extraAttributes + if (!extra.contains("drill_fuel")) return@subscribe + val fuel = extra.getInt("drill_fuel") + val percentage = fuel / maxFuel.toFloat() + it.barOverride = DurabilityBarEvent.DurabilityBar( + lerp( + DyeColor.RED.toShedaniel(), + DyeColor.GREEN.toShedaniel(), + percentage + ), percentage + ) + } SlotClickEvent.subscribe { if (MC.screen?.title?.unformattedString == "Heart of the Mountain") { val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return@subscribe @@ -93,7 +124,8 @@ object PickaxeAbility : FirmamentFeature { } } - val pattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!") + val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!") + val fuelPattern = Pattern.compile("Fuel: .*/(?<maxFuel>$SHORT_NUMBER_FORMAT)") data class PickaxeAbilityData( val name: String, @@ -117,21 +149,12 @@ object PickaxeAbility : FirmamentFeature { return PickaxeAbilityData(name, cooldown) } - @Language("RegExp") - val TIME_PATTERN = "[0-9]+[ms]" + val cooldownPattern = Pattern.compile("Cooldown: (?<cooldown>$TIME_PATTERN)") val abilityPattern = Pattern.compile("Ability: (?<name>.*) {2}RIGHT CLICK") val abilitySwitchPattern = Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!") - fun parseTimePattern(text: String): Duration { - val length = text.dropLast(1).toInt() - return when (text.last()) { - 'm' -> length.minutes - 's' -> length.seconds - else -> error("Invalid pattern for time $text") - } - } private fun renderHud(event: HudRenderEvent) { if (!TConfig.cooldownEnabled) return diff --git a/src/main/kotlin/moe/nea/firmament/util/DurabilityBarEvent.kt b/src/main/kotlin/moe/nea/firmament/util/DurabilityBarEvent.kt new file mode 100644 index 0000000..eacf070 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/util/DurabilityBarEvent.kt @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.util + +import me.shedaniel.math.Color +import net.minecraft.item.ItemStack +import moe.nea.firmament.events.FirmamentEvent +import moe.nea.firmament.events.FirmamentEventBus + +data class DurabilityBarEvent( + val item: ItemStack, +) : FirmamentEvent() { + data class DurabilityBar( + val color: Color, + val percentage: Float, + ) + + var barOverride: DurabilityBar? = null + + companion object : FirmamentEventBus<DurabilityBarEvent>() +} diff --git a/src/main/kotlin/moe/nea/firmament/util/regex.kt b/src/main/kotlin/moe/nea/firmament/util/regex.kt index 4cc3f03..9de2b36 100644 --- a/src/main/kotlin/moe/nea/firmament/util/regex.kt +++ b/src/main/kotlin/moe/nea/firmament/util/regex.kt @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> * * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -8,6 +9,10 @@ package moe.nea.firmament.util import java.util.regex.Matcher import java.util.regex.Pattern +import org.intellij.lang.annotations.Language +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds inline fun <T> String.ifMatches(regex: Regex, block: (MatchResult) -> T): T? = regex.matchEntire(this)?.let(block) @@ -16,3 +21,40 @@ inline fun <T> Pattern.useMatch(string: String, block: Matcher.() -> T): T? = matcher(string) .takeIf(Matcher::matches) ?.let(block) + +@Language("RegExp") +val TIME_PATTERN = "[0-9]+[ms]" + +@Language("RegExp") +val SHORT_NUMBER_FORMAT = "[0-9]+(?:,[0-9]+)*(?:\\.[0-9]+)?[kKmMbB]?" + + +val siScalars = mapOf( + 'k' to 1_000.0, + 'K' to 1_000.0, + 'm' to 1_000_000.0, + 'M' to 1_000_000.0, + 'b' to 1_000_000_000.0, + 'B' to 1_000_000_000.0, +) + +fun parseTimePattern(text: String): Duration { + val length = text.dropLast(1).toInt() + return when (text.last()) { + 'm' -> length.minutes + 's' -> length.seconds + else -> error("Invalid pattern for time $text") + } +} + +fun parseShortNumber(string: String): Double { + var k = string.replace(",", "") + val scalar = k.last() + var scalarMultiplier = siScalars[scalar] + if (scalarMultiplier == null) { + scalarMultiplier = 1.0 + } else { + k = k.dropLast(1) + } + return k.toDouble() * scalarMultiplier +} diff --git a/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt b/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt index a979f8d..66899ce 100644 --- a/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt +++ b/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt @@ -6,6 +6,8 @@ package moe.nea.firmament.util.render +import me.shedaniel.math.Color + val pi = Math.PI val tau = Math.PI * 2 fun lerpAngle(a: Float, b: Float, progress: Float): Float { @@ -17,7 +19,20 @@ fun lerpAngle(a: Float, b: Float, progress: Float): Float { fun lerp(a: Float, b: Float, progress: Float): Float { return a + (b - a) * progress } +fun lerp(a: Int, b: Int, progress: Float): Int { + return (a + (b - a) * progress).toInt() +} fun ilerp(a: Float, b: Float, value: Float): Float { return (value - a) / (b - a) } + +fun lerp(a: Color, b: Color, progress: Float): Color { + return Color.ofRGBA( + lerp(a.red, b.red, progress), + lerp(a.green, b.green, progress), + lerp(a.blue, b.blue, progress), + lerp(a.alpha, b.alpha, progress), + ) +} + diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index 37df38e..cdcaea2 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -167,5 +167,6 @@ "firmament.quick-commands.join.unknown-catacombs": "Unknown catacombs floor %s", "firmament.config.pickaxe-info": "Pickaxes", "firmament.config.pickaxe-info.ability-cooldown": "Pickaxe Ability Cooldown", - "firmament.config.pickaxe-info.ability-scale": "Ability Cooldown Scale" + "firmament.config.pickaxe-info.ability-scale": "Ability Cooldown Scale", + "firmament.config.pickaxe-info.fuel-bar": "Drill Fuel Durability Bar" } |