feat: Smooth-ish interpolation of breaking progress
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user