Add fuel durability bar

This commit is contained in:
Linnea Gräf
2024-04-26 10:11:23 +02:00
parent c264ca9e8f
commit 041da7c7d1
6 changed files with 179 additions and 15 deletions

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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>()
}

View File

@@ -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
}

View File

@@ -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),
)
}

View File

@@ -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"
}