forked from Clones/Controlify
more rumble effects
- new continuous rumble - block break rumble - item break rumble - fix damage rumble
This commit is contained in:
@ -0,0 +1,145 @@
|
||||
package dev.isxander.controlify.rumble;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BasicRumbleEffect implements RumbleEffect {
|
||||
private final RumbleState[] keyframes;
|
||||
private int tick = 0;
|
||||
private boolean finished;
|
||||
private int priority = 0;
|
||||
|
||||
public BasicRumbleEffect(RumbleState[] keyframes) {
|
||||
this.keyframes = keyframes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleState nextState() {
|
||||
tick++;
|
||||
if (tick >= keyframes.length)
|
||||
finished = true;
|
||||
|
||||
return keyframes[tick - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public BasicRumbleEffect prioritised(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RumbleState[] states() {
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (BasicRumbleEffect) obj;
|
||||
return Arrays.equals(this.states(), that.states())
|
||||
&& this.priority() == that.priority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(Arrays.hashCode(this.states()), this.priority());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RumbleEffect[" +
|
||||
"states=" + Arrays.toString(this.states()) + ',' +
|
||||
"priority=" + this.priority() + ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rumble effect where the state is determined by the tick.
|
||||
*
|
||||
* @param stateFunction the function that takes a tick and returns the state for that tick.
|
||||
* @param durationTicks how many ticks the effect should last for.
|
||||
*/
|
||||
public static BasicRumbleEffect byTick(Function<Integer, RumbleState> stateFunction, int durationTicks) {
|
||||
RumbleState[] states = new RumbleState[durationTicks];
|
||||
for (int i = 0; i < durationTicks; i++) {
|
||||
states[i] = stateFunction.apply(i);
|
||||
}
|
||||
return new BasicRumbleEffect(states);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rumble effect from a function that takes a time value from 0, start, to 1, end, and returns that tick.
|
||||
*
|
||||
* @param stateFunction the function that takes the time value and returns the state for that tick.
|
||||
* @param durationTicks how many ticks the effect should last for.
|
||||
*/
|
||||
public static BasicRumbleEffect byTime(Function<Float, RumbleState> stateFunction, int durationTicks) {
|
||||
return BasicRumbleEffect.byTick(tick -> stateFunction.apply((float) tick / (float) durationTicks), durationTicks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rumble effect that has a constant state.
|
||||
*
|
||||
* @param strong the strong motor magnitude.
|
||||
* @param weak the weak motor magnitude
|
||||
* @param durationTicks how many ticks the effect should last for.
|
||||
*/
|
||||
public static BasicRumbleEffect constant(float strong, float weak, int durationTicks) {
|
||||
return BasicRumbleEffect.byTick(tick -> new RumbleState(strong, weak), durationTicks);
|
||||
}
|
||||
|
||||
public static BasicRumbleEffect empty(int durationTicks) {
|
||||
return BasicRumbleEffect.byTick(tick -> new RumbleState(0f, 0f), durationTicks);
|
||||
}
|
||||
|
||||
public static BasicRumbleEffect join(BasicRumbleEffect... effects) {
|
||||
int totalTicks = 0;
|
||||
for (BasicRumbleEffect effect : effects) {
|
||||
totalTicks += effect.states().length;
|
||||
}
|
||||
|
||||
RumbleState[] states = new RumbleState[totalTicks];
|
||||
int currentTick = 0;
|
||||
for (BasicRumbleEffect effect : effects) {
|
||||
for (RumbleState state : effect.states()) {
|
||||
states[currentTick] = state;
|
||||
currentTick++;
|
||||
}
|
||||
}
|
||||
|
||||
return new BasicRumbleEffect(states);
|
||||
}
|
||||
|
||||
public BasicRumbleEffect join(BasicRumbleEffect other) {
|
||||
return BasicRumbleEffect.join(this, other);
|
||||
}
|
||||
|
||||
public BasicRumbleEffect repeat(int count) {
|
||||
Validate.isTrue(count > 0, "count must be greater than 0");
|
||||
|
||||
if (count == 1) return this;
|
||||
|
||||
BasicRumbleEffect effect = this;
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
effect = BasicRumbleEffect.join(effect, this);
|
||||
}
|
||||
return effect;
|
||||
}
|
||||
|
||||
public ContinuousRumbleEffect continuous() {
|
||||
int lastIndex = this.states().length - 1;
|
||||
return new ContinuousRumbleEffect(index -> this.states()[index % lastIndex], this.priority());
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package dev.isxander.controlify.rumble;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ContinuousRumbleEffect implements RumbleEffect {
|
||||
private final Function<Integer, RumbleState> stateFunction;
|
||||
private final int priority;
|
||||
private int tick;
|
||||
private boolean stopped;
|
||||
|
||||
public ContinuousRumbleEffect(Function<Integer, RumbleState> stateFunction) {
|
||||
this(stateFunction, 0);
|
||||
}
|
||||
|
||||
public ContinuousRumbleEffect(Function<Integer, RumbleState> stateFunction, int priority) {
|
||||
this.stateFunction = stateFunction;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleState nextState() {
|
||||
tick++;
|
||||
return stateFunction.apply(tick - 1);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
public int currentTick() {
|
||||
return tick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return stopped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return this.priority;
|
||||
}
|
||||
}
|
@ -1,77 +1,9 @@
|
||||
package dev.isxander.controlify.rumble;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
public interface RumbleEffect {
|
||||
RumbleState nextState();
|
||||
|
||||
import java.util.function.Function;
|
||||
boolean isFinished();
|
||||
|
||||
public record RumbleEffect(RumbleState[] states) {
|
||||
/**
|
||||
* Creates a rumble effect where the state is determined by the tick.
|
||||
* @param stateFunction the function that takes a tick and returns the state for that tick.
|
||||
* @param durationTicks how many ticks the effect should last for.
|
||||
*/
|
||||
public static RumbleEffect byTick(Function<Integer, RumbleState> stateFunction, int durationTicks) {
|
||||
RumbleState[] states = new RumbleState[durationTicks];
|
||||
for (int i = 0; i < durationTicks; i++) {
|
||||
states[i] = stateFunction.apply(i);
|
||||
}
|
||||
return new RumbleEffect(states);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rumble effect from a function that takes a time value from 0, start, to 1, end, and returns that tick.
|
||||
* @param stateFunction the function that takes the time value and returns the state for that tick.
|
||||
* @param durationTicks how many ticks the effect should last for.
|
||||
*/
|
||||
public static RumbleEffect byTime(Function<Float, RumbleState> stateFunction, int durationTicks) {
|
||||
return RumbleEffect.byTick(tick -> stateFunction.apply((float) tick / (float) durationTicks), durationTicks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rumble effect that has a constant state.
|
||||
* @param strong the strong motor magnitude.
|
||||
* @param weak the weak motor magnitude
|
||||
* @param durationTicks how many ticks the effect should last for.
|
||||
*/
|
||||
public static RumbleEffect constant(float strong, float weak, int durationTicks) {
|
||||
return RumbleEffect.byTick(tick -> new RumbleState(strong, weak), durationTicks);
|
||||
}
|
||||
|
||||
public static RumbleEffect empty(int durationTicks) {
|
||||
return RumbleEffect.byTick(tick -> new RumbleState(0f, 0f), durationTicks);
|
||||
}
|
||||
|
||||
public static RumbleEffect join(RumbleEffect... effects) {
|
||||
int totalTicks = 0;
|
||||
for (RumbleEffect effect : effects) {
|
||||
totalTicks += effect.states().length;
|
||||
}
|
||||
|
||||
RumbleState[] states = new RumbleState[totalTicks];
|
||||
int currentTick = 0;
|
||||
for (RumbleEffect effect : effects) {
|
||||
for (RumbleState state : effect.states()) {
|
||||
states[currentTick] = state;
|
||||
currentTick++;
|
||||
}
|
||||
}
|
||||
|
||||
return new RumbleEffect(states);
|
||||
}
|
||||
|
||||
public RumbleEffect join(RumbleEffect other) {
|
||||
return RumbleEffect.join(this, other);
|
||||
}
|
||||
|
||||
public RumbleEffect repeat(int count) {
|
||||
Validate.isTrue(count > 0, "count must be greater than 0");
|
||||
|
||||
if (count == 1) return this;
|
||||
|
||||
RumbleEffect effect = this;
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
effect = RumbleEffect.join(effect, this);
|
||||
}
|
||||
return effect;
|
||||
}
|
||||
int priority();
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package dev.isxander.controlify.rumble;
|
||||
public class RumbleManager {
|
||||
private final RumbleCapable controller;
|
||||
private RumbleEffect playingEffect;
|
||||
private int currentPlayingTick;
|
||||
|
||||
public RumbleManager(RumbleCapable controller) {
|
||||
this.controller = controller;
|
||||
@ -14,7 +13,6 @@ public class RumbleManager {
|
||||
return;
|
||||
|
||||
playingEffect = effect;
|
||||
currentPlayingTick = 0;
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
@ -27,20 +25,18 @@ public class RumbleManager {
|
||||
|
||||
controller.setRumble(0f, 0f);
|
||||
playingEffect = null;
|
||||
currentPlayingTick = 0;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if (playingEffect == null)
|
||||
return;
|
||||
|
||||
if (currentPlayingTick >= playingEffect.states().length) {
|
||||
if (playingEffect.isFinished()) {
|
||||
stopCurrentEffect();
|
||||
return;
|
||||
}
|
||||
|
||||
RumbleState state = playingEffect.states()[currentPlayingTick];
|
||||
RumbleState state = playingEffect.nextState();
|
||||
controller.setRumble(state.strong(), state.weak());
|
||||
currentPlayingTick++;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user