mirror of
https://github.com/chylex/Better-Controls.git
synced 2025-09-17 14:24:52 +02:00
Compare commits
12 Commits
767ab9cb7d
...
main
Author | SHA1 | Date | |
---|---|---|---|
2e19fffe44
|
|||
32f6a6e7fe
|
|||
dfefab3482
|
|||
ffd56a4407
|
|||
6b574f8568
|
|||
76a1353dbf
|
|||
0757d30f12
|
|||
64c4b51f0e
|
|||
5111ac5f7e
|
|||
ee3db91f0c
|
|||
9da758937e
|
|||
aa499bead5
|
23
README.md
23
README.md
@@ -11,28 +11,33 @@ Another major difference is the amount and granularity of options. Better Contro
|
||||
|
||||
## Features
|
||||
|
||||
The mod adds **Toggle Keybinds** for sprinting, sneaking, flying (creative mode), walking, and jumping. You can use modifier keys (`Control` / `Shift` / `Alt`) for each, including for example setting `Control` to Sneak, and `Control + Y` to Toggle Sneak. If you press the original key, the toggle will be canceled (in the previous example, you can Toggle Sneak by pressing `Control + Y`, and stop sneaking by simply tapping Sneak). Note that the vanilla options for toggling sprinting/sneaking are disabled to avoid conflicts with the custom keybinds.
|
||||
The mod adds **Toggle Keybinds** for sprinting, sneaking, flying (creative mode), walking, and jumping. You can use modifier keys (`Control` / `Shift` / `Alt`) for each, including for example setting `Control` to Sneak, and `Control + Y` to Toggle Sneak. If you press the original key, the toggle will be canceled (in the previous example, you can Toggle Sneak by pressing `Control + Y`, and stop sneaking by simply tapping `Control`). Note that the vanilla options for toggling sprinting/sneaking are disabled to avoid conflicts with the custom keybinds.
|
||||
|
||||
You can also bind a key that resets all **Toggle Keybinds** at once. That makes it easy to for ex. turn on walking, jumping, and sprinting, and then turn all of them off again by pressing one key instead of three.
|
||||
|
||||
#### Sprinting
|
||||
|
||||
* **Sprint Key Mode** changes how the Sprint key behaves. You can choose between *Tap To Start Sprinting*, *Tap To Start / Stop Sprinting*, and *Hold To Sprint*.
|
||||
* **Double Tap 'Walk Forwards' To Sprint** can be turned off to prevent accidental sprinting.
|
||||
* **Resume Sprinting After Hitting Obstacle** automatically presses the Sprint key once you are no longer touching any blocks (helpful when climbing hills, especially if the previous option is enabled).
|
||||
* **Double Tap 'Walk Forwards' To Sprint** can be turned off.
|
||||
* **Resume Sprinting After Hitting Obstacle** re-activates sprinting once you are no longer touching any blocks.
|
||||
|
||||
#### Sneaking
|
||||
|
||||
* **Move Camera Smoothly** lets you disable the smooth movement when sneaking or unsneaking.
|
||||
* **Move Camera Smoothly** can be turned off to disable the smooth movement when sneaking or unsneaking.
|
||||
|
||||
#### Gliding
|
||||
|
||||
* **Start a Glide** with a dedicated key.
|
||||
* **Double Tap 'Jump' To Glide** can be turned off.
|
||||
|
||||
#### Flying
|
||||
|
||||
* **Double Tap 'Jump' To Fly** can be turned off to prevent accidental flight toggling.
|
||||
* **Disable Flight Inertia** stops you instantly when you stop holding movement keys.
|
||||
* **Double Tap 'Jump' To Fly** can be turned off.
|
||||
* **Flight Inertia Multiplier** changes how quickly you stop moving in the air when you stop holding movement keys.
|
||||
* **Disable Field Of View Changing** prevents sprinting, potions, and other factors from changing the FOV while flying in creative and spectator mode.
|
||||
* **Fly On Ground** lets you fly while touching the ground in creative mode (and also lets you stop flying by tapping Sneak while touching the ground).
|
||||
* **Flight Speed Multiplier** (0.25x - 8x) changes how fast you fly in creative and spectator mode.
|
||||
* **Vertical Speed Boost** (up to +300%) adds additional vertical speed boost while flying in creative and spectator mode.
|
||||
* **Fly On Ground** lets you fly while touching the ground in creative mode. Stop flying by tapping Sneak while touching the ground.
|
||||
* **Flight Speed Multiplier** (0.25x - 8x) changes flight speed in creative and spectator mode.
|
||||
* **Vertical Speed Boost** (up to +300%) adds additional vertical flight speed boost in creative and spectator mode.
|
||||
|
||||
Both speed boosts can be configured separately for sprinting, which will be active when the Sprint key is held. Unlike in vanilla, the sprinting flight boost works in all directions.
|
||||
|
||||
|
@@ -6,28 +6,33 @@ Another major difference is the amount and granularity of options. Better Contro
|
||||
|
||||
## Features
|
||||
|
||||
The mod adds **Toggle Keybinds** for sprinting, sneaking, flying (creative mode), walking, and jumping. You can use modifier keys (`Control` / `Shift` / `Alt`) for each, including for example setting `Control` to Sneak, and `Control + Y` to Toggle Sneak. If you press the original key, the toggle will be canceled (in the previous example, you can Toggle Sneak by pressing `Control + Y`, and stop sneaking by simply tapping Sneak). Note that the vanilla options for toggling sprinting/sneaking are disabled to avoid conflicts with the custom keybinds.
|
||||
The mod adds **Toggle Keybinds** for sprinting, sneaking, flying (creative mode), walking, and jumping. You can use modifier keys (`Control` / `Shift` / `Alt`) for each, including for example setting `Control` to Sneak, and `Control + Y` to Toggle Sneak. If you press the original key, the toggle will be canceled (in the previous example, you can Toggle Sneak by pressing `Control + Y`, and stop sneaking by simply tapping `Control`). Note that the vanilla options for toggling sprinting/sneaking are disabled to avoid conflicts with the custom keybinds.
|
||||
|
||||
You can also bind a key that resets all **Toggle Keybinds** at once. That makes it easy to for ex. turn on walking, jumping, and sprinting, and then turn all of them off again by pressing one key instead of three.
|
||||
|
||||
#### Sprinting
|
||||
|
||||
* **Sprint Key Mode** changes how the Sprint key behaves. You can choose between *Tap To Start Sprinting*, *Tap To Start / Stop Sprinting*, and *Hold To Sprint*.
|
||||
* **Double Tap 'Walk Forwards' To Sprint** can be turned off to prevent accidental sprinting.
|
||||
* **Resume Sprinting After Hitting Obstacle** automatically presses the Sprint key once you are no longer touching any blocks (helpful when climbing hills, especially if the previous option is enabled).
|
||||
* **Double Tap 'Walk Forwards' To Sprint** can be turned off.
|
||||
* **Resume Sprinting After Hitting Obstacle** re-activates sprinting once you are no longer touching any blocks.
|
||||
|
||||
#### Sneaking
|
||||
|
||||
* **Move Camera Smoothly** lets you disable the smooth movement when sneaking or unsneaking.
|
||||
* **Move Camera Smoothly** can be turned off to disable the smooth movement when sneaking or unsneaking.
|
||||
|
||||
#### Gliding
|
||||
|
||||
* **Start a Glide** with a dedicated key.
|
||||
* **Double Tap 'Jump' To Glide** can be turned off.
|
||||
|
||||
#### Flying
|
||||
|
||||
* **Double Tap 'Jump' To Fly** can be turned off to prevent accidental flight toggling.
|
||||
* **Disable Flight Inertia** stops you instantly when you stop holding movement keys.
|
||||
* **Double Tap 'Jump' To Fly** can be turned off.
|
||||
* **Flight Inertia Multiplier** changes how quickly you stop moving in the air when you stop holding movement keys.
|
||||
* **Disable Field Of View Changing** prevents sprinting, potions, and other factors from changing the FOV while flying in creative and spectator mode.
|
||||
* **Fly On Ground** lets you fly while touching the ground in creative mode (and also lets you stop flying by tapping Sneak while touching the ground).
|
||||
* **Flight Speed Multiplier** (0.25x - 8x) changes how fast you fly in creative and spectator mode.
|
||||
* **Vertical Speed Boost** (up to +300%) adds additional vertical speed boost while flying in creative and spectator mode.
|
||||
* **Fly On Ground** lets you fly while touching the ground in creative mode. Stop flying by tapping Sneak while touching the ground.
|
||||
* **Flight Speed Multiplier** (0.25x - 8x) changes flight speed in creative and spectator mode.
|
||||
* **Vertical Speed Boost** (up to +300%) adds additional vertical flight speed boost in creative and spectator mode.
|
||||
|
||||
Both speed boosts can be configured separately for sprinting, which will be active when the Sprint key is held. Unlike in vanilla, the sprinting flight boost works in all directions.
|
||||
|
@@ -6,28 +6,33 @@ Another major difference is the amount and granularity of options. Better Contro
|
||||
|
||||
## Features
|
||||
|
||||
The mod adds **Toggle Keybinds** for sprinting, sneaking, flying (creative mode), walking, and jumping. You can use modifier keys (`Control` / `Shift` / `Alt`) for each, including for example setting `Control` to Sneak, and `Control + Y` to Toggle Sneak. If you press the original key, the toggle will be canceled (in the previous example, you can Toggle Sneak by pressing `Control + Y`, and stop sneaking by simply tapping Sneak). Note that the vanilla options for toggling sprinting/sneaking are disabled to avoid conflicts with the custom keybinds.
|
||||
The mod adds **Toggle Keybinds** for sprinting, sneaking, flying (creative mode), walking, and jumping. You can use modifier keys (`Control` / `Shift` / `Alt`) for each, including for example setting `Control` to Sneak, and `Control + Y` to Toggle Sneak. If you press the original key, the toggle will be canceled (in the previous example, you can Toggle Sneak by pressing `Control + Y`, and stop sneaking by simply tapping `Control`). Note that the vanilla options for toggling sprinting/sneaking are disabled to avoid conflicts with the custom keybinds.
|
||||
|
||||
You can also bind a key that resets all **Toggle Keybinds** at once. That makes it easy to for ex. turn on walking, jumping, and sprinting, and then turn all of them off again by pressing one key instead of three.
|
||||
|
||||
#### Sprinting
|
||||
|
||||
* **Sprint Key Mode** changes how the Sprint key behaves. You can choose between *Tap To Start Sprinting*, *Tap To Start / Stop Sprinting*, and *Hold To Sprint*.
|
||||
* **Double Tap 'Walk Forwards' To Sprint** can be turned off to prevent accidental sprinting.
|
||||
* **Resume Sprinting After Hitting Obstacle** automatically presses the Sprint key once you are no longer touching any blocks (helpful when climbing hills, especially if the previous option is enabled).
|
||||
* **Double Tap 'Walk Forwards' To Sprint** can be turned off.
|
||||
* **Resume Sprinting After Hitting Obstacle** re-activates sprinting once you are no longer touching any blocks.
|
||||
|
||||
#### Sneaking
|
||||
|
||||
* **Move Camera Smoothly** lets you disable the smooth movement when sneaking or unsneaking.
|
||||
* **Move Camera Smoothly** can be turned off to disable the smooth movement when sneaking or unsneaking.
|
||||
|
||||
#### Gliding
|
||||
|
||||
* **Start a Glide** with a dedicated key.
|
||||
* **Double Tap 'Jump' To Glide** can be turned off.
|
||||
|
||||
#### Flying
|
||||
|
||||
* **Double Tap 'Jump' To Fly** can be turned off to prevent accidental flight toggling.
|
||||
* **Disable Flight Inertia** stops you instantly when you stop holding movement keys.
|
||||
* **Double Tap 'Jump' To Fly** can be turned off.
|
||||
* **Flight Inertia Multiplier** changes how quickly you stop moving in the air when you stop holding movement keys.
|
||||
* **Disable Field Of View Changing** prevents sprinting, potions, and other factors from changing the FOV while flying in creative and spectator mode.
|
||||
* **Fly On Ground** lets you fly while touching the ground in creative mode (and also lets you stop flying by tapping Sneak while touching the ground).
|
||||
* **Flight Speed Multiplier** (0.25x - 8x) changes how fast you fly in creative and spectator mode.
|
||||
* **Vertical Speed Boost** (up to +300%) adds additional vertical speed boost while flying in creative and spectator mode.
|
||||
* **Fly On Ground** lets you fly while touching the ground in creative mode. Stop flying by tapping Sneak while touching the ground.
|
||||
* **Flight Speed Multiplier** (0.25x - 8x) changes flight speed in creative and spectator mode.
|
||||
* **Vertical Speed Boost** (up to +300%) adds additional vertical flight speed boost in creative and spectator mode.
|
||||
|
||||
Both speed boosts can be configured separately for sprinting, which will be active when the Sprint key is held. Unlike in vanilla, the sprinting flight boost works in all directions.
|
||||
|
||||
|
@@ -3,18 +3,18 @@ modId=bettercontrols
|
||||
modName=Better Controls
|
||||
modDescription=Adds many powerful key bindings and options to control your movement.\\n\\nThe features complement vanilla mechanics without giving unfair advantages, so server use should be fine.
|
||||
modAuthor=chylex
|
||||
modVersion=1.4.0
|
||||
modVersion=1.6.1
|
||||
modLicense=MPL-2.0
|
||||
modSourcesURL=https://github.com/chylex/Better-Controls
|
||||
modIssuesURL=https://github.com/chylex/Better-Controls/issues
|
||||
modSides=client
|
||||
|
||||
# Dependencies
|
||||
minecraftVersion=1.21.4
|
||||
neoForgeVersion=21.4.77-beta
|
||||
neoModDevVersion=2.0.76
|
||||
fabricVersion=0.16.10
|
||||
loomVersion=1.9
|
||||
minecraftVersion=1.21.6
|
||||
neoForgeVersion=21.6.20-beta
|
||||
neoModDevVersion=2.0.103
|
||||
fabricVersion=0.16.14
|
||||
loomVersion=1.10
|
||||
mixinVersion=0.12.5+mixin.0.8.5
|
||||
mixinExtrasVersion=0.4.1
|
||||
|
||||
@@ -24,8 +24,8 @@ mixinExtrasVersion=0.4.1
|
||||
# https://github.com/FabricMC/fabric-loom/releases
|
||||
|
||||
# Constraints
|
||||
minimumMinecraftVersion=1.21.4
|
||||
minimumNeoForgeVersion=21.4.0-beta
|
||||
minimumMinecraftVersion=1.21.6
|
||||
minimumNeoForgeVersion=21.6.0-beta
|
||||
minimumFabricVersion=0.15.0
|
||||
|
||||
# Gradle
|
||||
|
42
src/main/java/chylex/bettercontrols/Mixins.java
Normal file
42
src/main/java/chylex/bettercontrols/Mixins.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package chylex.bettercontrols;
|
||||
|
||||
import chylex.bettercontrols.mixin.AccessCameraFields;
|
||||
import chylex.bettercontrols.mixin.AccessClientPlayerFields;
|
||||
import chylex.bettercontrols.mixin.AccessKeyMappingFields;
|
||||
import chylex.bettercontrols.mixin.AccessPlayerFields;
|
||||
import chylex.bettercontrols.mixin.AccessToggleKeyMappingFields;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.ToggleKeyMapping;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
@SuppressWarnings("CastToIncompatibleInterface")
|
||||
public final class Mixins {
|
||||
private Mixins() {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T me(Object object) {
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
public static AccessCameraFields cameraFields(Camera camera) {
|
||||
return (AccessCameraFields) camera;
|
||||
}
|
||||
|
||||
public static AccessClientPlayerFields clientPlayerFields(LocalPlayer localPlayer) {
|
||||
return (AccessClientPlayerFields) localPlayer;
|
||||
}
|
||||
|
||||
public static AccessKeyMappingFields keyMappingFields(KeyMapping keyMapping) {
|
||||
return (AccessKeyMappingFields) keyMapping;
|
||||
}
|
||||
|
||||
public static AccessPlayerFields playerFields(Player player) {
|
||||
return (AccessPlayerFields) player;
|
||||
}
|
||||
|
||||
public static AccessToggleKeyMappingFields toggleKeyMappingFields(ToggleKeyMapping toggleKeyMapping) {
|
||||
return (AccessToggleKeyMappingFields) toggleKeyMapping;
|
||||
}
|
||||
}
|
@@ -27,9 +27,12 @@ public final class BetterControlsConfig {
|
||||
public final KeyBindingWithModifier keyToggleSneak = new KeyBindingWithModifier("key.bettercontrols.toggle_sneak");
|
||||
public boolean sneakingMovesCameraSmoothly = true;
|
||||
|
||||
public final KeyBindingWithModifier keyStartGlide = new KeyBindingWithModifier("key.bettercontrols.start_glide");
|
||||
public boolean doubleTapJumpToGlide = true;
|
||||
|
||||
public final KeyBindingWithModifier keyToggleFlight = new KeyBindingWithModifier("key.bettercontrols.toggle_flight");
|
||||
public boolean doubleTapJumpToToggleFlight = true;
|
||||
public boolean disableFlightInertia = false;
|
||||
public float flightInertiaMultiplier = 1F;
|
||||
public boolean disableChangingFovWhileFlying = false;
|
||||
public boolean flyOnGroundInCreative = false;
|
||||
public float flightHorizontalSpeedMpCreativeDefault = 1F;
|
||||
|
@@ -41,9 +41,12 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js
|
||||
Json.writeKeyBinding(obj, "Sneak.KeyToggle", cfg.keyToggleSneak);
|
||||
Json.setBool(obj, "Sneak.SmoothCamera", cfg.sneakingMovesCameraSmoothly);
|
||||
|
||||
Json.writeKeyBinding(obj, "Glide.KeyStart", cfg.keyStartGlide);
|
||||
Json.setBool(obj, "Glide.DoubleTapJump", cfg.doubleTapJumpToGlide);
|
||||
|
||||
Json.writeKeyBinding(obj, "Flight.KeyToggle.Creative", cfg.keyToggleFlight);
|
||||
Json.setBool(obj, "Flight.DoubleTapJump", cfg.doubleTapJumpToToggleFlight);
|
||||
Json.setBool(obj, "Flight.DisableInertia", cfg.disableFlightInertia);
|
||||
Json.setFloat(obj, "Flight.InertiaMultiplier", cfg.flightInertiaMultiplier);
|
||||
Json.setBool(obj, "Flight.DisableChangingFOV", cfg.disableChangingFovWhileFlying);
|
||||
Json.setBool(obj, "Flight.FlyOnGround.Creative", cfg.flyOnGroundInCreative);
|
||||
Json.setFloat(obj, "Flight.SpeedMp.Creative.Default", cfg.flightHorizontalSpeedMpCreativeDefault);
|
||||
@@ -72,6 +75,10 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js
|
||||
cfg.sprintMode = SprintMode.TAP_TO_TOGGLE;
|
||||
}
|
||||
|
||||
if (obj.has("Flight.DisableInertia") && obj.get("Flight.DisableInertia").getAsBoolean()) {
|
||||
cfg.flightInertiaMultiplier = 0F;
|
||||
}
|
||||
|
||||
Json.readKeyBinding(obj, "Sprint.KeyToggle", cfg.keyToggleSprint);
|
||||
cfg.sprintMode = Json.getEnum(obj, "Sprint.Mode", cfg.sprintMode, SprintMode.class);
|
||||
cfg.doubleTapForwardToSprint = Json.getBool(obj, "Sprint.DoubleTapForward", cfg.doubleTapForwardToSprint);
|
||||
@@ -80,9 +87,12 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js
|
||||
Json.readKeyBinding(obj, "Sneak.KeyToggle", cfg.keyToggleSneak);
|
||||
cfg.sneakingMovesCameraSmoothly = Json.getBool(obj, "Sneak.SmoothCamera", cfg.sneakingMovesCameraSmoothly);
|
||||
|
||||
Json.readKeyBinding(obj, "Glide.KeyStart", cfg.keyStartGlide);
|
||||
cfg.doubleTapJumpToGlide = Json.getBool(obj, "Glide.DoubleTapJump", cfg.doubleTapJumpToGlide);
|
||||
|
||||
Json.readKeyBinding(obj, "Flight.KeyToggle.Creative", cfg.keyToggleFlight);
|
||||
cfg.doubleTapJumpToToggleFlight = Json.getBool(obj, "Flight.DoubleTapJump", cfg.doubleTapJumpToToggleFlight);
|
||||
cfg.disableFlightInertia = Json.getBool(obj, "Flight.DisableInertia", cfg.disableFlightInertia);
|
||||
cfg.flightInertiaMultiplier = Json.getFloat(obj, "Flight.InertiaMultiplier", cfg.flightInertiaMultiplier, 0F, 1F);
|
||||
cfg.disableChangingFovWhileFlying = Json.getBool(obj, "Flight.DisableChangingFOV", cfg.disableChangingFovWhileFlying);
|
||||
cfg.flyOnGroundInCreative = Json.getBool(obj, "Flight.FlyOnGround.Creative", cfg.flyOnGroundInCreative);
|
||||
cfg.flightHorizontalSpeedMpCreativeDefault = readHorizontalSpeedMultiplier(obj, "Flight.SpeedMp.Creative.Default", cfg.flightHorizontalSpeedMpCreativeDefault);
|
||||
|
@@ -83,9 +83,29 @@ public class BetterControlsScreen extends OptionsSubScreen {
|
||||
return y;
|
||||
}
|
||||
|
||||
private int generateGlidingOptions(int y, List<GuiEventListener> elements) {
|
||||
BetterControlsConfig cfg = BetterControlsCommon.getConfig();
|
||||
|
||||
generateKeyBindingWithModifierRow(y, elements, text("Start a Glide"), cfg.keyStartGlide);
|
||||
y += ROW_HEIGHT;
|
||||
|
||||
generateBooleanOptionRow(y, elements, text("Double Tap 'Jump' To Start a Glide"), cfg.doubleTapJumpToGlide, value -> cfg.doubleTapJumpToGlide = value);
|
||||
y += ROW_HEIGHT;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
private int generateFlightOptions(int y, List<GuiEventListener> elements) {
|
||||
BetterControlsConfig cfg = BetterControlsCommon.getConfig();
|
||||
|
||||
ImmutableList<Option<Float>> flightInertiaOptions = ImmutableList.of(
|
||||
new Option<>(Float.valueOf(0.00F), text("0x")),
|
||||
new Option<>(Float.valueOf(0.25F), text("0.25x")),
|
||||
new Option<>(Float.valueOf(0.50F), text("0.5x")),
|
||||
new Option<>(Float.valueOf(0.75F), text("0.75x")),
|
||||
new Option<>(Float.valueOf(1.00F), text("1x"))
|
||||
);
|
||||
|
||||
ImmutableList<Option<Float>> flightSpeedOptions = ImmutableList.of(
|
||||
new Option<>(Float.valueOf(0.25F), text("0.25x")),
|
||||
new Option<>(Float.valueOf(0.50F), text("0.5x")),
|
||||
@@ -107,13 +127,14 @@ public class BetterControlsScreen extends OptionsSubScreen {
|
||||
generateBooleanOptionRow(y, elements, text("Double Tap 'Jump' To Fly (Creative)"), cfg.doubleTapJumpToToggleFlight, value -> cfg.doubleTapJumpToToggleFlight = value);
|
||||
y += ROW_HEIGHT;
|
||||
|
||||
generateBooleanOptionRow(y, elements, text("Disable Flight Inertia"), cfg.disableFlightInertia, value -> cfg.disableFlightInertia = value);
|
||||
generateLeftSideText(y, elements, text("Flight Inertia Multiplier"));
|
||||
elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, text("Flight Inertia Multiplier"), flightInertiaOptions, cfg.flightInertiaMultiplier, value -> cfg.flightInertiaMultiplier = value));
|
||||
y += ROW_HEIGHT;
|
||||
|
||||
generateBooleanOptionRow(y, elements, text("Disable Field Of View Changing"), cfg.disableChangingFovWhileFlying, value -> cfg.disableChangingFovWhileFlying = value);
|
||||
y += ROW_HEIGHT;
|
||||
|
||||
generateBooleanOptionRow(y, elements, text("Fly On Ground (Creative Mode)"), cfg.flyOnGroundInCreative, value -> cfg.flyOnGroundInCreative = value);
|
||||
generateBooleanOptionRow(y, elements, text("Fly On Ground (Creative)"), cfg.flyOnGroundInCreative, value -> cfg.flyOnGroundInCreative = value);
|
||||
y += ROW_HEIGHT;
|
||||
|
||||
y += ROW_HEIGHT / 3;
|
||||
@@ -223,6 +244,9 @@ public class BetterControlsScreen extends OptionsSubScreen {
|
||||
elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, text("Sneaking"), CENTER));
|
||||
y = generateSneakingOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
|
||||
|
||||
elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, text("Gliding"), CENTER));
|
||||
y = generateGlidingOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
|
||||
|
||||
elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, text("Flying"), CENTER));
|
||||
y = generateFlightOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
|
||||
|
||||
|
@@ -9,12 +9,11 @@ import net.minecraft.client.gui.components.Renderable;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
public final class OptionListWidget extends ContainerObjectSelectionList<Entry> {
|
||||
public static final int ROW_WIDTH = 408;
|
||||
@@ -35,28 +34,32 @@ public final class OptionListWidget extends ContainerObjectSelectionList<Entry>
|
||||
|
||||
private static Offset getElementOffset(GuiEventListener element) {
|
||||
if (element instanceof OptionWidget widget) {
|
||||
return new Offset(widget.getX(), widget.getY());
|
||||
return new Offset(widget.getX(), widget.getY(), widget.getHeight());
|
||||
}
|
||||
else if (element instanceof AbstractWidget widget) {
|
||||
return new Offset(widget.getX(), widget.getY());
|
||||
return new Offset(widget.getX(), widget.getY(), widget.getHeight());
|
||||
}
|
||||
else {
|
||||
return new Offset(0, 0);
|
||||
return new Offset(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OptionWidget extends GuiEventListener, Renderable {
|
||||
int getX();
|
||||
int getY();
|
||||
void setX(int x);
|
||||
int getX();
|
||||
|
||||
void setY(int y);
|
||||
int getY();
|
||||
|
||||
int getHeight();
|
||||
}
|
||||
|
||||
private record Offset(int x, int y) {}
|
||||
private record Offset(int x, int y, int height) {}
|
||||
|
||||
@SuppressWarnings("ThisEscapedInObjectConstruction")
|
||||
public OptionListWidget(int width, int height, int top, int innerHeight, List<GuiEventListener> widgets) {
|
||||
super(Minecraft.getInstance(), width, height, top, innerHeight);
|
||||
addEntry(new Entry(widgets));
|
||||
addEntry(new Entry(this, widgets));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,27 +83,46 @@ public final class OptionListWidget extends ContainerObjectSelectionList<Entry>
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void ensureVisible(@NotNull Entry entry) {
|
||||
// Scrolling to focused item is implemented in Entry.
|
||||
}
|
||||
|
||||
protected static final class Entry extends ContainerObjectSelectionList.Entry<Entry> {
|
||||
private final OptionListWidget parentWidget;
|
||||
private final List<GuiEventListener> elements;
|
||||
private final List<NarratableEntry> narratables;
|
||||
private final Map<GuiEventListener, Offset> offsets;
|
||||
|
||||
public Entry(List<GuiEventListener> elements) {
|
||||
this.elements = new ArrayList<>(elements);
|
||||
this.narratables = elements.stream().filter(e -> e instanceof NarratableEntry).map(e -> (NarratableEntry)e).collect(Collectors.toList());
|
||||
this.offsets = elements.stream().collect(Collectors.toMap(Function.identity(), OptionListWidget::getElementOffset));
|
||||
public Entry(OptionListWidget parentWidget, List<GuiEventListener> elements) {
|
||||
this.parentWidget = parentWidget;
|
||||
this.elements = List.copyOf(elements);
|
||||
this.narratables = elements.stream().filter(e -> e instanceof NarratableEntry).map(e -> (NarratableEntry)e).toList();
|
||||
this.offsets = elements.stream().collect(toMap(Function.identity(), OptionListWidget::getElementOffset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocused(@Nullable GuiEventListener element) {
|
||||
super.setFocused(element);
|
||||
|
||||
if (Minecraft.getInstance().getLastInputType().isKeyboard()) {
|
||||
Offset offset = offsets.get(element);
|
||||
if (offset != null) {
|
||||
parentWidget.setScrollAmount(offset.y + (offset.height * 0.5F) - (parentWidget.getHeight() * 0.5F) + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children() {
|
||||
return Collections.unmodifiableList(elements);
|
||||
return elements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends NarratableEntry> narratables() {
|
||||
return Collections.unmodifiableList(narratables);
|
||||
return narratables;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -2,10 +2,12 @@ package chylex.bettercontrols.gui.elements;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.gui.components.AbstractSliderButton;
|
||||
import net.minecraft.client.gui.navigation.CommonInputs;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class DiscreteValueSliderWidget<T> extends AbstractSliderButton {
|
||||
@@ -15,7 +17,7 @@ public final class DiscreteValueSliderWidget<T> extends AbstractSliderButton {
|
||||
private T selectedValue;
|
||||
|
||||
public DiscreteValueSliderWidget(int x, int y, int width, int height, Component narration, ImmutableList<Option<T>> options, T selectedValue, Consumer<T> onChanged) {
|
||||
super(x, y, width, height, Option.find(options, selectedValue).text(), options.indexOf(Option.find(options, selectedValue)) / (options.size() - 1.0));
|
||||
super(x, y, width, height, Option.find(options, selectedValue).text(), getOptionValue(options, options.indexOf(Option.find(options, selectedValue))));
|
||||
this.narration = narration;
|
||||
this.options = options;
|
||||
this.selectedValue = selectedValue;
|
||||
@@ -27,7 +29,11 @@ public final class DiscreteValueSliderWidget<T> extends AbstractSliderButton {
|
||||
}
|
||||
|
||||
public Option<T> getSelectedOption() {
|
||||
return options.get(Mth.floor(Mth.clampedLerp(0.0, options.size() - 1.0, value)));
|
||||
return options.get(getSelectedOptionIndex());
|
||||
}
|
||||
|
||||
private int getSelectedOptionIndex() {
|
||||
return Mth.floor(Mth.clampedLerp(0.0, options.size() - 1.0, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,6 +41,29 @@ public final class DiscreteValueSliderWidget<T> extends AbstractSliderButton {
|
||||
setMessage(getSelectedOption().text());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
if (CommonInputs.selected(keyCode)) {
|
||||
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
if (keyCode == GLFW.GLFW_KEY_LEFT || keyCode == GLFW.GLFW_KEY_RIGHT) {
|
||||
int newOptionIndex = keyCode == GLFW.GLFW_KEY_LEFT
|
||||
? getSelectedOptionIndex() - 1
|
||||
: getSelectedOptionIndex() + 1;
|
||||
|
||||
if (newOptionIndex >= 0 && newOptionIndex < options.size()) {
|
||||
value = getOptionValue(options, newOptionIndex);
|
||||
applyValue();
|
||||
updateMessage();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyValue() {
|
||||
T newSelectedValue = getSelectedOption().value();
|
||||
@@ -50,4 +79,8 @@ public final class DiscreteValueSliderWidget<T> extends AbstractSliderButton {
|
||||
protected MutableComponent createNarrationMessage() {
|
||||
return Component.translatable("gui.narrate.slider", narration.plainCopy().append(" ").append(getMessage()));
|
||||
}
|
||||
|
||||
private static <T> double getOptionValue(ImmutableList<Option<T>> options, int optionIndex) {
|
||||
return optionIndex / (options.size() - 1.0);
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ public final class TextWidget implements OptionWidget {
|
||||
public static final int LEFT = 0;
|
||||
public static final int CENTER = 1;
|
||||
|
||||
public static final int WHITE = 0xFF_FF_FF;
|
||||
public static final int WHITE = 0xFF_FF_FF_FF;
|
||||
|
||||
private final Component text;
|
||||
private int x;
|
||||
@@ -39,24 +39,29 @@ public final class TextWidget implements OptionWidget {
|
||||
this(x, y, width, 20, text, LEFT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -6,15 +6,19 @@ public class ToggleTracker {
|
||||
protected final KeyMapping bindingToggle;
|
||||
protected final KeyMapping bindingReset;
|
||||
|
||||
protected boolean isToggled;
|
||||
|
||||
private boolean isToggled;
|
||||
private boolean waitForRelease;
|
||||
private boolean hasToggledWhileHoldingReset;
|
||||
private boolean skipNextToggle;
|
||||
|
||||
public ToggleTracker(KeyMapping bindingToggle, KeyMapping bindingReset) {
|
||||
protected ToggleTracker(KeyMapping bindingToggle, KeyMapping bindingReset, boolean initialState) {
|
||||
this.bindingToggle = bindingToggle;
|
||||
this.bindingReset = bindingReset;
|
||||
this.isToggled = initialState;
|
||||
}
|
||||
|
||||
public ToggleTracker(KeyMapping bindingToggle, KeyMapping bindingReset) {
|
||||
this(bindingToggle, bindingReset, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -1,36 +1,36 @@
|
||||
package chylex.bettercontrols.input;
|
||||
|
||||
import chylex.bettercontrols.mixin.AccessKeyBindingFields;
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.OptionInstance;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ToggleTrackerForStickyKey extends ToggleTracker {
|
||||
private static final Set<KeyMapping> enabledOverrides = new HashSet<>();
|
||||
|
||||
@SuppressWarnings("StaticMethodOnlyUsedInOneClass")
|
||||
public static boolean isOverrideEnabled(KeyMapping binding) {
|
||||
return enabledOverrides.contains(binding);
|
||||
}
|
||||
|
||||
private final BooleanConsumer setToggleState;
|
||||
private final OptionInstance<Boolean> toggleOption;
|
||||
|
||||
public ToggleTrackerForStickyKey(KeyMapping bindingToggle, KeyMapping bindingStickyReset, BooleanConsumer setToggleState) {
|
||||
super(bindingToggle, bindingStickyReset);
|
||||
this.setToggleState = setToggleState;
|
||||
this.setToggleState.accept(false);
|
||||
public ToggleTrackerForStickyKey(KeyMapping bindingToggle, KeyMapping bindingStickyReset, OptionInstance<Boolean> toggleOption) {
|
||||
super(bindingToggle, bindingStickyReset, toggleOption.get().booleanValue());
|
||||
this.toggleOption = toggleOption;
|
||||
enabledOverrides.add(bindingStickyReset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tick() {
|
||||
boolean isToggled = super.tick();
|
||||
setToggleState.accept(isToggled);
|
||||
toggleOption.set(Boolean.valueOf(isToggled));
|
||||
return isToggled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isResetKeyPressed() {
|
||||
return ((AccessKeyBindingFields)bindingReset).isPressedField();
|
||||
return Mixins.keyMappingFields(bindingReset).isPressedField();
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,8 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(KeyMapping.class)
|
||||
public interface AccessKeyBindingFields {
|
||||
@SuppressWarnings("StaticMethodOnlyUsedInOneClass")
|
||||
public interface AccessKeyMappingFields {
|
||||
@Accessor("CATEGORY_SORT_ORDER")
|
||||
static Map<String, Integer> getCategoryOrderMap() {
|
||||
throw new AssertionError();
|
@@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Mixin(ToggleKeyMapping.class)
|
||||
public interface AccessStickyKeyBindingStateGetter {
|
||||
public interface AccessToggleKeyMappingFields {
|
||||
@Accessor
|
||||
BooleanSupplier getNeedsToggle();
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.player.PlayerTicker;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
@@ -14,9 +15,9 @@ public abstract class HookClientPlayerFOV {
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Abilities;getWalkingSpeed()F")
|
||||
)
|
||||
private float overrideWalkingSpeed(float walkingSpeed) {
|
||||
AbstractClientPlayer me = (AbstractClientPlayer)(Object)this;
|
||||
AbstractClientPlayer me = Mixins.me(this);
|
||||
|
||||
if (me instanceof LocalPlayer localPlayer && PlayerTicker.get(localPlayer).shouldResetFOV(localPlayer)) {
|
||||
if (me instanceof LocalPlayer localPlayer && PlayerTicker.shouldResetFOV(localPlayer)) {
|
||||
return 0F;
|
||||
}
|
||||
else {
|
||||
|
@@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import static org.spongepowered.asm.mixin.injection.At.Shift.AFTER;
|
||||
|
||||
@Mixin(KeyboardInput.class)
|
||||
@SuppressWarnings({ "MethodMayBeStatic", "UnreachableCode" })
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
public abstract class HookClientPlayerInputTick {
|
||||
@Inject(
|
||||
method = "tick",
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.player.PlayerTicker;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
@@ -12,7 +13,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import static org.spongepowered.asm.mixin.injection.At.Shift.AFTER;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
@SuppressWarnings("UnreachableCode")
|
||||
public abstract class HookClientPlayerTick extends AbstractClientPlayer {
|
||||
protected HookClientPlayerTick(ClientLevel world, GameProfile profile) {
|
||||
super(world, profile);
|
||||
@@ -20,22 +20,19 @@ public abstract class HookClientPlayerTick extends AbstractClientPlayer {
|
||||
|
||||
@Inject(method = "aiStep()V", at = @At("HEAD"))
|
||||
private void atHead(CallbackInfo info) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
LocalPlayer player = (LocalPlayer)(Object)this;
|
||||
LocalPlayer player = Mixins.me(this);
|
||||
PlayerTicker.get(player).atHead(player);
|
||||
}
|
||||
|
||||
@Inject(method = "aiStep()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/ClientInput;tick()V", ordinal = 0, shift = AFTER))
|
||||
private void afterInputTick(CallbackInfo info) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
LocalPlayer player = (LocalPlayer)(Object)this;
|
||||
LocalPlayer player = Mixins.me(this);
|
||||
PlayerTicker.get(player).afterInputTick(player);
|
||||
}
|
||||
|
||||
@Inject(method = "aiStep()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;aiStep()V", ordinal = 0, shift = AFTER))
|
||||
private void afterSuperCall(CallbackInfo info) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
LocalPlayer player = (LocalPlayer)(Object)this;
|
||||
LocalPlayer player = Mixins.me(this);
|
||||
PlayerTicker.get(player).afterSuperCall(player);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.player.FlightHelper;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
@@ -11,7 +12,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
@SuppressWarnings({ "SameReturnValue", "UnreachableCode" })
|
||||
public abstract class HookClientPlayerVerticalFlightSpeed extends LivingEntity {
|
||||
protected HookClientPlayerVerticalFlightSpeed(EntityType<? extends LivingEntity> type, Level world) {
|
||||
super(type, world);
|
||||
@@ -26,8 +26,7 @@ public abstract class HookClientPlayerVerticalFlightSpeed extends LivingEntity {
|
||||
)
|
||||
)
|
||||
private float modifyVerticalFlightSpeed(float flyingSpeed) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
LocalPlayer me = (LocalPlayer)(Object)this;
|
||||
LocalPlayer me = Mixins.me(this);
|
||||
return flyingSpeed * FlightHelper.getVerticalSpeedMultiplier(me);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.gui.BetterControlsScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Options;
|
||||
@@ -17,7 +18,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ControlsScreen.class)
|
||||
@SuppressWarnings("UnreachableCode")
|
||||
public abstract class HookControlsScreen extends OptionsSubScreen {
|
||||
public HookControlsScreen(Screen parentScreen, Options options, Component title) {
|
||||
super(parentScreen, options, title);
|
||||
@@ -26,8 +26,7 @@ public abstract class HookControlsScreen extends OptionsSubScreen {
|
||||
@Inject(method = "addOptions", at = @At("RETURN"))
|
||||
public void afterAddOptions(CallbackInfo ci) {
|
||||
if (list != null) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
ControlsScreen screen = (ControlsScreen)(Object)this;
|
||||
ControlsScreen screen = Mixins.me(this);
|
||||
MutableComponent buttonTitle = BetterControlsScreen.TITLE.plainCopy().append("...");
|
||||
list.addSmall(List.of(Button.builder(buttonTitle, btn -> showOptionsScreen(screen)).build()));
|
||||
}
|
||||
|
@@ -38,6 +38,6 @@ public abstract class HookLoadGameOptions {
|
||||
|
||||
hasLoaded = true;
|
||||
keyMappings = ArrayUtils.addAll(keyMappings, config.getAllKeyBindings());
|
||||
AccessKeyBindingFields.getCategoryOrderMap().put(KeyBindingWithModifier.CATEGORY, Integer.valueOf(Integer.MAX_VALUE));
|
||||
AccessKeyMappingFields.getCategoryOrderMap().put(KeyBindingWithModifier.CATEGORY, Integer.valueOf(Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,23 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.player.FlightHelper;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
public abstract class HookPlayerGliding {
|
||||
@ModifyExpressionValue(
|
||||
method = "aiStep",
|
||||
at = @At(value = "INVOKE:LAST", target = "Lnet/minecraft/world/entity/player/Input;jump()Z"),
|
||||
slice = @Slice(
|
||||
to = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;tryToStartFallFlying()Z")
|
||||
)
|
||||
)
|
||||
private boolean shouldStartGliding(boolean isHoldingJump) {
|
||||
return FlightHelper.shouldStartGliding(isHoldingJump);
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.player.FlightHelper;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
@@ -13,7 +14,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
|
||||
@Mixin(Player.class)
|
||||
@SuppressWarnings({ "SameReturnValue", "UnreachableCode" })
|
||||
public abstract class HookPlayerHorizontalFlightSpeed extends LivingEntity {
|
||||
protected HookPlayerHorizontalFlightSpeed(EntityType<? extends LivingEntity> type, Level world) {
|
||||
super(type, world);
|
||||
@@ -29,8 +29,7 @@ public abstract class HookPlayerHorizontalFlightSpeed extends LivingEntity {
|
||||
)
|
||||
)
|
||||
private boolean disableVanillaSprintBoost(boolean isSprinting) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
Player me = (Player)(Object)this;
|
||||
Player me = Mixins.me(this);
|
||||
|
||||
if (me instanceof LocalPlayer localPlayer && FlightHelper.isFlyingCreativeOrSpectator(localPlayer)) {
|
||||
return false;
|
||||
@@ -42,8 +41,7 @@ public abstract class HookPlayerHorizontalFlightSpeed extends LivingEntity {
|
||||
|
||||
@ModifyReturnValue(method = "getFlyingSpeed", at = @At("RETURN"))
|
||||
private float modifyHorizontalFlyingSpeed(float flyingSpeed) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
Player me = (Player)(Object)this;
|
||||
Player me = Mixins.me(this);
|
||||
|
||||
if (me instanceof LocalPlayer localPlayer && localPlayer.getAbilities().flying) {
|
||||
return flyingSpeed * FlightHelper.getHorizontalSpeedMultiplier(localPlayer);
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.input.ToggleTrackerForStickyKey;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.ToggleKeyMapping;
|
||||
@@ -24,7 +25,7 @@ public abstract class HookStickyKeyBindingState extends KeyMapping {
|
||||
@Inject(method = "setDown", at = @At("HEAD"), cancellable = true)
|
||||
public void setPressed(boolean pressed, CallbackInfo info) {
|
||||
if (ToggleTrackerForStickyKey.isOverrideEnabled(this)) {
|
||||
((AccessKeyBindingFields)this).setPressedField(pressed);
|
||||
Mixins.keyMappingFields(this).setPressedField(pressed);
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package chylex.bettercontrols.mixin;
|
||||
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import net.minecraft.client.OptionInstance;
|
||||
import net.minecraft.client.Options;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
@@ -10,12 +11,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(OptionInstance.class)
|
||||
@SuppressWarnings("UnreachableCode")
|
||||
public abstract class HookToggleOptionButtons {
|
||||
@Inject(method = "createButton(Lnet/minecraft/client/Options;IIILjava/util/function/Consumer;)Lnet/minecraft/client/gui/components/AbstractWidget;", at = @At("RETURN"))
|
||||
private <T> void disableToggleOptions(Options options, int x, int y, int width, Consumer<T> callback, CallbackInfoReturnable<AbstractWidget> cir) {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
OptionInstance<?> me = (OptionInstance<?>)(Object)this;
|
||||
OptionInstance<?> me = Mixins.me(this);
|
||||
|
||||
if (me == options.toggleCrouch() || me == options.toggleSprint()) {
|
||||
cir.getReturnValue().active = false;
|
||||
|
@@ -1,10 +1,9 @@
|
||||
package chylex.bettercontrols.player;
|
||||
|
||||
import chylex.bettercontrols.BetterControlsCommon;
|
||||
import chylex.bettercontrols.config.BetterControlsConfig;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import static chylex.bettercontrols.BetterControlsCommon.getConfig;
|
||||
|
||||
public final class FlightHelper {
|
||||
private FlightHelper() {}
|
||||
@@ -15,8 +14,8 @@ public final class FlightHelper {
|
||||
return KEY_SPRINT.isDown();
|
||||
}
|
||||
|
||||
private static BetterControlsConfig cfg() {
|
||||
return BetterControlsCommon.getConfig();
|
||||
public static boolean shouldStartGliding(boolean isHoldingJump) {
|
||||
return getConfig().keyStartGlide.isDown() || (getConfig().doubleTapJumpToGlide && isHoldingJump);
|
||||
}
|
||||
|
||||
public static boolean isFlyingCreativeOrSpectator(LocalPlayer player) {
|
||||
@@ -24,15 +23,15 @@ public final class FlightHelper {
|
||||
}
|
||||
|
||||
static boolean shouldFlyOnGround(LocalPlayer player) {
|
||||
return cfg().flyOnGroundInCreative && player.isCreative() && player.getAbilities().flying;
|
||||
return getConfig().flyOnGroundInCreative && player.isCreative() && player.getAbilities().flying;
|
||||
}
|
||||
|
||||
public static float getHorizontalSpeedMultiplier(LocalPlayer player) {
|
||||
if (player.isCreative()) {
|
||||
return isSprinting() ? cfg().flightHorizontalSpeedMpCreativeSprinting : cfg().flightHorizontalSpeedMpCreativeDefault;
|
||||
return isSprinting() ? getConfig().flightHorizontalSpeedMpCreativeSprinting : getConfig().flightHorizontalSpeedMpCreativeDefault;
|
||||
}
|
||||
else if (player.isSpectator()) {
|
||||
return isSprinting() ? cfg().flightHorizontalSpeedMpSpectatorSprinting : cfg().flightHorizontalSpeedMpSpectatorDefault;
|
||||
return isSprinting() ? getConfig().flightHorizontalSpeedMpSpectatorSprinting : getConfig().flightHorizontalSpeedMpSpectatorDefault;
|
||||
}
|
||||
else {
|
||||
return 1F;
|
||||
@@ -41,10 +40,10 @@ public final class FlightHelper {
|
||||
|
||||
public static float getVerticalSpeedMultiplier(LocalPlayer player) {
|
||||
if (player.isCreative()) {
|
||||
return isSprinting() ? cfg().flightVerticalSpeedMpCreativeSprinting : cfg().flightVerticalSpeedMpCreativeDefault;
|
||||
return isSprinting() ? getConfig().flightVerticalSpeedMpCreativeSprinting : getConfig().flightVerticalSpeedMpCreativeDefault;
|
||||
}
|
||||
else if (player.isSpectator()) {
|
||||
return isSprinting() ? cfg().flightVerticalSpeedMpSpectatorSprinting : cfg().flightVerticalSpeedMpSpectatorDefault;
|
||||
return isSprinting() ? getConfig().flightVerticalSpeedMpSpectatorSprinting : getConfig().flightVerticalSpeedMpSpectatorDefault;
|
||||
}
|
||||
else {
|
||||
return 1F;
|
||||
|
@@ -1,30 +1,28 @@
|
||||
package chylex.bettercontrols.player;
|
||||
|
||||
import chylex.bettercontrols.BetterControlsCommon;
|
||||
import chylex.bettercontrols.config.BetterControlsConfig;
|
||||
import chylex.bettercontrols.Mixins;
|
||||
import chylex.bettercontrols.gui.BetterControlsScreen;
|
||||
import chylex.bettercontrols.input.SprintMode;
|
||||
import chylex.bettercontrols.input.ToggleTracker;
|
||||
import chylex.bettercontrols.input.ToggleTrackerForStickyKey;
|
||||
import chylex.bettercontrols.mixin.AccessCameraFields;
|
||||
import chylex.bettercontrols.mixin.AccessClientPlayerFields;
|
||||
import chylex.bettercontrols.mixin.AccessPlayerFields;
|
||||
import chylex.bettercontrols.mixin.AccessStickyKeyBindingStateGetter;
|
||||
import chylex.bettercontrols.mixin.AccessToggleKeyMappingFields;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Options;
|
||||
import net.minecraft.client.ToggleKeyMapping;
|
||||
import net.minecraft.client.player.ClientInput;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.player.Input;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import static chylex.bettercontrols.BetterControlsCommon.getConfig;
|
||||
|
||||
public final class PlayerTicker {
|
||||
private static final Minecraft MINECRAFT = Minecraft.getInstance();
|
||||
private static final Options OPTIONS = MINECRAFT.options;
|
||||
|
||||
private static final KeyMapping KEY_SPRINT = OPTIONS.keySprint;
|
||||
private static final ToggleKeyMapping KEY_SPRINT = (ToggleKeyMapping) OPTIONS.keySprint;
|
||||
private static final KeyMapping KEY_SNEAK = OPTIONS.keyShift;
|
||||
private static final KeyMapping KEY_FORWARD = OPTIONS.keyUp;
|
||||
private static final KeyMapping KEY_JUMP = OPTIONS.keyJump;
|
||||
@@ -39,10 +37,6 @@ public final class PlayerTicker {
|
||||
return ticker;
|
||||
}
|
||||
|
||||
private static BetterControlsConfig cfg() {
|
||||
return BetterControlsCommon.getConfig();
|
||||
}
|
||||
|
||||
private final WeakReference<LocalPlayer> ref;
|
||||
|
||||
private PlayerTicker(LocalPlayer player) {
|
||||
@@ -52,10 +46,10 @@ public final class PlayerTicker {
|
||||
|
||||
// Logic
|
||||
|
||||
private final ToggleTracker toggleSprint = new ToggleTrackerForStickyKey(cfg().keyToggleSprint, KEY_SPRINT, OPTIONS.toggleSprint()::set);
|
||||
private final ToggleTracker toggleSneak = new ToggleTrackerForStickyKey(cfg().keyToggleSneak, KEY_SNEAK, OPTIONS.toggleCrouch()::set);
|
||||
private final ToggleTracker toggleWalkForward = new ToggleTracker(cfg().keyToggleWalkForward, KEY_FORWARD);
|
||||
private final ToggleTracker toggleJump = new ToggleTracker(cfg().keyToggleJump, KEY_JUMP);
|
||||
private final ToggleTracker toggleSprint = new ToggleTrackerForStickyKey(getConfig().keyToggleSprint, KEY_SPRINT, OPTIONS.toggleSprint());
|
||||
private final ToggleTracker toggleSneak = new ToggleTrackerForStickyKey(getConfig().keyToggleSneak, KEY_SNEAK, OPTIONS.toggleCrouch());
|
||||
private final ToggleTracker toggleWalkForward = new ToggleTracker(getConfig().keyToggleWalkForward, KEY_FORWARD);
|
||||
private final ToggleTracker toggleJump = new ToggleTracker(getConfig().keyToggleJump, KEY_JUMP);
|
||||
|
||||
private boolean waitingForSprintKeyRelease = false;
|
||||
private boolean stopSprintingAfterReleasingSprintKey = false;
|
||||
@@ -69,7 +63,7 @@ public final class PlayerTicker {
|
||||
private int temporaryFlyOnGroundTimer = 0;
|
||||
|
||||
private void setup() {
|
||||
AccessStickyKeyBindingStateGetter sprint = (AccessStickyKeyBindingStateGetter)KEY_SPRINT;
|
||||
AccessToggleKeyMappingFields sprint = Mixins.toggleKeyMappingFields(KEY_SPRINT);
|
||||
BooleanSupplier getter = sprint.getNeedsToggle();
|
||||
|
||||
if (getter instanceof SprintPressGetter g) {
|
||||
@@ -84,15 +78,15 @@ public final class PlayerTicker {
|
||||
player.setOnGround(false);
|
||||
}
|
||||
|
||||
if (!cfg().doubleTapForwardToSprint) {
|
||||
((AccessClientPlayerFields)player).setSprintTriggerTime(0);
|
||||
if (!getConfig().doubleTapForwardToSprint) {
|
||||
Mixins.clientPlayerFields(player).setSprintTriggerTime(0);
|
||||
}
|
||||
|
||||
if (!cfg().doubleTapJumpToToggleFlight) {
|
||||
((AccessPlayerFields)player).setJumpTriggerTime(0);
|
||||
if (!getConfig().doubleTapJumpToToggleFlight) {
|
||||
Mixins.playerFields(player).setJumpTriggerTime(0);
|
||||
}
|
||||
|
||||
SprintMode sprintMode = cfg().sprintMode;
|
||||
SprintMode sprintMode = getConfig().sprintMode;
|
||||
boolean wasSprintToggled = Boolean.TRUE.equals(OPTIONS.toggleSprint().get());
|
||||
boolean isSprintToggled = toggleSprint.tick();
|
||||
|
||||
@@ -170,7 +164,7 @@ public final class PlayerTicker {
|
||||
player.input.makeJump();
|
||||
}
|
||||
|
||||
if (cfg().resumeSprintingAfterHittingObstacle) {
|
||||
if (getConfig().resumeSprintingAfterHittingObstacle) {
|
||||
if (wasHittingObstacle != player.horizontalCollision) {
|
||||
if (!wasHittingObstacle) {
|
||||
wasSprintingBeforeHittingObstacle = player.isSprinting() || KEY_SPRINT.isDown();
|
||||
@@ -229,20 +223,26 @@ public final class PlayerTicker {
|
||||
holdingSneakWhileTouchingGround = false;
|
||||
}
|
||||
|
||||
if (FlightHelper.isFlyingCreativeOrSpectator(player) && cfg().disableFlightInertia) {
|
||||
ClientInput input = player.input;
|
||||
if (FlightHelper.isFlyingCreativeOrSpectator(player)) {
|
||||
float inertiaMultiplier = getConfig().flightInertiaMultiplier;
|
||||
|
||||
if (input.forwardImpulse == 0F && input.leftImpulse == 0F) {
|
||||
player.setDeltaMovement(player.getDeltaMovement().multiply(0.0, 1.0, 0.0));
|
||||
}
|
||||
|
||||
if (!input.keyPresses.jump() && !input.keyPresses.shift()) {
|
||||
player.setDeltaMovement(player.getDeltaMovement().multiply(1.0, 0.0, 1.0));
|
||||
if (inertiaMultiplier < 1F) {
|
||||
ClientInput input = player.input;
|
||||
Input keyPresses = input.keyPresses;
|
||||
double inertiaMultiplierSqrt = Math.sqrt(inertiaMultiplier);
|
||||
|
||||
if (!keyPresses.forward() && !keyPresses.backward() && !keyPresses.left() && !keyPresses.right()) {
|
||||
player.setDeltaMovement(player.getDeltaMovement().multiply(inertiaMultiplierSqrt, 1.0, inertiaMultiplierSqrt));
|
||||
}
|
||||
|
||||
if (!keyPresses.jump() && !keyPresses.shift()) {
|
||||
player.setDeltaMovement(player.getDeltaMovement().multiply(1.0, inertiaMultiplierSqrt, 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (player.isCreative()) {
|
||||
if (cfg().keyToggleFlight.consumeClick()) {
|
||||
if (getConfig().keyToggleFlight.consumeClick()) {
|
||||
boolean isFlying = !player.getAbilities().flying;
|
||||
|
||||
player.getAbilities().flying = isFlying;
|
||||
@@ -267,27 +267,27 @@ public final class PlayerTicker {
|
||||
temporaryFlyOnGroundTimer = 0;
|
||||
}
|
||||
|
||||
if (!cfg().sneakingMovesCameraSmoothly) {
|
||||
if (!getConfig().sneakingMovesCameraSmoothly) {
|
||||
Camera camera = MINECRAFT.gameRenderer.getMainCamera();
|
||||
|
||||
if (camera.getEntity() == player) {
|
||||
((AccessCameraFields)camera).setEyeHeight(player.getEyeHeight());
|
||||
Mixins.cameraFields(camera).setEyeHeight(player.getEyeHeight());
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg().keyResetAllToggles.consumeClick()) {
|
||||
if (getConfig().keyResetAllToggles.consumeClick()) {
|
||||
toggleSprint.reset();
|
||||
toggleSneak.reset();
|
||||
toggleWalkForward.reset();
|
||||
toggleJump.reset();
|
||||
}
|
||||
|
||||
if (cfg().keyOpenMenu.isDown()) {
|
||||
if (getConfig().keyOpenMenu.isDown()) {
|
||||
MINECRAFT.setScreen(new BetterControlsScreen(null));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldResetFOV(LocalPlayer player) {
|
||||
return cfg().disableChangingFovWhileFlying && FlightHelper.isFlyingCreativeOrSpectator(player);
|
||||
public static boolean shouldResetFOV(LocalPlayer player) {
|
||||
return getConfig().disableChangingFovWhileFlying && FlightHelper.isFlyingCreativeOrSpectator(player);
|
||||
}
|
||||
}
|
||||
|
@@ -7,9 +7,9 @@
|
||||
"client": [
|
||||
"AccessCameraFields",
|
||||
"AccessClientPlayerFields",
|
||||
"AccessKeyBindingFields",
|
||||
"AccessKeyMappingFields",
|
||||
"AccessPlayerFields",
|
||||
"AccessStickyKeyBindingStateGetter",
|
||||
"AccessToggleKeyMappingFields",
|
||||
"HookClientPlayerFOV",
|
||||
"HookClientPlayerInputTick",
|
||||
"HookClientPlayerTick",
|
||||
@@ -17,6 +17,7 @@
|
||||
"HookControlsListWidget",
|
||||
"HookControlsScreen",
|
||||
"HookLoadGameOptions",
|
||||
"HookPlayerGliding",
|
||||
"HookPlayerHorizontalFlightSpeed",
|
||||
"HookStickyKeyBindingState",
|
||||
"HookToggleOptionButtons"
|
||||
|
Reference in New Issue
Block a user