diff --git a/README.md b/README.md index cad1698..4e6a4a9 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,14 @@ This mod adds a controller support (and an experimental touchscreen support). - Touchscreen support (very experimental and buggy). - Keyboard controls to look around. - Toggleable on screen button indicator (like in Bedrock Edition). + - Vertical reacharound. - Many Bedrock Edition features: - Toggleable fly drifting - Front block placing (be careful with this one) - New controls settings! - Many options in config to change to your liking. - Many controllers supported and in a simply way your own controller mappings. + - An easy API for developers to add their own button bindings. ## 🎮 Supported Controllers: diff --git a/core/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsFeature.java b/core/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsFeature.java index e341299..94303fc 100644 --- a/core/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsFeature.java +++ b/core/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsFeature.java @@ -21,14 +21,15 @@ * Represents a feature. * * @author LambdAurora - * @version 1.2.0 + * @version 1.3.2 * @since 1.1.0 */ public class LambdaControlsFeature implements Nameable { - private static final List FEATURES = new ArrayList<>(); - public static final LambdaControlsFeature FRONT_BLOCK_PLACING = new LambdaControlsFeature("front_block_placing", true, false); - public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true); + private static final List FEATURES = new ArrayList<>(); + public static final LambdaControlsFeature FAST_BLOCK_PLACING = new LambdaControlsFeature("fast_block_placing", true, true); + public static final LambdaControlsFeature FRONT_BLOCK_PLACING = new LambdaControlsFeature("front_block_placing", true, false); + public static final LambdaControlsFeature VERTICAL_REACHAROUND = new LambdaControlsFeature("vertical_reacharound", true, false); private final String key; private final boolean defaultAllowed; @@ -155,7 +156,8 @@ public static void resetAllAllowed() } static { - FEATURES.add(FRONT_BLOCK_PLACING); FEATURES.add(FAST_BLOCK_PLACING); + FEATURES.add(FRONT_BLOCK_PLACING); + FEATURES.add(VERTICAL_REACHAROUND); } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java index c88d6b6..e8fd643 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java @@ -23,7 +23,6 @@ import me.lambdaurora.spruceui.hud.HudManager; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.minecraft.client.MinecraftClient; @@ -40,7 +39,7 @@ * Represents the LambdaControls client mod. * * @author LambdAurora - * @version 1.3.0 + * @version 1.3.2 * @since 1.1.0 */ public class LambdaControlsClient extends LambdaControls implements ClientModInitializer @@ -59,6 +58,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png"); public final LambdaControlsConfig config = new LambdaControlsConfig(this); public final LambdaInput input = new LambdaInput(this); + public final LambdaReacharound reacharound = new LambdaReacharound(); private LambdaControlsHud hud; private ControlsMode previousControlsMode; @@ -79,6 +79,7 @@ public void onInitializeClient() LambdaControlsFeature.fromName(name).ifPresent(feature -> context.getTaskQueue().execute(() -> feature.setAllowed(allowed))); }); + ClientTickEvents.START_CLIENT_TICK.register(this.reacharound::tick); ClientTickEvents.END_CLIENT_TICK.register(this::onTick); OpenScreenCallback.EVENT.register((client, screen) -> { diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java index b4ccf21..24b064f 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java @@ -34,37 +34,39 @@ public class LambdaControlsConfig { // General - private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT; - private static final boolean DEFAULT_AUTO_SWITCH_MODE = false; + private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT; + private static final boolean DEFAULT_AUTO_SWITCH_MODE = false; // HUD - private static final boolean DEFAULT_HUD_ENABLE = true; - private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT; + private static final boolean DEFAULT_HUD_ENABLE = true; + private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT; // Gameplay - private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true; - private static final boolean DEFAULT_FLY_DRIFTING = false; - private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true; - private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false; - private static final boolean DEFAULT_FRONT_BLOCK_OUTLINE = true; + private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true; + private static final boolean DEFAULT_FLY_DRIFTING = false; + private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true; + private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false; + private static final boolean DEFAULT_VERTICAL_REACHAROUND = false; + private static final boolean DEFAULT_REACHAROUND_OUTLINE = true; + private static final int[] DEFAULT_REACHAROUND_OUTLINE_COLOR = new int[]{255, 255, 255, 102}; // Controller - private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT; - private static final double DEFAULT_DEAD_ZONE = 0.25; - private static final double DEFAULT_ROTATION_SPEED = 40.0; - private static final double DEFAULT_MOUSE_SPEED = 25.0; - private static final boolean DEFAULT_UNFOCUSED_INPUT = false; - private static final boolean DEFAULT_VIRTUAL_MOUSE = false; - private static final VirtualMouseSkin DEFAULT_VIRTUAL_MOUSE_SKIN = VirtualMouseSkin.DEFAULT_LIGHT; + private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT; + private static final double DEFAULT_DEAD_ZONE = 0.25; + private static final double DEFAULT_ROTATION_SPEED = 40.0; + private static final double DEFAULT_MOUSE_SPEED = 25.0; + private static final boolean DEFAULT_UNFOCUSED_INPUT = false; + private static final boolean DEFAULT_VIRTUAL_MOUSE = false; + private static final VirtualMouseSkin DEFAULT_VIRTUAL_MOUSE_SKIN = VirtualMouseSkin.DEFAULT_LIGHT; private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?"); protected final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build(); private final LambdaControlsClient mod; private ControlsMode controlsMode; - private ControllerType controllerType; + private ControllerType controllerType; // Gameplay. - private boolean shouldRenderFrontBlockOutline; - private int[] frontBlockOutlineColor; + private boolean shouldRenderReacharoundOutline; + private int[] reacharoundOutlineColor; // Controller settings - private double deadZone; + private double deadZone; private double rotationSpeed; private double mouseSpeed; private boolean unfocusedInput; @@ -93,9 +95,10 @@ public void load() this.hudSide = HudSide.byId(this.config.getOrElse("hud.side", DEFAULT_HUD_SIDE.getName())).orElse(DEFAULT_HUD_SIDE); // Gameplay LambdaControlsFeature.FAST_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.fast_block_placing", DEFAULT_FAST_BLOCK_INTERACTION)); - LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.front_block_placing.enabled", DEFAULT_FRONT_BLOCK_PLACING)); - this.shouldRenderFrontBlockOutline = this.config.getOrElse("gameplay.front_block_placing.outline", DEFAULT_FRONT_BLOCK_OUTLINE); - this.frontBlockOutlineColor = this.config.getOptional("gameplay.front_block_placing.outline_color").map(hex -> parseColor((String) hex)).orElse(new int[]{255, 255, 255, 102}); + LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(this.config.getOrElse("gameplay.reacharound.horizontal", DEFAULT_FRONT_BLOCK_PLACING)); + LambdaControlsFeature.VERTICAL_REACHAROUND.setEnabled(this.config.getOrElse("gameplay.reacharound.vertical", DEFAULT_VERTICAL_REACHAROUND)); + this.shouldRenderReacharoundOutline = this.config.getOrElse("gameplay.reacharound.outline", DEFAULT_REACHAROUND_OUTLINE); + this.reacharoundOutlineColor = this.config.getOptional("gameplay.reacharound.outline_color").map(hex -> parseColor((String) hex)).orElse(DEFAULT_REACHAROUND_OUTLINE_COLOR); // Controller settings. this.controllerType = ControllerType.byId(this.config.getOrElse("controller.type", DEFAULT_CONTROLLER_TYPE.getName())).orElse(DEFAULT_CONTROLLER_TYPE); this.deadZone = this.config.getOrElse("controller.dead_zone", DEFAULT_DEAD_ZONE); @@ -133,10 +136,19 @@ public void checkAndFix() } }); - // This shouldn't happen if the configuration is new. - if (!this.config.contains("gameplay.front_block_placing.enabled") && this.config.contains("gameplay.front_block_placing")) { - this.config.remove("gameplay.front_block_placing"); - this.config.set("gameplay.front_block_placing.enabled", DEFAULT_FRONT_BLOCK_PLACING); + if (this.config.contains("gameplay.front_block_placing.enabled")) { + this.setFrontBlockPlacing(this.config.getOrElse("gameplay.front_block_placing.enabled", DEFAULT_FRONT_BLOCK_PLACING)); + this.config.remove("gameplay.front_block_placing.enabled"); + } + + if (this.config.contains("gameplay.front_block_placing.outline")) { + this.setRenderReacharoundOutline(this.config.getOrElse("gameplay.front_block_placing.outline", DEFAULT_REACHAROUND_OUTLINE)); + this.config.remove("gameplay.front_block_placing.outline"); + } + + if (this.config.contains("gameplay.front_block_placing.outline_color")) { + this.config.getOptional("gameplay.front_block_placing.outline_color").ifPresent(color -> this.config.set("gameplay.reacharound.outline_color", color)); + this.config.remove("gameplay.front_block_placing.outline_color"); } this.renamed("controller.controls.tab_left", "controller.controls.tab_back"); @@ -165,7 +177,8 @@ public void reset() this.setFlyDrifting(DEFAULT_FLY_DRIFTING); this.setFlyVerticalDrifting(DEFAULT_FLY_VERTICAL_DRIFTING); this.setFrontBlockPlacing(DEFAULT_FRONT_BLOCK_PLACING); - this.setRenderFrontBlockOutline(DEFAULT_FRONT_BLOCK_OUTLINE); + this.setVerticalReacharound(DEFAULT_VERTICAL_REACHAROUND); + this.setRenderReacharoundOutline(DEFAULT_REACHAROUND_OUTLINE); // Controller this.setControllerType(DEFAULT_CONTROLLER_TYPE); this.setDeadZone(DEFAULT_DEAD_ZONE); @@ -352,7 +365,28 @@ public boolean hasFrontBlockPlacing() public void setFrontBlockPlacing(boolean enable) { LambdaControlsFeature.FRONT_BLOCK_PLACING.setEnabled(enable); - this.config.set("gameplay.front_block_placing.enabled", enable); + this.config.set("gameplay.reacharound.horizontal", enable); + } + + /** + * Returns whether vertical reacharound is enabled or not. + * + * @return True if vertical reacharound is enabled, else false. + */ + public boolean hasVerticalReacharound() + { + return LambdaControlsFeature.VERTICAL_REACHAROUND.isEnabled(); + } + + /** + * Sets whether vertical reacharound is enabled or not. + * + * @param enable True if vertical reacharound is enabled, else false. + */ + public void setVerticalReacharound(boolean enable) + { + LambdaControlsFeature.VERTICAL_REACHAROUND.setEnabled(enable); + this.config.set("gameplay.reacharound.vertical", enable); } /** @@ -360,9 +394,9 @@ public void setFrontBlockPlacing(boolean enable) * * @return True if front block placing outline is enabled, else false. */ - public boolean shouldRenderFrontBlockOutline() + public boolean shouldRenderReacharoundOutline() { - return this.shouldRenderFrontBlockOutline; + return this.shouldRenderReacharoundOutline; } /** @@ -370,9 +404,9 @@ public boolean shouldRenderFrontBlockOutline() * * @param render True if front block placing outline is enabled, else false. */ - public void setRenderFrontBlockOutline(boolean render) + public void setRenderReacharoundOutline(boolean render) { - this.config.set("gameplay.front_block_placing.outline", this.shouldRenderFrontBlockOutline = render); + this.config.set("gameplay.reacharound.outline", this.shouldRenderReacharoundOutline = render); } /** @@ -382,9 +416,9 @@ public void setRenderFrontBlockOutline(boolean render) * * @return The color as a RGBA integer array. */ - public int[] getFrontBlockOutlineColor() + public int[] getReacharoundOutlineColor() { - return this.frontBlockOutlineColor; + return this.reacharoundOutlineColor; } /* diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java index c6754a2..a2ccee7 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java @@ -9,7 +9,6 @@ package me.lambdaurora.lambdacontrols.client; -import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.Controller; @@ -22,10 +21,6 @@ import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import me.lambdaurora.spruceui.SpruceLabelWidget; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.FluidBlock; -import net.minecraft.block.SlabBlock; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.ParentElement; @@ -42,14 +37,8 @@ import net.minecraft.client.gui.widget.EntryListWidget; import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.SlotActionType; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import org.aperlambda.lambdacommon.utils.Pair; import org.jetbrains.annotations.NotNull; @@ -72,7 +61,7 @@ * Represents the LambdaControls' input handler. * * @author LambdAurora - * @version 1.3.1 + * @version 1.3.2 * @since 1.0.0 */ public class LambdaInput @@ -325,7 +314,8 @@ private void handleButton(@NotNull MinecraftClient client, int button, int actio if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) { if (client.currentScreen != null) { - client.currentScreen.onClose(); + if (!LambdaControlsCompat.handleMenuBack(client, client.currentScreen)) + client.currentScreen.onClose(); return; } } @@ -390,6 +380,8 @@ private boolean handleInventory(@NotNull MinecraftClient client, int button) if (screen instanceof CreativeInventoryScreen) if (((CreativeInventoryScreenAccessor) screen).lambdacontrols_isCreativeInventorySlot(slot)) actionType = SlotActionType.CLONE; + if (slot != null && LambdaControlsCompat.streamCompatHandlers().anyMatch(handler -> handler.isCreativeSlot(screen, slot))) + actionType = SlotActionType.CLONE; break; case GLFW.GLFW_GAMEPAD_BUTTON_X: clickData = GLFW_MOUSE_BUTTON_2; @@ -720,71 +712,4 @@ private void moveMouseToClosestSlot(@NotNull MinecraftClient client, @Nullable S this.mouseSpeedY = 0.F; } } - - public static Direction getMoveDirection(@Nullable BlockPos lastPos, @NotNull BlockPos newPos) - { - if (lastPos == null) - return null; - BlockPos vector = newPos.subtract(lastPos); - if (vector.getX() > 0) - return Direction.EAST; - else if (vector.getX() < 0) - return Direction.WEST; - else if (vector.getZ() > 0) - return Direction.SOUTH; - else if (vector.getZ() < 0) - return Direction.NORTH; - else if (vector.getY() > 0) - return Direction.UP; - else if (vector.getY() < 0) - return Direction.DOWN; - return null; - } - - /** - * Returns a nullable block hit result if front placing is possible. - * - * @param client The client instance. - * @return A block hit result if front placing is possible. - */ - public static @Nullable BlockHitResult tryFrontPlace(@NotNull MinecraftClient client) - { - if (!LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable()) - return null; - if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS && client.player.isOnGround() && client.player.pitch > 35.0F) { - if (client.player.isRiding()) - return null; - BlockPos playerPos = client.player.getBlockPos().down(); - BlockPos targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos); - BlockPos vector = new BlockPos(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1)); - BlockPos blockPos = playerPos.add(vector); - - Direction direction = client.player.getHorizontalFacing(); - - BlockState state = client.world.getBlockState(blockPos); - if (!state.isAir()) - return null; - BlockState adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite())); - if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) { - return null; - } - - return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false); - } - return null; - } - - public static @NotNull BlockHitResult withSideForFrontPlace(@NotNull BlockHitResult result, @Nullable ItemStack stack) - { - if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem)) - return result; - return withSideForFrontPlace(result, Block.getBlockFromItem(stack.getItem())); - } - - public static @NotNull BlockHitResult withSideForFrontPlace(@NotNull BlockHitResult result, @NotNull Block block) - { - if (block instanceof SlabBlock) - result = result.withSide(Direction.DOWN); - return result; - } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaReacharound.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaReacharound.java new file mode 100644 index 0000000..ced2135 --- /dev/null +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaReacharound.java @@ -0,0 +1,164 @@ +/* + * Copyright © 2020 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.client; + +import me.lambdaurora.lambdacontrols.LambdaControlsFeature; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidBlock; +import net.minecraft.block.SlabBlock; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RayTraceContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents the reacharound API of LambdaControls. + * + * @version 1.3.2 + * @since 1.3.2 + */ +public class LambdaReacharound +{ + private BlockHitResult lastReacharoundResult = null; + private boolean lastReacharoundVertical = false; + + public void tick(@NotNull MinecraftClient client) + { + this.lastReacharoundResult = this.tryVerticalReachAround(client); + if (this.lastReacharoundResult == null) { + this.lastReacharoundResult = this.tryFrontPlace(client); + this.lastReacharoundVertical = false; + } else this.lastReacharoundVertical = true; + } + + /** + * Returns the last reach around result. + * + * @return The last reach around result. + */ + public @Nullable BlockHitResult getLastReacharoundResult() + { + return this.lastReacharoundResult; + } + + /** + * Returns whether the last reach around is vertical. + * + * @return True if the reach around is vertical. + */ + public boolean isLastReacharoundVertical() + { + return this.lastReacharoundVertical; + } + + /** + * Returns whether reacharound is available or not. + * + * @return True if reacharound is available, else false. + */ + public boolean isReacharoundAvailable() + { + return LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable() || LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable(); + } + + private float getPlayerRange(@NotNull MinecraftClient client) + { + return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f; + } + + /** + * Returns a nullable block hit result if vertical reacharound is possible. + * + * @param client The client instance. + * @return A block hit result if vertical reacharound is possible, else null. + */ + public @Nullable BlockHitResult tryVerticalReachAround(@NotNull MinecraftClient client) + { + if (!LambdaControlsFeature.VERTICAL_REACHAROUND.isAvailable()) + return null; + if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.MISS + || !client.player.isOnGround() || client.player.pitch < 80.0F + || client.player.isRiding()) + return null; + + Vec3d pos = client.player.getCameraPosVec(1.0F); + Vec3d rotationVec = client.player.getRotationVec(1.0F); + float range = getPlayerRange(client); + Vec3d rayVec = pos.add(rotationVec.x * range, rotationVec.y * range, rotationVec.z * range).add(0, 0.75, 0); + BlockHitResult result = client.world.rayTrace(new RayTraceContext(pos, rayVec, RayTraceContext.ShapeType.OUTLINE, RayTraceContext.FluidHandling.NONE, client.player)); + + if (result.getType() == HitResult.Type.BLOCK) { + BlockPos blockPos = result.getBlockPos().down(); + BlockState state = client.world.getBlockState(blockPos); + + if (client.player.getBlockPos().getY() - blockPos.getY() > 1 && (client.world.isAir(blockPos) || state.getMaterial().isReplaceable())) { + return new BlockHitResult(result.getPos(), Direction.DOWN, blockPos, false); + } + } + + return null; + } + + /** + * Returns a nullable block hit result if front placing is possible. + * + * @param client The client instance. + * @return A block hit result if front placing is possible. + */ + public @Nullable BlockHitResult tryFrontPlace(@NotNull MinecraftClient client) + { + if (!LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable()) + return null; + if (client.player != null && client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.MISS && client.player.isOnGround() && client.player.pitch > 35.0F) { + if (client.player.isRiding()) + return null; + BlockPos playerPos = client.player.getBlockPos().down(); + BlockPos targetPos = new BlockPos(client.crosshairTarget.getPos()).subtract(playerPos); + BlockPos vector = new BlockPos(MathHelper.clamp(targetPos.getX(), -1, 1), 0, MathHelper.clamp(targetPos.getZ(), -1, 1)); + BlockPos blockPos = playerPos.add(vector); + + Direction direction = client.player.getHorizontalFacing(); + + BlockState state = client.world.getBlockState(blockPos); + if (!state.isAir()) + return null; + BlockState adjacentBlockState = client.world.getBlockState(blockPos.offset(direction.getOpposite())); + if (adjacentBlockState.isAir() || adjacentBlockState.getBlock() instanceof FluidBlock || (vector.getX() == 0 && vector.getZ() == 0)) { + return null; + } + + return new BlockHitResult(client.crosshairTarget.getPos(), direction, blockPos, false); + } + return null; + } + + public static @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @Nullable ItemStack stack) + { + if (stack == null || stack.isEmpty() || !(stack.getItem() instanceof BlockItem)) + return result; + return withSideForReacharound(result, Block.getBlockFromItem(stack.getItem())); + } + + public static @NotNull BlockHitResult withSideForReacharound(@NotNull BlockHitResult result, @NotNull Block block) + { + if (block instanceof SlabBlock) + result = result.withSide(Direction.DOWN); + return result; + } +} diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/CompatHandler.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/CompatHandler.java index 8e70f45..7ce00ab 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/CompatHandler.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/CompatHandler.java @@ -10,14 +10,20 @@ package me.lambdaurora.lambdacontrols.client.compat; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.screen.slot.Slot; +import net.minecraft.util.hit.BlockHitResult; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Represents a compatibility handler for a mod. * * @author LambdAurora - * @version 1.2.0 + * @version 1.3.2 * @since 1.1.0 */ public interface CompatHandler @@ -33,10 +39,58 @@ public interface CompatHandler * Returns whether the mouse is required on the specified screen. * * @param screen The screen. - * @return True if the mouse is requried on the specified screen, else false. + * @return True if the mouse is required on the specified screen, else false. */ default boolean requireMouseOnScreen(Screen screen) { return false; } + + /** + * Returns whether the current slot is a creative slot or not. + * + * @param screen The screen. + * @param slot The slot to check. + * @return True if the slot is a creative slot, else false. + */ + default boolean isCreativeSlot(@NotNull HandledScreen screen, @NotNull Slot slot) + { + return false; + } + + /** + * Returns a custom translation key to make custom attack action strings on the HUD. + * + * @param client The client instance. + * @param placeResult The last place block result. + * @return Null if untouched, else a translation key. + */ + default String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) + { + return null; + } + + /** + * Returns a custom translation key to make custom use action strings on the HUD. + * + * @param client The client instance. + * @param placeResult The last place block result. + * @return Null if untouched, else a translation key. + */ + default String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) + { + return null; + } + + /** + * Handles the menu back button. + * + * @param client The client instance. + * @param screen The screen. + * @return True if the handle was fired and succeed, else false. + */ + default boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) + { + return false; + } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/HQMCompat.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/HQMCompat.java new file mode 100644 index 0000000..812af19 --- /dev/null +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/HQMCompat.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2020 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.client.compat; + +import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import net.minecraft.client.gui.screen.Screen; +import org.aperlambda.lambdacommon.utils.LambdaReflection; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * Represents HQM compatibility handler. + * + * This is bad. + * + * @author LambdAurora + * @version 1.3.2 + * @since 1.3.2 + */ +public class HQMCompat implements CompatHandler +{ + public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase"; + private Optional> guiBaseClass; + + @Override + public void handle(@NotNull LambdaControlsClient mod) + { + this.guiBaseClass = LambdaReflection.getClass(GUI_BASE_CLASS_PATH); + } + + @Override + public boolean requireMouseOnScreen(Screen screen) + { + return this.guiBaseClass.map(clazz -> clazz.isInstance(screen)).orElse(false); + } +} diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/LambdaControlsCompat.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/LambdaControlsCompat.java index 88733f6..9bf07c7 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/LambdaControlsCompat.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/LambdaControlsCompat.java @@ -12,18 +12,23 @@ import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.controller.InputManager; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.util.hit.BlockHitResult; import org.aperlambda.lambdacommon.utils.LambdaReflection; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; /** * Represents a compatibility handler. * * @author LambdAurora - * @version 1.1.0 + * @version 1.3.2 * @since 1.1.0 */ public class LambdaControlsCompat @@ -45,10 +50,34 @@ public static void init(@NotNull LambdaControlsClient mod) mod.log("Adding REI compatiblity..."); HANDLERS.add(new ReiCompat()); } + if (FabricLoader.getInstance().isModLoaded("hardcorequesting") && LambdaReflection.doesClassExist(HQMCompat.GUI_BASE_CLASS_PATH)) { + mod.log("Adding HQM compatibility..."); + HANDLERS.add(new HQMCompat()); + } HANDLERS.forEach(handler -> handler.handle(mod)); InputManager.loadButtonBindings(mod.config); } + /** + * Registers a new compatibility handler. + * + * @param handler The compatibility handler to register. + */ + public static void registerCompatHandler(@NotNull CompatHandler handler) + { + HANDLERS.add(handler); + } + + /** + * Streams through compatibility handlers. + * + * @return A stream of compatibility handlers. + */ + public static Stream streamCompatHandlers() + { + return HANDLERS.stream(); + } + /** * Returns whether the mouse is required on the specified screen. * @@ -60,6 +89,57 @@ public static boolean requireMouseOnScreen(Screen screen) return HANDLERS.stream().anyMatch(handler -> handler.requireMouseOnScreen(screen)); } + /** + * Returns a custom translation key to make custom attack action strings on the HUD. + * + * @param client The client instance. + * @param placeResult The last place block result. + * @return Null if untouched, else a translation key. + */ + public static String getAttackActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) + { + for (CompatHandler handler : HANDLERS) { + String action = handler.getAttackActionAt(client, placeResult); + if (action != null) { + return action; + } + } + return null; + } + + /** + * Returns a custom translation key to make custom use action strings on the HUD. + * + * @param client The client instance. + * @param placeResult The last place block result. + * @return Null if untouched, else a translation key. + */ + public static String getUseActionAt(@NotNull MinecraftClient client, @Nullable BlockHitResult placeResult) + { + for (CompatHandler handler : HANDLERS) { + String action = handler.getUseActionAt(client, placeResult); + if (action != null) { + return action; + } + } + return null; + } + + /** + * Handles the menu back button. + * + * @param client The client instance. + * @param screen The screen. + * @return True if the handle was fired and succeed, else false. + */ + public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) { + for (CompatHandler handler : HANDLERS) { + if (handler.handleMenuBack(client, screen)) + return true; + } + return false; + } + /** * Returns whether Roughly Enough Items is present. * diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/ReiCompat.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/ReiCompat.java index 745337d..d73554c 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/ReiCompat.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/ReiCompat.java @@ -17,12 +17,14 @@ import me.lambdaurora.lambdacontrols.client.controller.InputHandlers; import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.lambdacontrols.client.controller.PressAction; +import me.shedaniel.rei.api.REIHelper; import me.shedaniel.rei.api.RecipeCategory; import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.RecipeViewingScreen; import me.shedaniel.rei.gui.VillagerRecipeViewingScreen; import me.shedaniel.rei.gui.widget.EntryListWidget; import me.shedaniel.rei.impl.ScreenHelper; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.util.Identifier; import org.aperlambda.lambdacommon.utils.LambdaReflection; @@ -37,13 +39,12 @@ * Represents a compatibility handler for REI. * * @author LambdAurora - * @version 1.3.0 + * @version 1.3.2 * @since 1.2.0 */ public class ReiCompat implements CompatHandler { private static EntryListWidget ENTRY_LIST_WIDGET; - public static ButtonBinding TAB_BACK; @Override public void handle(@NotNull LambdaControlsClient mod) @@ -106,6 +107,17 @@ private static boolean isViewingScreen(Screen screen) return screen instanceof RecipeViewingScreen || screen instanceof VillagerRecipeViewingScreen; } + @Override + public boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) + { + if (!isViewingScreen(screen)) + return false; + + MinecraftClient.getInstance().openScreen(REIHelper.getInstance().getPreviousContainerScreen()); + ScreenHelper.getLastOverlay().init(); + return true; + } + private static EntryListWidget getEntryListWidget() { if (ENTRY_LIST_WIDGET == null) { diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsHud.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsHud.java index 1a66ab4..9caac07 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsHud.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsHud.java @@ -13,11 +13,12 @@ import me.lambdaurora.lambdacontrols.LambdaControlsConstants; import me.lambdaurora.lambdacontrols.client.HudSide; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; -import me.lambdaurora.lambdacontrols.client.LambdaInput; +import me.lambdaurora.lambdacontrols.client.compat.LambdaControlsCompat; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.spruceui.hud.Hud; import net.minecraft.client.MinecraftClient; import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.util.Window; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -31,26 +32,27 @@ * Represents the LambdaControls HUD. * * @author LambdAurora - * @version 1.3.0 + * @version 1.3.2 * @since 1.0.0 */ public class LambdaControlsHud extends Hud { private final LambdaControlsClient mod; private MinecraftClient client; - private int attackWidth = 0; - private int attackButtonWidth = 0; - private int dropItemWidth = 0; - private int dropItemButtonWidth = 0; - private int inventoryWidth = 0; - private int inventoryButtonWidth = 0; - private int swapHandsWidth = 0; - private int swapHandsButtonWidth = 0; - private int useWidth = 0; - private int useButtonWidth = 0; + private int attackWidth = 0; + private int attackButtonWidth = 0; + private int dropItemWidth = 0; + private int dropItemButtonWidth = 0; + private int inventoryWidth = 0; + private int inventoryButtonWidth = 0; + private int swapHandsWidth = 0; + private int swapHandsButtonWidth = 0; + private int useWidth = 0; + private int useButtonWidth = 0; private BlockHitResult placeHitResult; - private String attackAction = ""; - private String placeAction = ""; + private String attackAction = ""; + private String placeAction = ""; + private int ticksDisplayedCrosshair = 0; public LambdaControlsHud(@NotNull LambdaControlsClient mod) { @@ -86,6 +88,19 @@ public void render(MatrixStack matrices, float tickDelta) this.renderFirstSection(matrices, this.mod.config.getHudSide() == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y); this.renderSecondSection(matrices, this.mod.config.getHudSide() == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y); } + + if (this.mod.reacharound.isLastReacharoundVertical()) { + // Render crosshair indicator. + Window window = this.client.getWindow(); + String text = "[ ]"; + + float scale = Math.min(5, this.ticksDisplayedCrosshair + tickDelta) / 5F; + scale *= scale; + int opacity = ((int) (255 * scale)) << 24; + + this.client.textRenderer.draw(matrices, text, window.getScaledWidth() / 2.f - this.client.textRenderer.getWidth(text) / 2.f, + window.getScaledHeight() / 2.f - 4, 0xCCCCCC | opacity); + } } public void renderFirstIcons(MatrixStack matrices, int x, int y) @@ -177,7 +192,7 @@ public void tick() // Update "Use" tip status. if (this.client.crosshairTarget.getType() == HitResult.Type.MISS) { - this.placeHitResult = LambdaInput.tryFrontPlace(this.client); + this.placeHitResult = this.mod.reacharound.getLastReacharoundResult(); this.attackAction = ""; this.attackWidth = 0; } else { @@ -190,8 +205,26 @@ public void tick() this.attackWidth = this.width(attackAction); } - ItemStack stack = this.client.player.getMainHandStack(); - if ((stack == null || stack.isEmpty()) && ((stack = this.client.player.getOffHandStack()) == null || stack.isEmpty())) { + if (this.mod.reacharound.isLastReacharoundVertical()) { + if (this.ticksDisplayedCrosshair < 5) + this.ticksDisplayedCrosshair++; + } else { + this.ticksDisplayedCrosshair = 0; + } + + String customAttackAction = LambdaControlsCompat.getAttackActionAt(this.client, this.placeHitResult); + if (customAttackAction != null) { + this.attackAction = customAttackAction; + this.attackWidth = this.width(customAttackAction); + } + + ItemStack stack = null; + if (this.client.player != null) { + stack = this.client.player.getMainHandStack(); + if (stack == null || stack.isEmpty()) + stack = this.client.player.getOffHandStack(); + } + if (stack == null || stack.isEmpty()) { placeAction = ""; } else { if (this.placeHitResult != null && stack.getItem() instanceof BlockItem) { @@ -201,6 +234,10 @@ public void tick() } } + String customUseAction = LambdaControlsCompat.getUseActionAt(this.client, this.placeHitResult); + if (customUseAction != null) + placeAction = customUseAction; + this.placeAction = placeAction; // Cache the "Use" tip width. diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java index 6f73e54..8c3c05a 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java @@ -11,6 +11,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import me.lambdaurora.lambdacontrols.client.LambdaInput; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.util.HandledScreenAccessor; import net.minecraft.client.MinecraftClient; @@ -28,7 +29,7 @@ * Represents the LambdaControls renderer. * * @author LambdAurora - * @version 1.3.1 + * @version 1.3.2 * @since 1.2.0 */ public class LambdaControlsRenderer @@ -228,7 +229,7 @@ private static int getButtonTipWidth(@NotNull String action, @NotNull TextRender public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client) { - if (!LambdaControlsClient.get().config.hasVirtualMouse() || client.currentScreen == null) + if (!LambdaControlsClient.get().config.hasVirtualMouse() || (client.currentScreen == null || LambdaInput.isScreenInteractive(client.currentScreen))) return; int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java index 8b19204..c600f24 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java @@ -51,6 +51,7 @@ public class LambdaControlsSettingsScreen extends Screen private final Option autoJumpOption; private final Option fastBlockPlacingOption; private final Option frontBlockPlacingOption; + private final Option verticalReacharoundOption; private final Option flyDriftingOption; private final Option flyVerticalDriftingOption; // Controller options @@ -104,8 +105,10 @@ public LambdaControlsSettingsScreen(Screen parent, boolean hideControls) this.autoJumpOption = SpruceBooleanOption.fromVanilla("options.autoJump", Option.AUTO_JUMP, null, true); this.fastBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.fast_block_placing", this.mod.config::hasFastBlockPlacing, this.mod.config::setFastBlockPlacing, new TranslatableText("lambdacontrols.tooltip.fast_block_placing"), true); - this.frontBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.front_block_placing", this.mod.config::hasFrontBlockPlacing, - this.mod.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.front_block_placing"), true); + this.frontBlockPlacingOption = new SpruceBooleanOption("lambdacontrols.menu.reacharound.horizontal", this.mod.config::hasFrontBlockPlacing, + this.mod.config::setFrontBlockPlacing, new TranslatableText("lambdacontrols.tooltip.reacharound.horizontal"), true); + this.verticalReacharoundOption = new SpruceBooleanOption("lambdacontrols.menu.reacharound.vertical", this.mod.config::hasVerticalReacharound, + this.mod.config::setVerticalReacharound, new TranslatableText("lambdacontrols.tooltip.reacharound.vertical"), true); this.flyDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting", this.mod.config::hasFlyDrifting, this.mod.config::setFlyDrifting, new TranslatableText("lambdacontrols.tooltip.fly_drifting"), true); this.flyVerticalDriftingOption = new SpruceBooleanOption("lambdacontrols.menu.fly_drifting_vertical", this.mod.config::hasFlyVerticalDrifting, @@ -239,8 +242,8 @@ protected void init() this.list.addSingleOptionEntry(this.autoSwitchModeOption); // Gameplay options this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.gameplay", true, null)); - this.list.addSingleOptionEntry(this.autoJumpOption); - this.list.addOptionEntry(this.fastBlockPlacingOption, this.frontBlockPlacingOption); + this.list.addOptionEntry(this.autoJumpOption, this.fastBlockPlacingOption); + this.list.addOptionEntry(this.frontBlockPlacingOption, this.verticalReacharoundOption); this.list.addSingleOptionEntry(this.flyDriftingOption); this.list.addSingleOptionEntry(this.flyVerticalDriftingOption); // Controller options diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java index 9a733a1..8fb044c 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java @@ -11,9 +11,8 @@ import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; -import me.lambdaurora.lambdacontrols.client.LambdaInput; +import me.lambdaurora.lambdacontrols.client.LambdaReacharound; import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; -import me.lambdaurora.lambdacontrols.client.util.FrontBlockPlaceResultAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.ClientPlayerEntity; @@ -40,7 +39,7 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(MinecraftClient.class) -public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAccessor +public abstract class MinecraftClientMixin { @Shadow @Nullable @@ -65,18 +64,10 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces @Shadow private int itemUseCooldown; - private BlockHitResult lambdacontrols_frontBlockPlaceResult = null; - private BlockPos lambdacontrols_lastTargetPos; private Vec3d lambdacontrols_lastPos; private Direction lambdacontrols_lastTargetSide; - @Override - public @Nullable BlockHitResult lambdacontrols_getFrontBlockPlaceResult() - { - return this.lambdacontrols_frontBlockPlaceResult; - } - @Inject(method = "", at = @At("RETURN")) private void onInit(CallbackInfo ci) { @@ -88,7 +79,7 @@ private void onStartTick(CallbackInfo ci) { if (this.player == null) return; - this.lambdacontrols_frontBlockPlaceResult = LambdaInput.tryFrontPlace(((MinecraftClient) (Object) this)); + if (!LambdaControlsFeature.FAST_BLOCK_PLACING.isAvailable()) return; if (this.lambdacontrols_lastPos == null) @@ -131,7 +122,8 @@ private void onRender(boolean fullRender, CallbackInfo ci) } @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V", shift = At.Shift.AFTER)) - private void renderVirtualCursor(boolean fullRender, CallbackInfo ci) { + private void renderVirtualCursor(boolean fullRender, CallbackInfo ci) + { LambdaControlsRenderer.renderVirtualCursor(new MatrixStack(), (MinecraftClient) (Object) this); } @@ -144,15 +136,15 @@ private void onLeave(@Nullable Screen screen, CallbackInfo ci) @Inject(method = "doItemUse()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true) private void onItemUse(CallbackInfo ci, Hand[] hands, int handCount, int handIndex, Hand hand, ItemStack stackInHand) { - if (!stackInHand.isEmpty() && this.player.pitch > 35.0F && LambdaControlsFeature.FRONT_BLOCK_PLACING.isAvailable()) { + if (!stackInHand.isEmpty() && this.player.pitch > 35.0F && LambdaControlsClient.get().reacharound.isReacharoundAvailable()) { if (this.crosshairTarget != null && this.crosshairTarget.getType() == HitResult.Type.MISS && this.player.isOnGround()) { if (!stackInHand.isEmpty() && stackInHand.getItem() instanceof BlockItem) { - BlockHitResult hitResult = LambdaInput.tryFrontPlace(((MinecraftClient) (Object) this)); + BlockHitResult hitResult = LambdaControlsClient.get().reacharound.getLastReacharoundResult(); if (hitResult == null) return; - hitResult = LambdaInput.withSideForFrontPlace(hitResult, stackInHand); + hitResult = LambdaReacharound.withSideForReacharound(hitResult, stackInHand); int previousStackCount = stackInHand.getCount(); ActionResult result = this.interactionManager.interactBlock(this.player, this.world, hand, hitResult); diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/WorldRendererMixin.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/WorldRendererMixin.java index afa1b61..b38b9ae 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/WorldRendererMixin.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/WorldRendererMixin.java @@ -10,8 +10,7 @@ package me.lambdaurora.lambdacontrols.client.mixin; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; -import me.lambdaurora.lambdacontrols.client.LambdaInput; -import me.lambdaurora.lambdacontrols.client.util.FrontBlockPlaceResultAccessor; +import me.lambdaurora.lambdacontrols.client.LambdaReacharound; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; @@ -74,9 +73,9 @@ private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTi Profiler profiler, Vec3d cameraPos, double x, double y, double z, Matrix4f modelMatrix, boolean bl, Frustum frustum2, boolean bl3, VertexConsumerProvider.Immediate immediate) { - if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !LambdaControlsClient.get().config.shouldRenderFrontBlockOutline()) + if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !LambdaControlsClient.get().config.shouldRenderReacharoundOutline()) return; - BlockHitResult result = ((FrontBlockPlaceResultAccessor) client).lambdacontrols_getFrontBlockPlaceResult(); + BlockHitResult result = LambdaControlsClient.get().reacharound.getLastReacharoundResult(); if (result == null) return; BlockPos blockPos = result.getBlockPos(); @@ -85,14 +84,14 @@ private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTi if (stack == null || !(stack.getItem() instanceof BlockItem)) return; Block block = ((BlockItem) stack.getItem()).getBlock(); - result = LambdaInput.withSideForFrontPlace(result, block); + result = LambdaReacharound.withSideForReacharound(result, block); ItemPlacementContext context = new ItemPlacementContext(new ItemUsageContext(this.client.player, Hand.MAIN_HAND, result)); VertexConsumer vertexConsumer = immediate.getBuffer(RenderLayer.getLines()); BlockState placementState = block.getPlacementState(context); if (placementState == null) return; VoxelShape outlineShape = placementState.getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity())); - int[] color = LambdaControlsClient.get().config.getFrontBlockOutlineColor(); + int[] color = LambdaControlsClient.get().config.getReacharoundOutlineColor(); drawShapeOutline(matrices, vertexConsumer, outlineShape, (double) blockPos.getX() - x, (double) blockPos.getY() - y, (double) blockPos.getZ() - z, color[0] / 255.f, color[1] / 255.f, color[2] / 255.f, color[3] / 255.f); } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/util/FrontBlockPlaceResultAccessor.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/util/FrontBlockPlaceResultAccessor.java deleted file mode 100644 index 67bca9d..0000000 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/util/FrontBlockPlaceResultAccessor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2020 LambdAurora - * - * This file is part of LambdaControls. - * - * Licensed under the MIT license. For more information, - * see the LICENSE file. - */ - -package me.lambdaurora.lambdacontrols.client.util; - -import net.minecraft.util.hit.BlockHitResult; -import org.jetbrains.annotations.Nullable; - -/** - * Represents an accessor of the BlockHitResult for the front block placing feature. - *

- * It is implemented by {@link net.minecraft.client.MinecraftClient}. - * - * @author LambdAurora - * @version 1.2.0 - * @since 1.2.0 - */ -public interface FrontBlockPlaceResultAccessor -{ - /** - * Returns the {@link BlockHitResult} if a block can be placed with the front block placing feature. - * - * @return If possible a {@link BlockHitResult}, else a null value. - */ - @Nullable BlockHitResult lambdacontrols_getFrontBlockPlaceResult(); -} diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json b/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json index 6128704..e99b5d0 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json @@ -82,13 +82,14 @@ "lambdacontrols.menu.fast_block_placing": "Fast Block Placing", "lambdacontrols.menu.fly_drifting": "Fly Drifting", "lambdacontrols.menu.fly_drifting_vertical": "Vertical Fly Drifting", - "lambdacontrols.menu.front_block_placing": "Front Block Placing", "lambdacontrols.menu.hud_enable": "Enable HUD", "lambdacontrols.menu.hud_side": "HUD Side", "lambdacontrols.menu.invert_right_x_axis": "Invert Right X", "lambdacontrols.menu.invert_right_y_axis": "Invert Right Y", "lambdacontrols.menu.keyboard_controls": "Keyboard Controls...", "lambdacontrols.menu.mouse_speed": "Mouse Speed", + "lambdacontrols.menu.reacharound.horizontal": "Front Block Placing", + "lambdacontrols.menu.reacharound.vertical": "Vertical Reacharound", "lambdacontrols.menu.reload_controller_mappings": "Reload Controller Mappings", "lambdacontrols.menu.rotation_speed": "Rotation Speed", "lambdacontrols.menu.title": "LambdaControls - Settings", @@ -111,12 +112,13 @@ "lambdacontrols.tooltip.fast_block_placing": "While flying in creative mode, enables fast block placing depending on your speed. §cOn some servers this might be considered as cheating.", "lambdacontrols.tooltip.fly_drifting": "While flying, enables Vanilla drifting/inertia.", "lambdacontrols.tooltip.fly_drifting_vertical": "While flying, enables Vanilla vertical drifting/intertia.", - "lambdacontrols.tooltip.front_block_placing": "Enables front block placing, §cmight be considered cheating on some servers§r.", "lambdacontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.", "lambdacontrols.tooltip.hud_side": "The position of the HUD.", "lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.", - "lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.", + "lambdacontrols.tooltip.reacharound.horizontal": "Enables front block placing, §cmight be considered cheating on some servers§r.", + "lambdacontrols.tooltip.reacharound.vertical": "Enables vertical reacharound, §cmight be considered cheating on some servers§r.", "lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.", + "lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.", "lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.", "lambdacontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.", "lambdacontrols.virtual_mouse.skin.default_light": "Default Light", diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json index 187adb6..d2fcf0a 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json @@ -81,13 +81,14 @@ "lambdacontrols.menu.dead_zone": "Zone morte", "lambdacontrols.menu.fly_drifting": "Inertie de vol", "lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol", - "lambdacontrols.menu.front_block_placing": "Placement avant de bloc", "lambdacontrols.menu.hud_enable": "Activer le HUD", "lambdacontrols.menu.hud_side": "Côté du HUD", "lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)", "lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)", "lambdacontrols.menu.keyboard_controls": "Contrôles clavier...", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris", + "lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc", + "lambdacontrols.menu.reacharound.vertical": "Placement vertical", "lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", "lambdacontrols.menu.rotation_speed": "Vitesse de rotation", "lambdacontrols.menu.title": "LambdaControls - Paramètres", @@ -107,14 +108,16 @@ "lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.", "lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.", "lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.", + "lambdacontrols.tooltip.fast_block_placing": "Active le placement rapide de blocs en vol.", "lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.", "lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.", - "lambdacontrols.tooltip.front_block_placing": "Active le placement avant de blocs, §cpeut être considérer comme de la trice sur certains serveurs§r.", "lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.", "lambdacontrols.tooltip.hud_side": "Change la position du HUD.", "lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.", - "lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.", + "lambdacontrols.tooltip.reacharound.horizontal": "Active le placement avant de blocs, §cpeut être considérer comme de la triche sur certains serveurs§r.", + "lambdacontrols.tooltip.reacharound.vertical": "Active le placement vertical de blocs, c'est-à-dire de blocs en dessous du bloc sur lequel vous êtes placé, §cpeut être considérer comme de la triche sur certains serveurs§r.", "lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.", + "lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.", "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.", "lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.", "lambdacontrols.virtual_mouse.skin.default_light": "défaut clair", diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json index 187adb6..d2fcf0a 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json @@ -81,13 +81,14 @@ "lambdacontrols.menu.dead_zone": "Zone morte", "lambdacontrols.menu.fly_drifting": "Inertie de vol", "lambdacontrols.menu.fly_drifting_vertical": "Inertie verticale de vol", - "lambdacontrols.menu.front_block_placing": "Placement avant de bloc", "lambdacontrols.menu.hud_enable": "Activer le HUD", "lambdacontrols.menu.hud_side": "Côté du HUD", "lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)", "lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)", "lambdacontrols.menu.keyboard_controls": "Contrôles clavier...", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris", + "lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc", + "lambdacontrols.menu.reacharound.vertical": "Placement vertical", "lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", "lambdacontrols.menu.rotation_speed": "Vitesse de rotation", "lambdacontrols.menu.title": "LambdaControls - Paramètres", @@ -107,14 +108,16 @@ "lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.", "lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.", "lambdacontrols.tooltip.dead_zone": "Zone morte des axes de la manette.", + "lambdacontrols.tooltip.fast_block_placing": "Active le placement rapide de blocs en vol.", "lambdacontrols.tooltip.fly_drifting": "Pendant que le joueur vole, active le glissement Vanilla.", "lambdacontrols.tooltip.fly_drifting_vertical": "Pendant que le joueur vole, active le glissement vertical Vanilla.", - "lambdacontrols.tooltip.front_block_placing": "Active le placement avant de blocs, §cpeut être considérer comme de la trice sur certains serveurs§r.", "lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.", "lambdacontrols.tooltip.hud_side": "Change la position du HUD.", "lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.", - "lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.", + "lambdacontrols.tooltip.reacharound.horizontal": "Active le placement avant de blocs, §cpeut être considérer comme de la triche sur certains serveurs§r.", + "lambdacontrols.tooltip.reacharound.vertical": "Active le placement vertical de blocs, c'est-à-dire de blocs en dessous du bloc sur lequel vous êtes placé, §cpeut être considérer comme de la triche sur certains serveurs§r.", "lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes.", + "lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.", "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.", "lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.", "lambdacontrols.virtual_mouse.skin.default_light": "défaut clair", diff --git a/fabric/src/main/resources/config.toml b/fabric/src/main/resources/config.toml index e9c5408..de46941 100644 --- a/fabric/src/main/resources/config.toml +++ b/fabric/src/main/resources/config.toml @@ -21,9 +21,11 @@ auto_switch_mode = false drifting = false # Enables vertical fly drifting. vertical_drifting = true - [gameplay.front_block_placing] + [gameplay.reacharound] # Enables front block placing like in Bedrock Edition. - enabled = false + horizontal = false + # Enables vertical reacharound. + vertical = false # Enables front block placing outline. outline = true # The color in a hexadecimal format of the outline. diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 884dda5..22c6945 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -37,12 +37,12 @@ "spruceui": ">=1.5.2" }, "recommends": { - "modmenu": ">=1.12.2", - "okzoomer": ">=4.0.0" + "modmenu": ">=1.12.2" }, "suggests": { "flamingo": "*", - "roughlyenoughitems": ">=4.5.5" + "roughlyenoughitems": ">=4.5.5", + "okzoomer": ">=4.0.0" }, "breaks": { "modmenu": "<1.12.2", diff --git a/gradle.properties b/gradle.properties index e7a37ae..4f6eee2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G loader_version=0.8.8+build.202 # Mod Properties - mod_version = 1.3.1 + mod_version = 1.3.2 maven_group = me.lambdaurora.lambdacontrols archives_base_name = lambdacontrols