diff options
author | Linnea Gräf <nea@nea.moe> | 2025-03-08 14:09:39 +0100 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2025-03-08 16:01:00 +0100 |
commit | c3d10173d2e309067dd8cfa7909f6907f031436d (patch) | |
tree | 37ddd74e5cc28fa69e61f6b3d32cc044ad64e169 | |
parent | b4a93bd7515ffd8f1fcbcf5315729ddd36b0166a (diff) | |
download | Firmament-c3d10173d2e309067dd8cfa7909f6907f031436d.tar.gz Firmament-c3d10173d2e309067dd8cfa7909f6907f031436d.tar.bz2 Firmament-c3d10173d2e309067dd8cfa7909f6907f031436d.zip |
feat: Smooth-ish interpolation of breaking progress
-rw-r--r-- | src/compat/jade/java/moe/nea/firmament/compat/jade/CustomMiningHardnessProvider.kt | 52 | ||||
-rw-r--r-- | src/compat/jade/java/moe/nea/firmament/mixins/compat/jade/PatchBreakingBarSpeedJade.java | 7 |
2 files changed, 53 insertions, 6 deletions
diff --git a/src/compat/jade/java/moe/nea/firmament/compat/jade/CustomMiningHardnessProvider.kt b/src/compat/jade/java/moe/nea/firmament/compat/jade/CustomMiningHardnessProvider.kt index 7864339..7f08bea 100644 --- a/src/compat/jade/java/moe/nea/firmament/compat/jade/CustomMiningHardnessProvider.kt +++ b/src/compat/jade/java/moe/nea/firmament/compat/jade/CustomMiningHardnessProvider.kt @@ -4,11 +4,15 @@ import snownee.jade.api.BlockAccessor import snownee.jade.api.IBlockComponentProvider import snownee.jade.api.ITooltip import snownee.jade.api.config.IPluginConfig +import kotlin.time.DurationUnit import net.minecraft.block.BlockState import net.minecraft.util.Identifier import net.minecraft.util.math.BlockPos import moe.nea.firmament.Firmament +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.TickEvent import moe.nea.firmament.util.MC +import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.tr object CustomMiningHardnessProvider : IBlockComponentProvider { @@ -29,13 +33,35 @@ object CustomMiningHardnessProvider : IBlockComponentProvider { data class BreakingInfo( val blockPos: BlockPos, val stage: Int, val state: BlockState?, + val ts: TimeMark = TimeMark.now() ) + var previousBreakingInfo: BreakingInfo? = null var currentBreakingInfo: BreakingInfo? = null + @Subscribe + fun clearInfoOnStopBreaking(event: TickEvent) { + val isBreakingBlock = MC.interactionManager?.isBreakingBlock ?: false + if (!isBreakingBlock) { + previousBreakingInfo = null + currentBreakingInfo = null + } + } + @JvmStatic fun setBreakingInfo(blockPos: BlockPos, stage: Int) { - currentBreakingInfo = BreakingInfo(blockPos.toImmutable(), stage, MC.world?.getBlockState(blockPos)) + previousBreakingInfo = currentBreakingInfo + val state = MC.world?.getBlockState(blockPos) + if (previousBreakingInfo?.let { it.state != state || it.blockPos != blockPos } ?: false) + previousBreakingInfo == null + currentBreakingInfo = BreakingInfo(blockPos.toImmutable(), stage, state) + // For some reason hypixel initially sends a stage 10 packet, and then fixes it up with a stage 0 packet. + // Ignore the stage 10 packet if we dont have any previous packets for this block. + // This could in theory still have issues if someone perfectly stops breaking a block the tick it finishes and then does not break another block until it respawns, but i deem that to be too much of an edge case. + if (stage == 10 && previousBreakingInfo == null) { + previousBreakingInfo = null + currentBreakingInfo = null + } } @JvmStatic @@ -45,10 +71,26 @@ object CustomMiningHardnessProvider : IBlockComponentProvider { val info = currentBreakingInfo if (info?.blockPos != pos || info.state != MC.world?.getBlockState(pos)) { currentBreakingInfo = null - return 0F + previousBreakingInfo = null + return original } - // TODO: use linear extrapolation to guess how quickly this progresses between stages. - // This would only be possible after one stage, but should make the remaining stages a bit smoother - return info.stage / 10F + // TODO: improve this interpolation to work across all stages, to alleviate some of the jittery bar. + // Maybe introduce a proper mining API that tracks the actual progress with some sort of FSM + val interpolatedStage = previousBreakingInfo?.let { prev -> + val timeBetweenTicks = (info.ts - prev.ts).toDouble(DurationUnit.SECONDS) + val stagesPerUpdate = (info.stage - prev.stage).toDouble() + if (stagesPerUpdate < 1) return@let null + val stagesPerSecond = stagesPerUpdate / timeBetweenTicks + info.stage + (info.ts.passedTime().toDouble(DurationUnit.SECONDS) * stagesPerSecond) + .coerceAtMost(stagesPerUpdate) + }?.toFloat() + val stage = interpolatedStage ?: info.stage.toFloat() + return stage / 10F + } + + @JvmStatic + fun replaceBlockBreakSpeed(original: Float): Float { + if (isOnMiningIsland()) return 0F + return original } } diff --git a/src/compat/jade/java/moe/nea/firmament/mixins/compat/jade/PatchBreakingBarSpeedJade.java b/src/compat/jade/java/moe/nea/firmament/mixins/compat/jade/PatchBreakingBarSpeedJade.java index f85c301..203f7e4 100644 --- a/src/compat/jade/java/moe/nea/firmament/mixins/compat/jade/PatchBreakingBarSpeedJade.java +++ b/src/compat/jade/java/moe/nea/firmament/mixins/compat/jade/PatchBreakingBarSpeedJade.java @@ -16,5 +16,10 @@ public class PatchBreakingBarSpeedJade { private static float replaceBlockBreakingProgress(float original) { return CustomMiningHardnessProvider.replaceBreakProgress(original); } - // TODO: given the inherent roughness of the server provided stages, i don't feel the need to also patch the accesses to the delta provided by the block state. if i ever get around to adding the linear extrapolation, i should also patch that extrapolation to use the better one provided by the server stages. + + @ModifyExpressionValue(method = "drawBreakingProgress", + at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;calcBlockBreakingDelta(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;)F")) + private static float replacePlayerSpecificBreakingProgress(float original) { + return CustomMiningHardnessProvider.replaceBlockBreakSpeed(original); + } } |