1
0
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:
isXander
2023-08-10 23:59:43 +01:00
parent 421b8abfc2
commit 58fe5c7043
9 changed files with 71 additions and 49 deletions

View File

@ -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;

View File

@ -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

View File

@ -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));
}

View File

@ -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;

View File

@ -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)) {

View File

@ -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);
}

View File

@ -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() {

View File

@ -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);
}

View File

@ -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;
}