forked from Clones/Controlify
✏️ Make rumble effects merge together rather than pausing one another when playing in unison (plays the stronger magnitude for both motors)
This commit is contained in:
@ -8,6 +8,8 @@ import dev.isxander.controlify.ControllerManager;
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
import dev.isxander.controlify.rumble.RumbleSource;
|
||||
import dev.isxander.controlify.rumble.RumbleState;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@ -128,6 +130,14 @@ public abstract class AbstractController<S extends ControllerState, C extends Co
|
||||
return Optional.of(hidInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleState applyRumbleSourceStrength(RumbleState state, RumbleSource source) {
|
||||
float strengthMod = config().getRumbleStrength(source);
|
||||
if (source != RumbleSource.MASTER)
|
||||
strengthMod *= config().getRumbleStrength(RumbleSource.MASTER);
|
||||
return state.mul(strengthMod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -7,6 +7,7 @@ import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
import dev.isxander.controlify.rumble.RumbleManager;
|
||||
import dev.isxander.controlify.rumble.RumbleSource;
|
||||
import dev.isxander.controlify.rumble.RumbleState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.Optional;
|
||||
@ -54,7 +55,7 @@ public interface Controller<S extends ControllerState, C extends ControllerConfi
|
||||
private final ControllerBindings<ControllerState> bindings = new ControllerBindings<>(this);
|
||||
private final RumbleManager rumbleManager = new RumbleManager(new RumbleCapable() {
|
||||
@Override
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -62,6 +63,11 @@ public interface Controller<S extends ControllerState, C extends ControllerConfi
|
||||
public boolean supportsRumble() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleState applyRumbleSourceStrength(RumbleState state, RumbleSource source) {
|
||||
return state;
|
||||
}
|
||||
});
|
||||
private final ControllerConfig config = new ControllerConfig() {
|
||||
@Override
|
||||
|
@ -8,7 +8,6 @@ import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.debug.DebugProperties;
|
||||
import dev.isxander.controlify.driver.*;
|
||||
import dev.isxander.controlify.rumble.RumbleManager;
|
||||
import dev.isxander.controlify.rumble.RumbleSource;
|
||||
import dev.isxander.controlify.utils.ControllerUtils;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@ -116,16 +115,9 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude) {
|
||||
if (!supportsRumble() || !config().allowVibrations) return false;
|
||||
|
||||
var strengthMod = config().getRumbleStrength(source);
|
||||
if (source != RumbleSource.MASTER)
|
||||
strengthMod *= config().getRumbleStrength(RumbleSource.MASTER);
|
||||
|
||||
strongMagnitude *= strengthMod;
|
||||
weakMagnitude *= strengthMod;
|
||||
|
||||
return drivers.rumbleDriver().rumble(Math.min(strongMagnitude, 1), Math.min(weakMagnitude, 1));
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import dev.isxander.controlify.controller.joystick.mapping.RPJoystickMapping;
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
import dev.isxander.controlify.rumble.RumbleManager;
|
||||
import dev.isxander.controlify.rumble.RumbleSource;
|
||||
import dev.isxander.controlify.rumble.RumbleState;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
@ -143,7 +144,7 @@ public class CompoundJoystickController implements JoystickController<JoystickCo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -152,6 +153,11 @@ public class CompoundJoystickController implements JoystickController<JoystickCo
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleState applyRumbleSourceStrength(RumbleState state, RumbleSource source) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleManager rumbleManager() {
|
||||
return this.rumbleManager;
|
||||
|
@ -91,16 +91,9 @@ public class SingleJoystickController extends AbstractController<JoystickState,
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude) {
|
||||
if (!supportsRumble()) return false;
|
||||
|
||||
var strengthMod = config().getRumbleStrength(source);
|
||||
if (source != RumbleSource.MASTER)
|
||||
strengthMod *= config().getRumbleStrength(RumbleSource.MASTER);
|
||||
|
||||
strongMagnitude *= strengthMod;
|
||||
weakMagnitude *= strengthMod;
|
||||
|
||||
// the duration doesn't matter because we are not updating the joystick state,
|
||||
// so there is never any SDL check to stop the rumble after the desired time.
|
||||
if (!SDL.SDL_JoystickRumbleTriggers(ptrJoystick, (int)(strongMagnitude * 65535.0F), (int)(weakMagnitude * 65535.0F), 1)) {
|
||||
|
@ -1,7 +1,9 @@
|
||||
package dev.isxander.controlify.rumble;
|
||||
|
||||
public interface RumbleCapable {
|
||||
boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source);
|
||||
boolean setRumble(float strongMagnitude, float weakMagnitude);
|
||||
|
||||
boolean supportsRumble();
|
||||
|
||||
RumbleState applyRumbleSourceStrength(RumbleState state, RumbleSource source);
|
||||
}
|
||||
|
@ -30,38 +30,41 @@ public class RumbleManager {
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
RumbleEffectInstance effect;
|
||||
do {
|
||||
effect = effectQueue.peek();
|
||||
|
||||
// if we have no effects, break out of loop and get the null check
|
||||
if (effect == null)
|
||||
break;
|
||||
|
||||
// if the effect is finished, remove and set null, so we loop again
|
||||
if (effect.effect().isFinished()) {
|
||||
effectQueue.remove(effect);
|
||||
effect = null;
|
||||
}
|
||||
} while (effect == null);
|
||||
|
||||
if (effect == null) {
|
||||
controller.setRumble(0f, 0f, RumbleSource.MASTER);
|
||||
return;
|
||||
}
|
||||
|
||||
effectQueue.removeIf(e -> e.effect().isFinished());
|
||||
effectQueue.forEach(e -> e.effect().tick());
|
||||
|
||||
if (silent) {
|
||||
if (!wasSilent) {
|
||||
controller.setRumble(0f, 0f, RumbleSource.MASTER);
|
||||
wasSilent = true;
|
||||
}
|
||||
} else {
|
||||
RumbleState state = effect.effect().currentState();
|
||||
controller.setRumble(state.strong(), state.weak(), effect.source());
|
||||
if (effectQueue.isEmpty()) {
|
||||
clearRumble();
|
||||
return;
|
||||
}
|
||||
|
||||
float strong = 0f, weak = 0f;
|
||||
for (RumbleEffectInstance effect : effectQueue) {
|
||||
RumbleState effectState = controller.applyRumbleSourceStrength(effect.effect().currentState(), effect.source());
|
||||
strong = Math.max(strong, effectState.strong());
|
||||
weak = Math.max(weak, effectState.weak());
|
||||
}
|
||||
RumbleState state = new RumbleState(strong, weak);
|
||||
|
||||
if (state.isZero()) {
|
||||
clearRumble();
|
||||
return;
|
||||
}
|
||||
|
||||
if (silent) {
|
||||
clearRumble();
|
||||
} else {
|
||||
controller.setRumble(state.strong(), state.weak());
|
||||
wasSilent = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearRumble() {
|
||||
if (wasSilent)
|
||||
return;
|
||||
|
||||
controller.setRumble(0f, 0f);
|
||||
wasSilent = true;
|
||||
}
|
||||
|
||||
public void clearEffects() {
|
||||
|
@ -3,6 +3,10 @@ package dev.isxander.controlify.rumble;
|
||||
public record RumbleState(float strong, float weak) {
|
||||
public static final RumbleState NONE = new RumbleState(0.0F, 0.0F);
|
||||
|
||||
public boolean isZero() {
|
||||
return strong == 0.0F && weak == 0.0F;
|
||||
}
|
||||
|
||||
public RumbleState mul(float multiplier) {
|
||||
return new RumbleState(strong * multiplier, weak * multiplier);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import dev.isxander.controlify.controller.joystick.mapping.UnmappedJoystickMappi
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
import dev.isxander.controlify.rumble.RumbleManager;
|
||||
import dev.isxander.controlify.rumble.RumbleSource;
|
||||
import dev.isxander.controlify.rumble.RumbleState;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -41,7 +42,7 @@ public class FakeController implements JoystickController<JoystickConfig> {
|
||||
this.config = new JoystickConfig(this);
|
||||
this.rumbleManager = new RumbleManager(new RumbleCapable() {
|
||||
@Override
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -49,6 +50,11 @@ public class FakeController implements JoystickController<JoystickConfig> {
|
||||
public boolean supportsRumble() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RumbleState applyRumbleSourceStrength(RumbleState state, RumbleSource source) {
|
||||
return state;
|
||||
}
|
||||
});
|
||||
this.config.deadzonesCalibrated = true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user