diff --git a/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java b/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java index 9db9f0b..d7bab42 100644 --- a/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java +++ b/src/main/java/chylex/bettercontrols/config/BetterControlsConfig.java @@ -11,6 +11,11 @@ public final class BetterControlsConfig{ public boolean doubleTapForwardToSprint = true; + public float flightSpeedMpCreativeDefault = 1F; + public float flightSpeedMpCreativeSprinting = 2F; + public float flightSpeedMpSpectatorDefault = 1F; + public float flightSpeedMpSpectatorSprinting = 2F; + BetterControlsConfig(){} private BetterControlsConfig setPath(final Path path){ diff --git a/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java b/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java index 4a6e00e..b1a8c83 100644 --- a/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java +++ b/src/main/java/chylex/bettercontrols/config/ConfigSerializer.java @@ -32,6 +32,11 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js Json.setBool(obj, "Sprint.DoubleTapForward", cfg.doubleTapForwardToSprint); + Json.setFloat(obj, "Flight.SpeedMp.Creative.Default", cfg.flightSpeedMpCreativeDefault); + Json.setFloat(obj, "Flight.SpeedMp.Creative.Sprinting", cfg.flightSpeedMpCreativeSprinting); + Json.setFloat(obj, "Flight.SpeedMp.Spectator.Default", cfg.flightSpeedMpSpectatorDefault); + Json.setFloat(obj, "Flight.SpeedMp.Spectator.Sprinting", cfg.flightSpeedMpSpectatorSprinting); + return obj; } @@ -42,6 +47,11 @@ final class ConfigSerializer implements JsonSerializer<BetterControlsConfig>, Js cfg.doubleTapForwardToSprint = Json.getBool(obj, "Sprint.DoubleTapForward", cfg.doubleTapForwardToSprint); + cfg.flightSpeedMpCreativeDefault = Json.getFloat(obj, "Flight.SpeedMp.Creative.Default", cfg.flightSpeedMpCreativeDefault); + cfg.flightSpeedMpCreativeSprinting = Json.getFloat(obj, "Flight.SpeedMp.Creative.Sprinting", cfg.flightSpeedMpCreativeSprinting); + cfg.flightSpeedMpSpectatorDefault = Json.getFloat(obj, "Flight.SpeedMp.Spectator.Default", cfg.flightSpeedMpSpectatorDefault); + cfg.flightSpeedMpSpectatorSprinting = Json.getFloat(obj, "Flight.SpeedMp.Spectator.Sprinting", cfg.flightSpeedMpSpectatorSprinting); + return cfg; } diff --git a/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java b/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java index 233c7e0..a0231d9 100644 --- a/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java +++ b/src/main/java/chylex/bettercontrols/gui/BetterControlsScreen.java @@ -2,7 +2,9 @@ package chylex.bettercontrols.gui; import chylex.bettercontrols.BetterControlsMod; import chylex.bettercontrols.config.BetterControlsConfig; import chylex.bettercontrols.gui.elements.BooleanValueWidget; +import chylex.bettercontrols.gui.elements.DiscreteValueSliderWidget; import chylex.bettercontrols.gui.elements.KeyBindingWidget; +import chylex.bettercontrols.gui.elements.Option; import chylex.bettercontrols.gui.elements.TextWidget; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Element; @@ -17,6 +19,7 @@ import net.minecraft.text.LiteralText; import net.minecraft.text.Text; import org.lwjgl.glfw.GLFW; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static chylex.bettercontrols.gui.OptionListWidget.COL2_W; import static chylex.bettercontrols.gui.OptionListWidget.ROW_WIDTH; @@ -43,6 +46,45 @@ public class BetterControlsScreen extends GameOptionsScreen{ return y; } + @SuppressWarnings({ "AutoBoxing", "AutoUnboxing" }) + private int generateFlightOptions(int y, final List<Element> elements){ + final BetterControlsConfig cfg = BetterControlsMod.config; + + final List<Option<Float>> flightSpeedOptions = Arrays.asList( + new Option<>(Float.valueOf(0.25F), Text.of("0.25x")), + new Option<>(Float.valueOf(0.50F), Text.of("0.5x")), + new Option<>(Float.valueOf(0.75F), Text.of("0.75x")), + new Option<>(Float.valueOf(1.00F), Text.of("1x")), + new Option<>(Float.valueOf(1.50F), Text.of("1.5x")), + new Option<>(Float.valueOf(2.00F), Text.of("2x")), + new Option<>(Float.valueOf(3.00F), Text.of("3x")), + new Option<>(Float.valueOf(4.00F), Text.of("4x")), + new Option<>(Float.valueOf(6.00F), Text.of("6x")), + new Option<>(Float.valueOf(8.00F), Text.of("8x")) + ); + + generateLeftSideText(y, elements, Text.of("Speed Multiplier (Creative)")); + elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpCreativeDefault, value -> cfg.flightSpeedMpCreativeDefault = value)); + + y += ROW_HEIGHT; + + generateLeftSideText(y, elements, Text.of("Speed Multiplier (Creative + Sprinting)")); + elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpCreativeSprinting, value -> cfg.flightSpeedMpCreativeSprinting = value)); + + y += ROW_HEIGHT; + + generateLeftSideText(y, elements, Text.of("Speed Multiplier (Spectator)")); + elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpSpectatorDefault, value -> cfg.flightSpeedMpSpectatorDefault = value)); + + y += ROW_HEIGHT; + + generateLeftSideText(y, elements, Text.of("Speed Multiplier (Spectator + Sprinting)")); + elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpSpectatorSprinting, value -> cfg.flightSpeedMpSpectatorSprinting = value)); + + y += ROW_HEIGHT; + return y; + } + // Helpers private static void generateLeftSideText(final int y, final List<Element> elements, final Text text){ @@ -69,6 +111,9 @@ public class BetterControlsScreen extends GameOptionsScreen{ elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, Text.of("Sprinting"), CENTER)); y = generateSprintingOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP; + elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, Text.of("Flying"), CENTER)); + y = generateFlightOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP; + addButton(new ButtonWidget(width / 2 - 99, height - 29, 200, 20, ScreenTexts.DONE, btn -> client.openScreen(parent))); addChild(optionsWidget = new OptionListWidget(21, height - 32, width, height, elements, y - TITLE_MARGIN_TOP + BOTTOM_PADDING)); } diff --git a/src/main/java/chylex/bettercontrols/mixin/HookClientPlayerTick.java b/src/main/java/chylex/bettercontrols/mixin/HookClientPlayerTick.java index 0ca4ea2..faf2e62 100644 --- a/src/main/java/chylex/bettercontrols/mixin/HookClientPlayerTick.java +++ b/src/main/java/chylex/bettercontrols/mixin/HookClientPlayerTick.java @@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static org.spongepowered.asm.mixin.injection.At.Shift.AFTER; @Mixin(ClientPlayerEntity.class) public abstract class HookClientPlayerTick extends AbstractClientPlayerEntity{ @@ -20,4 +21,10 @@ public abstract class HookClientPlayerTick extends AbstractClientPlayerEntity{ final ClientPlayerEntity player = (ClientPlayerEntity)(Object)this; PlayerTicker.get(player).atHead(player); } + + @Inject(method = "tickMovement()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(Z)V", ordinal = 0, shift = AFTER)) + private void afterInputTick(final CallbackInfo info){ + final ClientPlayerEntity player = (ClientPlayerEntity)(Object)this; + PlayerTicker.get(player).afterInputTick(player); + } } diff --git a/src/main/java/chylex/bettercontrols/player/FlightHelper.java b/src/main/java/chylex/bettercontrols/player/FlightHelper.java new file mode 100644 index 0000000..d3e38d2 --- /dev/null +++ b/src/main/java/chylex/bettercontrols/player/FlightHelper.java @@ -0,0 +1,37 @@ +package chylex.bettercontrols.player; +import chylex.bettercontrols.BetterControlsMod; +import chylex.bettercontrols.config.BetterControlsConfig; +import net.minecraft.client.network.ClientPlayerEntity; + +final class FlightHelper{ + private FlightHelper(){} + + private static final float BASE_FLIGHT_SPEED = 0.05F; + private static final float BASE_FLIGHT_SPEED_SPRINT_MP_INV = 0.5F; // sprinting doubles speed in PlayerEntity.travel + + private static BetterControlsConfig cfg(){ + return BetterControlsMod.config; + } + + static float getFlightSpeed(final ClientPlayerEntity player){ + if (player.isCreative()){ + if (player.isSprinting()){ + return BASE_FLIGHT_SPEED * cfg().flightSpeedMpCreativeSprinting * BASE_FLIGHT_SPEED_SPRINT_MP_INV; + } + else{ + return BASE_FLIGHT_SPEED * cfg().flightSpeedMpCreativeDefault; + } + } + else if (player.isSpectator()){ + if (player.isSprinting()){ + return BASE_FLIGHT_SPEED * cfg().flightSpeedMpSpectatorSprinting * BASE_FLIGHT_SPEED_SPRINT_MP_INV; + } + else{ + return BASE_FLIGHT_SPEED * cfg().flightSpeedMpSpectatorDefault; + } + } + else{ + return 0F; + } + } +} diff --git a/src/main/java/chylex/bettercontrols/player/PlayerTicker.java b/src/main/java/chylex/bettercontrols/player/PlayerTicker.java index 4610009..3556287 100644 --- a/src/main/java/chylex/bettercontrols/player/PlayerTicker.java +++ b/src/main/java/chylex/bettercontrols/player/PlayerTicker.java @@ -38,4 +38,12 @@ public final class PlayerTicker{ ((AccessClientPlayerFields)player).setTicksLeftToDoubleTapSprint(0); } } + + public void afterInputTick(final ClientPlayerEntity player){ + final float flightSpeed = FlightHelper.getFlightSpeed(player); + + if (flightSpeed > 0F){ + player.abilities.setFlySpeed(flightSpeed); + } + } }