diff --git a/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java b/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java index 186c750..895f661 100644 --- a/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java +++ b/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java @@ -1,5 +1,6 @@ package chylex.bettercontrols.config; import chylex.bettercontrols.input.KeyBindingWithModifier; +import chylex.bettercontrols.input.SprintMode; import net.minecraft.client.options.KeyBinding; import java.nio.file.Path; @@ -11,14 +12,15 @@ public final class BetterControlsConfig{ private Path path; public final KeyBindingWithModifier keyToggleSprint = new KeyBindingWithModifier("key.bettercontrols.toggle_sprint"); + public SprintMode sprintMode = SprintMode.TAP_TO_START; public boolean doubleTapForwardToSprint = true; - public boolean tapSprintKeyAgainToStopSprinting = false; public boolean resumeSprintingAfterHittingObstacle = false; public final KeyBindingWithModifier keyToggleSneak = new KeyBindingWithModifier("key.bettercontrols.toggle_sneak"); public boolean sneakingMovesCameraSmoothly = true; public final KeyBindingWithModifier keyToggleFlight = new KeyBindingWithModifier("key.bettercontrols.toggle_flight"); + public SprintMode sprintModeWhileFlying = SprintMode.TAP_TO_START; public boolean flyOnGroundInCreative = false; public float flightSpeedMpCreativeDefault = 1F; public float flightSpeedMpCreativeSprinting = 2F; diff --git a/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java b/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java index 7a5e640..1492b13 100644 --- a/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java +++ b/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java @@ -1,4 +1,5 @@ package chylex.bettercontrols.config; +import chylex.bettercontrols.input.SprintMode; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; @@ -32,14 +33,15 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js final JsonObject obj = new JsonObject(); Json.writeKeyBinding(obj, "Sprint.KeyToggle", cfg.keyToggleSprint); + Json.setEnum(obj, "Sprint.Mode", cfg.sprintMode); Json.setBool(obj, "Sprint.DoubleTapForward", cfg.doubleTapForwardToSprint); - Json.setBool(obj, "Sprint.TapToStop", cfg.tapSprintKeyAgainToStopSprinting); Json.setBool(obj, "Sprint.ResumeAfterHittingObstacle", cfg.resumeSprintingAfterHittingObstacle); Json.writeKeyBinding(obj, "Sneak.KeyToggle", cfg.keyToggleSneak); Json.setBool(obj, "Sneak.SmoothCamera", cfg.sneakingMovesCameraSmoothly); Json.writeKeyBinding(obj, "Flight.KeyToggle.Creative", cfg.keyToggleFlight); + Json.setEnum(obj, "Flight.SprintMode", cfg.sprintModeWhileFlying); Json.setBool(obj, "Flight.FlyOnGround.Creative", cfg.flyOnGroundInCreative); Json.setFloat(obj, "Flight.SpeedMp.Creative.Default", cfg.flightSpeedMpCreativeDefault); Json.setFloat(obj, "Flight.SpeedMp.Creative.Sprinting", cfg.flightSpeedMpCreativeSprinting); @@ -58,15 +60,20 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js final BetterControlsConfig cfg = new BetterControlsConfig(); final JsonObject obj = json.getAsJsonObject(); + if (obj.has("Sprint.TapToStop") && obj.get("Sprint.TapToStop").getAsBoolean()){ + cfg.sprintMode = SprintMode.TAP_TO_TOGGLE; + } + 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); - cfg.tapSprintKeyAgainToStopSprinting = Json.getBool(obj, "Sprint.TapToStop", cfg.tapSprintKeyAgainToStopSprinting); cfg.resumeSprintingAfterHittingObstacle = Json.getBool(obj, "Sprint.ResumeAfterHittingObstacle", cfg.resumeSprintingAfterHittingObstacle); Json.readKeyBinding(obj, "Sneak.KeyToggle", cfg.keyToggleSneak); cfg.sneakingMovesCameraSmoothly = Json.getBool(obj, "Sneak.SmoothCamera", cfg.sneakingMovesCameraSmoothly); Json.readKeyBinding(obj, "Flight.KeyToggle.Creative", cfg.keyToggleFlight); + cfg.sprintModeWhileFlying = Json.getEnum(obj, "Flight.SprintMode", cfg.sprintModeWhileFlying, SprintMode.class); cfg.flyOnGroundInCreative = Json.getBool(obj, "Flight.FlyOnGround.Creative", cfg.flyOnGroundInCreative); cfg.flightSpeedMpCreativeDefault = MathHelper.clamp(Json.getFloat(obj, "Flight.SpeedMp.Creative.Default", cfg.flightSpeedMpCreativeDefault), 0.25F, 8F); cfg.flightSpeedMpCreativeSprinting = MathHelper.clamp(Json.getFloat(obj, "Flight.SpeedMp.Creative.Sprinting", cfg.flightSpeedMpCreativeSprinting), 0.25F, 8F); diff --git a/src/main/java/chylex/bettercontrols/config/Json.java b/src/main/java/chylex/bettercontrols/config/Json.java index 7efb7d3..0e4c26a 100644 --- a/src/main/java/chylex/bettercontrols/config/Json.java +++ b/src/main/java/chylex/bettercontrols/config/Json.java @@ -31,6 +31,30 @@ final class Json{ return obj.has(key) ? obj.get(key).getAsBoolean() : defaultValue; } + static <T extends Enum<T>> void setEnum(final JsonObject obj, final String key, final T value){ + obj.addProperty(key, value.name()); + } + + static <T extends Enum<T>> T getEnum(final JsonObject obj, final String key, final T defaultValue, final Class<T> enumClass){ + if (!obj.has(key)){ + return defaultValue; + } + + final T[] constants = enumClass.getEnumConstants(); + + if (constants != null){ + final String value = obj.get(key).getAsString(); + + for(final T constant : constants){ + if (constant.name().equalsIgnoreCase(value)){ + return constant; + } + } + } + + return defaultValue; + } + private static final String KEY_SUFFIX = ".Key"; private static final String MOD_SUFFIX = ".Mod"; diff --git a/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java b/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java index c418ea4..3bb2ceb 100644 --- a/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java +++ b/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java @@ -9,6 +9,7 @@ import chylex.bettercontrols.gui.elements.Option; import chylex.bettercontrols.gui.elements.TextWidget; import chylex.bettercontrols.input.KeyBindingWithModifier; import chylex.bettercontrols.input.ModifierKey; +import chylex.bettercontrols.input.SprintMode; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.screen.Screen; @@ -39,6 +40,12 @@ public class BetterControlsScreen extends GameOptionsScreen{ private static final int TITLE_MARGIN_TOP = 3; private static final int ROW_HEIGHT = 22; + private final List<Option<SprintMode>> SPRINT_MODE_OPTIONS = Arrays.asList( + new Option<>(SprintMode.TAP_TO_START, Text.of("Tap To Start Sprinting")), + new Option<>(SprintMode.TAP_TO_TOGGLE, Text.of("Tap To Start / Stop Sprinting")), + new Option<>(SprintMode.HOLD, Text.of("Hold To Sprint")) + ); + // Options private int generateSprintingOptions(int y, final List<Element> elements){ @@ -48,13 +55,13 @@ public class BetterControlsScreen extends GameOptionsScreen{ y += ROW_HEIGHT; - generateLeftSideText(y, elements, Text.of("Double Tap 'Walk Forwards' To Sprint")); - elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.doubleTapForwardToSprint, value -> cfg.doubleTapForwardToSprint = value)); + generateLeftSideText(y, elements, Text.of("Sprint Key Mode")); + elements.add(new CycleButtonWidget<>(col2(1), y, COL2_W, SPRINT_MODE_OPTIONS, cfg.sprintMode, value -> cfg.sprintMode = value)); y += ROW_HEIGHT; - generateLeftSideText(y, elements, Text.of("Tap 'Sprint' While Sprinting To Stop")); - elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.tapSprintKeyAgainToStopSprinting, value -> cfg.tapSprintKeyAgainToStopSprinting = value)); + generateLeftSideText(y, elements, Text.of("Double Tap 'Walk Forwards' To Sprint")); + elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.doubleTapForwardToSprint, value -> cfg.doubleTapForwardToSprint = value)); y += ROW_HEIGHT; @@ -100,6 +107,11 @@ public class BetterControlsScreen extends GameOptionsScreen{ y += ROW_HEIGHT; + generateLeftSideText(y, elements, Text.of("Sprint Key Mode While Flying")); + elements.add(new CycleButtonWidget<>(col2(1), y, COL2_W, SPRINT_MODE_OPTIONS, cfg.sprintModeWhileFlying, value -> cfg.sprintModeWhileFlying = value)); + + y += ROW_HEIGHT; + generateLeftSideText(y, elements, Text.of("Fly On Ground (Creative Mode)")); elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.flyOnGroundInCreative, value -> cfg.flyOnGroundInCreative = value)); diff --git a/src/main/java/chylex/bettercontrols/input/SprintMode.java b/src/main/java/chylex/bettercontrols/input/SprintMode.java new file mode 100644 index 0000000..1f65e9d --- /dev/null +++ b/src/main/java/chylex/bettercontrols/input/SprintMode.java @@ -0,0 +1,7 @@ +package chylex.bettercontrols.input; + +public enum SprintMode{ + TAP_TO_START, + TAP_TO_TOGGLE, + HOLD +} diff --git a/src/main/java/chylex/bettercontrols/player/PlayerTicker.java b/src/main/java/chylex/bettercontrols/player/PlayerTicker.java index fe968ce..805c958 100644 --- a/src/main/java/chylex/bettercontrols/player/PlayerTicker.java +++ b/src/main/java/chylex/bettercontrols/player/PlayerTicker.java @@ -2,6 +2,7 @@ package chylex.bettercontrols.player; import chylex.bettercontrols.BetterControlsMod; import chylex.bettercontrols.config.BetterControlsConfig; 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; @@ -78,6 +79,15 @@ public final class PlayerTicker{ ((AccessClientPlayerFields)player).setTicksLeftToDoubleTapSprint(0); } + final SprintMode sprintMode; + + if (player.abilities.flying && (player.isCreative() || player.isSpectator())){ + sprintMode = cfg().sprintModeWhileFlying; + } + else{ + sprintMode = cfg().sprintMode; + } + final GameOptions opts = mc().options; final boolean wasSprintToggled = opts.sprintToggled; final boolean isSprintToggled = toggleSprint.tick(); @@ -92,7 +102,7 @@ public final class PlayerTicker{ if (!opts.keySprint.isPressed() && opts.keyForward.isPressed()){ temporarySprintTimer = nextTemporarySprintTimer; } - else if (cfg().tapSprintKeyAgainToStopSprinting){ + else if (sprintMode == SprintMode.TAP_TO_TOGGLE){ stopSprintingAfterReleasingSprintKey = true; } } @@ -105,7 +115,7 @@ public final class PlayerTicker{ stopSprintingAfterReleasingSprintKey = true; waitingForSprintKeyRelease = true; } - else if (cfg().tapSprintKeyAgainToStopSprinting){ + else if (sprintMode == SprintMode.TAP_TO_TOGGLE){ if (opts.keySprint.isPressed()){ if (!waitingForSprintKeyRelease){ waitingForSprintKeyRelease = true; @@ -120,6 +130,11 @@ public final class PlayerTicker{ waitingForSprintKeyRelease = false; } } + else if (sprintMode == SprintMode.HOLD){ + if (opts.keySprint.isPressed()){ + stopSprintingAfterReleasingSprintKey = true; + } + } if (stopSprintingAfterReleasingSprintKey && !opts.keySprint.isPressed()){ stopSprintingAfterReleasingSprintKey = false;