aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2025-03-08 14:09:39 +0100
committerLinnea Gräf <nea@nea.moe>2025-03-08 16:01:00 +0100
commitc3d10173d2e309067dd8cfa7909f6907f031436d (patch)
tree37ddd74e5cc28fa69e61f6b3d32cc044ad64e169
parentb4a93bd7515ffd8f1fcbcf5315729ddd36b0166a (diff)
downloadFirmament-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.kt52
-rw-r--r--src/compat/jade/java/moe/nea/firmament/mixins/compat/jade/PatchBreakingBarSpeedJade.java7
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);
+ }
}