more themes, fix input events passing to ingame from screen, changelog, fix button guide sneak wrong in some places
20
.github/README.md
vendored
@ -19,14 +19,6 @@ Another fabric mod to add controller support to Minecraft Java - with a focus on
|
||||
|
||||
</div>
|
||||
|
||||
## Work In Progress
|
||||
|
||||
This mod is still in development (so is this readme!) and is not ready for use. If you want to help contribute,
|
||||
there are a few things you can do:
|
||||
|
||||
- Find/create controller diagrams & buttons for each major controller brand.
|
||||
- Add built-in support for common mod GUIs (contact me for a how-to).
|
||||
|
||||
## Why another?
|
||||
|
||||
Yes, mods like [Midnight Controls](https://modrinth.com/mod/midnight-controls) already exist. However due to the fact it
|
||||
@ -35,6 +27,18 @@ create this mod!
|
||||
|
||||
## Features
|
||||
|
||||
### Controller vibration
|
||||
|
||||
Controlify supports controller vibration, which has not been seen before for PC versions of Minecraft,
|
||||
including Bedrock Windows 10 Edition. Configure the intensity of each vibration source, with
|
||||
complex vibration patterns for lots of aspects of the game (e.g. when you take damage).
|
||||
|
||||
### Built-in gyro support
|
||||
|
||||
Controlify has built-in support for controller gyroscopes, allowing you to make fine movements in-game
|
||||
with your controller. This can be combined with [flick stick](https://www.reddit.com/r/gamedev/comments/bw5xct/flick_stick_is_a_new_way_to_control_3d_games_with/) to be able to use a controller without
|
||||
the compromise.
|
||||
|
||||
### Controller identification
|
||||
|
||||
Controlify has the ability to identify the make and model of your controller automatically,
|
||||
|
83
changelogs/1.1.0-beta.3+1.19.4.md
Normal file
@ -0,0 +1,83 @@
|
||||
# Controlify 1.1 (Beta 3)
|
||||
|
||||
## New Features
|
||||
|
||||
### Gyro support
|
||||
|
||||
Controlify now has built-in support for controller gyroscopes, allowing you to make fine movements in-game.
|
||||
This can be combined with [flick stick](https://www.reddit.com/r/gamedev/comments/bw5xct/flick_stick_is_a_new_way_to_control_3d_games_with/) to be able to use a controller without
|
||||
the compromise of using the thumbsticks.
|
||||
|
||||
This requires use of a compatible controller, such as a Dualsense controller.
|
||||
|
||||
Currently, the Steam Deck is not supported, as it does not expose the gyro data to the OS, however, explicit
|
||||
support for this device is planned in the future.
|
||||
|
||||
## UI sounds
|
||||
|
||||
A toggleable setting enables playing the legacy console edition UI sound when changing the selected component
|
||||
in GUIs. In the future, this will be expanded to have more sounds.
|
||||
|
||||
### Under-the-hood drivers
|
||||
|
||||
Controlify now uses a new driver system, which allows me to combine multiple libraries to create a more
|
||||
powerful controller interface, with a modular system to mix and match drivers.
|
||||
|
||||
This means in the future, I can add more advanced features per-controller, such as Steam Deck touchpad and
|
||||
back buttons explicitly supported in-game.
|
||||
|
||||
### Improved joystick mapping
|
||||
|
||||
Allows the mapping of joysticks to be more flexible, allowing for more complex mappings. This has been
|
||||
battle-tested with a Thrustmaster TM.16000M FCS HOTAS joystick.
|
||||
|
||||
### Built-in resource pack for extra mappings
|
||||
|
||||
Controlify now has a built-in resource pack, which contains mappings and language files for the
|
||||
aforementioned joystick.
|
||||
|
||||
The split was done to not modify the default language file, which would become huge in size and potentially cause merge
|
||||
conflicts.
|
||||
|
||||
### Improved crash handling
|
||||
|
||||
Where possible, Controlify now generates Minecraft crash reports with details of the controller which
|
||||
caused the crash.
|
||||
|
||||
## Changes
|
||||
|
||||
### Screen navigation improvements
|
||||
|
||||
Moving between components in GUIs feel more like most other games, where when holding the stick in a direction,
|
||||
it moves once, waits a bit, and then moves through components quickly. Think holding down a key while you type.
|
||||
|
||||
### More controller identifications
|
||||
|
||||
More controllers are now identified out-of-box, particularly the PS3 and Dualsense controllers.
|
||||
|
||||
Along with that, Dualsense, PS3 and Steam Deck now have textures.
|
||||
|
||||
### Vibration natives downloading changes
|
||||
|
||||
The vibration natives are now downloaded from my maven repository, allowing for better version control
|
||||
and syncing with the mod version.
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Fixed a bug where closing the pause menu or similar menu would cause you to trigger in-game inputs if
|
||||
bound to the same button
|
||||
- Fixed YetAnotherConfigLib not being declared as a fabric dependency, causing crashes if not present.
|
||||
|
||||
## API Changes
|
||||
|
||||
### Sources JAR now published
|
||||
|
||||
The sources JAR is now published to the maven repository, allowing you to debug Controlify and view documentation in your IDE.
|
||||
|
||||
### Controller binding API refactor
|
||||
|
||||
Controller binding API has had a minor refactor that will cause incompatibilities with mods.
|
||||
|
||||
### YACL option binding generator
|
||||
|
||||
Bindings now allow you to create a YACL option, to add to your own config GUIs.
|
@ -228,8 +228,9 @@ public class Controlify implements ControlifyApi {
|
||||
controller.rumbleManager().tick();
|
||||
}
|
||||
|
||||
if (state.hasAnyInput())
|
||||
if (state.hasAnyInput()) {
|
||||
this.setInputMode(InputMode.CONTROLLER);
|
||||
}
|
||||
|
||||
if (consecutiveInputSwitches > 100) {
|
||||
LOGGER.warn("Controlify detected current controller to be constantly giving input and has been disabled.");
|
||||
@ -408,8 +409,8 @@ public class Controlify implements ControlifyApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputMode(@NotNull InputMode currentInputMode) {
|
||||
if (this.currentInputMode == currentInputMode) return;
|
||||
public boolean setInputMode(@NotNull InputMode currentInputMode) {
|
||||
if (this.currentInputMode == currentInputMode) return false;
|
||||
this.currentInputMode = currentInputMode;
|
||||
|
||||
var minecraft = Minecraft.getInstance();
|
||||
@ -432,7 +433,12 @@ public class Controlify implements ControlifyApi {
|
||||
}
|
||||
lastInputSwitchTime = Blaze3D.getTime();
|
||||
|
||||
if (currentInputMode == InputMode.CONTROLLER)
|
||||
getCurrentController().ifPresent(Controller::clearState);
|
||||
|
||||
ControlifyEvents.INPUT_MODE_CHANGED.invoker().onInputModeChanged(currentInputMode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void hideMouse(boolean hide, boolean moveMouse) {
|
||||
|
@ -30,7 +30,7 @@ public interface ControlifyApi {
|
||||
* Get the current input mode for the game.
|
||||
*/
|
||||
@NotNull InputMode currentInputMode();
|
||||
void setInputMode(@NotNull InputMode mode);
|
||||
boolean setInputMode(@NotNull InputMode mode);
|
||||
|
||||
static ControlifyApi get() {
|
||||
return Controlify.instance();
|
||||
|
@ -137,7 +137,6 @@ public class ControllerBindings<T extends ControllerState> {
|
||||
.identifier("controlify", "sneak")
|
||||
.defaultBind(GamepadBinds.RIGHT_STICK_PRESS)
|
||||
.category(MOVEMENT_CATEGORY)
|
||||
.vanillaOverride(options.keyShift, () -> controller.config().toggleSneak)
|
||||
.build());
|
||||
register(ATTACK = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "attack")
|
||||
|
@ -220,9 +220,7 @@ public class YACLHelper {
|
||||
category.group(makeVibrationGroup(globalVibrationOption, config, def));
|
||||
}
|
||||
|
||||
if (controller instanceof GamepadController gamepad && gamepad.hasGyro()) {
|
||||
category.group(makeGyroGroup(gamepad));
|
||||
}
|
||||
category.group(makeGyroGroup(controller));
|
||||
|
||||
var advancedGroup = OptionGroup.createBuilder()
|
||||
.name(Component.translatable("controlify.gui.group.advanced"))
|
||||
@ -309,19 +307,27 @@ public class YACLHelper {
|
||||
return vibrationGroup.build();
|
||||
}
|
||||
|
||||
private static OptionGroup makeGyroGroup(GamepadController gamepad) {
|
||||
var gpCfg = gamepad.config();
|
||||
var gpCfgDef = gamepad.defaultConfig();
|
||||
private static OptionGroup makeGyroGroup(Controller<?, ?> controller) {
|
||||
GamepadController gamepad = (controller instanceof GamepadController) ? (GamepadController) controller : null;
|
||||
boolean hasGyro = gamepad != null && gamepad.hasGyro();
|
||||
|
||||
var gpCfg = gamepad != null ? gamepad.config() : null;
|
||||
var gpCfgDef = gamepad != null ? gamepad.defaultConfig() : null;
|
||||
|
||||
Component noGyroTooltip = Component.translatable("controlify.gui.group.gyro.no_gyro.tooltip").withStyle(ChatFormatting.RED);
|
||||
|
||||
Option<Float> gyroSensitivity;
|
||||
List<Option<?>> gyroOptions = new ArrayList<>();
|
||||
var gyroGroup = OptionGroup.createBuilder()
|
||||
.name(Component.translatable("controlify.gui.group.gyro"))
|
||||
.tooltip(Component.translatable("controlify.gui.group.gyro.tooltip"))
|
||||
.collapsed(!hasGyro)
|
||||
.option(gyroSensitivity = Option.createBuilder(float.class)
|
||||
.name(Component.translatable("controlify.gui.gyro_look_sensitivity"))
|
||||
.tooltip(Component.translatable("controlify.gui.gyro_look_sensitivity.tooltip"))
|
||||
.binding(gpCfgDef.gyroLookSensitivity, () -> gpCfg.gyroLookSensitivity, v -> gpCfg.gyroLookSensitivity = v)
|
||||
.tooltip(hasGyro ? Component.empty() : noGyroTooltip)
|
||||
.available(hasGyro)
|
||||
.binding(hasGyro ? gpCfgDef.gyroLookSensitivity : 0, () -> hasGyro ? gpCfg.gyroLookSensitivity : 0, v -> gpCfg.gyroLookSensitivity = v)
|
||||
.controller(opt -> new FloatSliderController(opt, 0f, 1f, 0.05f, percentOrOffFormatter))
|
||||
.listener((opt, sensitivity) -> gyroOptions.forEach(o -> {
|
||||
o.setAvailable(sensitivity > 0);
|
||||
@ -332,7 +338,9 @@ public class YACLHelper {
|
||||
var opt = Option.createBuilder(boolean.class)
|
||||
.name(Component.translatable("controlify.gui.gyro_requires_button"))
|
||||
.tooltip(Component.translatable("controlify.gui.gyro_requires_button.tooltip"))
|
||||
.binding(gpCfgDef.gyroRequiresButton, () -> gpCfg.gyroRequiresButton, v -> gpCfg.gyroRequiresButton = v)
|
||||
.tooltip(hasGyro ? Component.empty() : noGyroTooltip)
|
||||
.available(hasGyro)
|
||||
.binding(hasGyro ? gpCfgDef.gyroRequiresButton : false, () -> hasGyro ? gpCfg.gyroRequiresButton : false, v -> gpCfg.gyroRequiresButton = v)
|
||||
.controller(TickBoxController::new)
|
||||
.available(gyroSensitivity.pendingValue() > 0)
|
||||
.build();
|
||||
@ -343,7 +351,9 @@ public class YACLHelper {
|
||||
var opt = Option.createBuilder(boolean.class)
|
||||
.name(Component.translatable("controlify.gui.flick_stick"))
|
||||
.tooltip(Component.translatable("controlify.gui.flick_stick.tooltip"))
|
||||
.binding(gpCfgDef.flickStick, () -> gpCfg.flickStick, v -> gpCfg.flickStick = v)
|
||||
.tooltip(hasGyro ? Component.empty() : noGyroTooltip)
|
||||
.available(hasGyro)
|
||||
.binding(hasGyro ? gpCfgDef.flickStick : false, () -> hasGyro ? gpCfg.flickStick : false, v -> gpCfg.flickStick = v)
|
||||
.controller(TickBoxController::new)
|
||||
.available(gyroSensitivity.pendingValue() > 0)
|
||||
.build();
|
||||
|
@ -9,7 +9,8 @@ public enum BuiltinGamepadTheme implements NameableEnum {
|
||||
XBOX_ONE("Xbox One", "xbox_one"),
|
||||
DUALSHOCK4("Dualshock 4", "dualshock4"),
|
||||
DUALSHOCK3("Dualshock 3", "dualshock3"),
|
||||
DUALSENSE("Dualsense", "dualsense");
|
||||
DUALSENSE("Dualsense", "dualsense"),
|
||||
STEAM_DECK("Steam Deck", "steam_deck");
|
||||
|
||||
private final String name, id;
|
||||
|
||||
|
@ -81,16 +81,6 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
|
||||
state = GamepadState.EMPTY;
|
||||
}
|
||||
|
||||
public void consumeButtonState() {
|
||||
this.state = new GamepadState(state().gamepadAxes(), state().rawGamepadAxes(), GamepadState.ButtonState.EMPTY, state().gyroDelta(), state().absoluteGyroPos());
|
||||
}
|
||||
|
||||
GLFWGamepadState getGamepadState() {
|
||||
GLFWGamepadState state = GLFWGamepadState.create();
|
||||
GLFW.glfwGetGamepadState(joystickId, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
||||
if (!canRumble()) return false;
|
||||
|
@ -16,7 +16,7 @@ public class ControllerPlayerMovement extends Input {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(boolean slowDown, float f) {
|
||||
public void tick(boolean slowDown, float movementMultiplier) {
|
||||
if (Minecraft.getInstance().screen != null || player == null) {
|
||||
this.up = false;
|
||||
this.down = false;
|
||||
@ -46,19 +46,25 @@ public class ControllerPlayerMovement extends Input {
|
||||
}
|
||||
|
||||
if (slowDown) {
|
||||
this.leftImpulse *= f;
|
||||
this.forwardImpulse *= f;
|
||||
this.leftImpulse *= movementMultiplier;
|
||||
this.forwardImpulse *= movementMultiplier;
|
||||
}
|
||||
|
||||
if (!this.jumping && bindings.JUMP.justPressed())
|
||||
// this over-complication is so exiting a GUI with the button still held doesn't trigger a jump.
|
||||
if (bindings.JUMP.justPressed())
|
||||
this.jumping = true;
|
||||
else
|
||||
this.jumping = bindings.JUMP.held();
|
||||
if (!bindings.JUMP.held())
|
||||
this.jumping = false;
|
||||
|
||||
if (player.getAbilities().flying || player.isInWater() || !controller.config().toggleSneak) {
|
||||
this.shiftKeyDown = bindings.SNEAK.held();
|
||||
if (player.getAbilities().flying || (player.isInWater() && !player.isOnGround()) || !controller.config().toggleSneak) {
|
||||
if (bindings.SNEAK.justPressed())
|
||||
this.shiftKeyDown = true;
|
||||
if (!bindings.SNEAK.held())
|
||||
this.shiftKeyDown = false;
|
||||
} else {
|
||||
this.shiftKeyDown = Minecraft.getInstance().options.keyShift.isDown();
|
||||
if (bindings.SNEAK.justPressed()) {
|
||||
this.shiftKeyDown = !this.shiftKeyDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,13 +154,10 @@ public class InGameButtonGuide implements IngameGuideRegistry {
|
||||
return Optional.of(Component.translatable("controlify.guide.dismount"));
|
||||
if (player.getAbilities().flying)
|
||||
return Optional.of(Component.translatable("controlify.guide.fly_down"));
|
||||
if (player.isInWater())
|
||||
if (player.isInWater() && !player.isOnGround())
|
||||
return Optional.of(Component.translatable("controlify.guide.swim_down"));
|
||||
if (ctx.controller().config().toggleSneak) {
|
||||
if (player.input.shiftKeyDown)
|
||||
return Optional.of(Component.translatable("controlify.guide.stop_sneaking"));
|
||||
else
|
||||
return Optional.of(Component.translatable("controlify.guide.start_sneaking"));
|
||||
return Optional.of(Component.translatable(player.input.shiftKeyDown ? "controlify.guide.stop_sneaking" : "controlify.guide.start_sneaking"));
|
||||
} else {
|
||||
if (!player.input.shiftKeyDown)
|
||||
return Optional.of(Component.translatable("controlify.guide.sneak"));
|
||||
|
@ -48,7 +48,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Steam Deck",
|
||||
"theme": "xbox_one",
|
||||
"theme": "steam_deck",
|
||||
|
||||
"hids": [
|
||||
[0x28de, 0x1205],
|
||||
|
@ -53,6 +53,7 @@
|
||||
"controlify.gui.group.vibration.tooltip": "Adjust how your controller vibrates.",
|
||||
"controlify.gui.group.gyro": "Gyro",
|
||||
"controlify.gui.group.gyro.tooltip": "Adjust how Controlify treats your controller's built in gyroscope.\nA gyroscope determines how the controller is rotated.",
|
||||
"controlify.gui.group.gyro.no_gyro.tooltip": "This controller does not support Gyro. You must have a Dualsense™ controller or other compatible controller to use this feature.",
|
||||
"controlify.gui.gyro_look_sensitivity": "Look Sensitivity",
|
||||
"controlify.gui.gyro_look_sensitivity.tooltip": "How much the camera moves based on gyroscope rotation.",
|
||||
"controlify.gui.gyro_requires_button": "Require Button",
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 166 B |
After Width: | Height: | Size: 181 B |
After Width: | Height: | Size: 180 B |
After Width: | Height: | Size: 180 B |
After Width: | Height: | Size: 183 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 152 B |
After Width: | Height: | Size: 207 B |
After Width: | Height: | Size: 212 B |
After Width: | Height: | Size: 193 B |
After Width: | Height: | Size: 217 B |
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 154 B |
After Width: | Height: | Size: 147 B |
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 213 B |
After Width: | Height: | Size: 192 B |
After Width: | Height: | Size: 216 B |
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 153 B |
After Width: | Height: | Size: 191 B |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |