1
0
forked from Clones/Controlify

more themes, fix input events passing to ingame from screen, changelog, fix button guide sneak wrong in some places

This commit is contained in:
isXander
2023-04-16 23:10:40 +01:00
parent 800f219fa6
commit b769661765
38 changed files with 145 additions and 48 deletions

20
.github/README.md vendored
View File

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

View 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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,7 +48,7 @@
},
{
"name": "Steam Deck",
"theme": "xbox_one",
"theme": "steam_deck",
"hids": [
[0x28de, 0x1205],

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB