diff --git a/src/main/java/dev/isxander/controlify/mixins/feature/rumble/explosion/ClientPacketListenerMixin.java b/src/main/java/dev/isxander/controlify/mixins/feature/rumble/explosion/ClientPacketListenerMixin.java index 0898392..1070b79 100644 --- a/src/main/java/dev/isxander/controlify/mixins/feature/rumble/explosion/ClientPacketListenerMixin.java +++ b/src/main/java/dev/isxander/controlify/mixins/feature/rumble/explosion/ClientPacketListenerMixin.java @@ -23,20 +23,27 @@ public class ClientPacketListenerMixin { @Inject(method = "handleExplosion", at = @At("RETURN")) private void onClientExplosion(ClientboundExplodePacket packet, CallbackInfo ci) { - float distanceSqr = Math.max( - (float)minecraft.player.distanceToSqr(packet.getX(), packet.getY(), packet.getZ()) - - packet.getPower() * packet.getPower(), // power is explosion radius - 0f); - float maxDistanceSqr = 4096f; // client only receives explosion packets within 64 blocks - - float magnitude = 1f - Easings.easeOutQuad(distanceSqr / maxDistanceSqr); + float initialMagnitude = calculateMagnitude(packet); ControlifyApi.get().currentController().rumbleManager().play( RumbleSource.EXPLOSION, BasicRumbleEffect.join( - BasicRumbleEffect.constant(magnitude, magnitude, 4), // initial boom - BasicRumbleEffect.byTime(t -> new RumbleState(0f, magnitude - t*magnitude), 20) // explosion + BasicRumbleEffect.constant(initialMagnitude, initialMagnitude, 4), // initial boom + BasicRumbleEffect.byTime(t -> { + float magnitude = calculateMagnitude(packet); + return new RumbleState(0f, magnitude - t * magnitude); + }, 20) // explosion ) ); } + + private float calculateMagnitude(ClientboundExplodePacket packet) { + float distanceSqr = Math.max( + (float)minecraft.player.distanceToSqr(packet.getX(), packet.getY(), packet.getZ()) + - packet.getPower() * packet.getPower(), // power is explosion radius + 0f); + float maxDistanceSqr = 4096f; // client only receives explosion packets within 64 blocks + + return 1f - Easings.easeOutQuad(distanceSqr / maxDistanceSqr); + } } diff --git a/src/main/java/dev/isxander/controlify/rumble/ContinuousRumbleEffect.java b/src/main/java/dev/isxander/controlify/rumble/ContinuousRumbleEffect.java index c3d38a6..116218f 100644 --- a/src/main/java/dev/isxander/controlify/rumble/ContinuousRumbleEffect.java +++ b/src/main/java/dev/isxander/controlify/rumble/ContinuousRumbleEffect.java @@ -1,5 +1,8 @@ package dev.isxander.controlify.rumble; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.Validate; import java.util.function.Function; @@ -60,6 +63,7 @@ public class ContinuousRumbleEffect implements RumbleEffect { private int priority; private int timeout = -1; private int minTime; + private InWorldProperties inWorldProperties; private Builder() { } @@ -97,11 +101,30 @@ public class ContinuousRumbleEffect implements RumbleEffect { return this; } + public Builder inWorld(Vec3 sourceLocation, float minMagnitude, float maxMagnitude, float minDistance, float maxDistance, Function fallofFunction) { + this.inWorldProperties = new InWorldProperties(sourceLocation, minMagnitude, maxMagnitude, minDistance, maxDistance, fallofFunction); + return this; + } + public ContinuousRumbleEffect build() { Validate.notNull(stateFunction, "stateFunction cannot be null!"); Validate.isTrue(minTime <= timeout || timeout == -1, "the minimum time cannot be greater than the timeout!"); + var stateFunction = this.stateFunction; + if (inWorldProperties != null) + stateFunction = inWorldProperties.modify(stateFunction); + return new ContinuousRumbleEffect(stateFunction, priority, timeout, minTime); } + + private record InWorldProperties(Vec3 sourceLocation, float minMagnitude, float maxMagnitude, float minDistance, float maxDistance, Function fallofFunction) { + private Function modify(Function stateFunction) { + return tick -> { + float distanceSqr = (float) Mth.clamp(Minecraft.getInstance().player.distanceToSqr(sourceLocation), minDistance, maxDistance); + float magnitude = Mth.lerp(1f - fallofFunction.apply(distanceSqr / (maxDistance * maxDistance)), minMagnitude, maxMagnitude); + return stateFunction.apply(tick).mul(magnitude); + }; + } + } } } diff --git a/src/main/java/dev/isxander/controlify/rumble/RumbleState.java b/src/main/java/dev/isxander/controlify/rumble/RumbleState.java index 87e2aba..c7b6329 100644 --- a/src/main/java/dev/isxander/controlify/rumble/RumbleState.java +++ b/src/main/java/dev/isxander/controlify/rumble/RumbleState.java @@ -1,4 +1,7 @@ package dev.isxander.controlify.rumble; public record RumbleState(float strong, float weak) { + public RumbleState mul(float multiplier) { + return new RumbleState(strong * multiplier, weak * multiplier); + } }