forked from Clones/Controlify
➕ D-Pad snapping + better drop key in containers (closes #124) - thanks @arnokeesman for PR and reference
This commit is contained in:
@ -49,7 +49,7 @@ public class ControllerBindings<T extends ControllerState> {
|
||||
JUMP, SNEAK,
|
||||
ATTACK, USE,
|
||||
SPRINT,
|
||||
DROP, DROP_STACK,
|
||||
DROP_INGAME, DROP_STACK, DROP_INVENTORY,
|
||||
NEXT_SLOT, PREV_SLOT,
|
||||
PAUSE,
|
||||
INVENTORY,
|
||||
@ -67,6 +67,7 @@ public class ControllerBindings<T extends ControllerState> {
|
||||
RADIAL_MENU, RADIAL_AXIS_UP, RADIAL_AXIS_DOWN, RADIAL_AXIS_LEFT, RADIAL_AXIS_RIGHT,
|
||||
VMOUSE_MOVE_UP, VMOUSE_MOVE_DOWN, VMOUSE_MOVE_LEFT, VMOUSE_MOVE_RIGHT,
|
||||
VMOUSE_LCLICK, VMOUSE_RCLICK, VMOUSE_SHIFT_CLICK,
|
||||
VMOUSE_SNAP_UP, VMOUSE_SNAP_DOWN, VMOUSE_SNAP_LEFT, VMOUSE_SNAP_RIGHT,
|
||||
VMOUSE_SCROLL_UP, VMOUSE_SCROLL_DOWN,
|
||||
VMOUSE_SHIFT,
|
||||
VMOUSE_TOGGLE,
|
||||
@ -173,7 +174,7 @@ public class ControllerBindings<T extends ControllerState> {
|
||||
.context(BindContexts.INGAME)
|
||||
.vanillaOverride(options.keyUse, () -> false)
|
||||
.build());
|
||||
register(DROP = ControllerBindingBuilder.create(controller)
|
||||
register(DROP_INGAME = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "drop")
|
||||
.defaultBind(GamepadBinds.DPAD_DOWN)
|
||||
.category(GAMEPLAY_CATEGORY)
|
||||
@ -187,6 +188,12 @@ public class ControllerBindings<T extends ControllerState> {
|
||||
.context(BindContexts.INGAME)
|
||||
.radialCandidate(RadialIcons.getItem(Items.TNT))
|
||||
.build());
|
||||
register(DROP_INVENTORY = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "drop_inventory")
|
||||
.defaultBind(GamepadBinds.Y_BUTTON)
|
||||
.category(INVENTORY_CATEGORY)
|
||||
.context(BindContexts.INVENTORY)
|
||||
.build());
|
||||
register(NEXT_SLOT = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "next_slot")
|
||||
.defaultBind(GamepadBinds.RIGHT_BUMPER)
|
||||
@ -396,6 +403,30 @@ public class ControllerBindings<T extends ControllerState> {
|
||||
.category(VMOUSE_CATEGORY)
|
||||
.context(BindContexts.GUI_VMOUSE)
|
||||
.build());
|
||||
register(VMOUSE_SNAP_UP = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "vmouse_snap_up")
|
||||
.defaultBind(GamepadBinds.DPAD_UP)
|
||||
.category(VMOUSE_CATEGORY)
|
||||
.context(BindContexts.GUI_VMOUSE)
|
||||
.build());
|
||||
register(VMOUSE_SNAP_DOWN = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "vmouse_snap_down")
|
||||
.defaultBind(GamepadBinds.DPAD_DOWN)
|
||||
.category(VMOUSE_CATEGORY)
|
||||
.context(BindContexts.GUI_VMOUSE)
|
||||
.build());
|
||||
register(VMOUSE_SNAP_LEFT = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "vmouse_snap_left")
|
||||
.defaultBind(GamepadBinds.DPAD_LEFT)
|
||||
.category(VMOUSE_CATEGORY)
|
||||
.context(BindContexts.GUI_VMOUSE)
|
||||
.build());
|
||||
register(VMOUSE_SNAP_RIGHT = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "vmouse_snap_right")
|
||||
.defaultBind(GamepadBinds.DPAD_RIGHT)
|
||||
.category(VMOUSE_CATEGORY)
|
||||
.context(BindContexts.GUI_VMOUSE)
|
||||
.build());
|
||||
register(VMOUSE_SCROLL_UP = ControllerBindingBuilder.create(controller)
|
||||
.identifier("controlify", "vmouse_scroll_up")
|
||||
.defaultBind(GamepadBinds.RIGHT_STICK_FORWARD)
|
||||
|
@ -72,7 +72,7 @@ public class InGameInputHandler {
|
||||
if (minecraft.player.drop(true)) {
|
||||
minecraft.player.swing(InteractionHand.MAIN_HAND);
|
||||
}
|
||||
} else if (dropRepeatHelper.shouldAction(controller.bindings().DROP)) {
|
||||
} else if (dropRepeatHelper.shouldAction(controller.bindings().DROP_INGAME)) {
|
||||
if (minecraft.player.drop(false)) {
|
||||
dropRepeatHelper.onNavigate();
|
||||
minecraft.player.swing(InteractionHand.MAIN_HAND);
|
||||
|
@ -45,11 +45,12 @@ public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<
|
||||
ContainerGuideCtx ctx = new ContainerGuideCtx(hoveredSlot.get(), screen.getMenu().getCarried(), accessor.invokeHasClickedOutside(vmouse.getCurrentX(1f), vmouse.getCurrentY(1f), accessor.getLeftPos(), accessor.getTopPos(), 0));
|
||||
|
||||
Slot hoveredSlot = this.hoveredSlot.get();
|
||||
if (hoveredSlot != null) {
|
||||
if (controller.bindings().DROP.justPressed() && hoveredSlot.hasItem()) {
|
||||
clickSlotFunction.clickSlot(hoveredSlot, hoveredSlot.index, 0, ClickType.THROW);
|
||||
if (!screen.getMenu().getCarried().isEmpty()) {
|
||||
if (controller.bindings().DROP_INVENTORY.justPressed()) {
|
||||
clickSlotFunction.clickSlot(null, -999, 0, ClickType.PICKUP);
|
||||
}
|
||||
|
||||
}
|
||||
if (hoveredSlot != null) {
|
||||
if (controller.bindings().INV_SELECT.justPressed()) {
|
||||
clickSlotFunction.clickSlot(hoveredSlot, hoveredSlot.index, 0, ClickType.PICKUP);
|
||||
}
|
||||
@ -147,8 +148,8 @@ public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<
|
||||
.rowPadding(0)
|
||||
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
||||
.element(new GuideActionRenderer<>(
|
||||
new GuideAction<>(bindings.DROP, ctx -> {
|
||||
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
||||
new GuideAction<>(bindings.DROP_INVENTORY, ctx -> {
|
||||
if (!ctx.holdingItem().isEmpty())
|
||||
return Optional.of(Component.translatable("controlify.guide.container.drop"));
|
||||
return Optional.empty();
|
||||
}),
|
||||
@ -171,7 +172,7 @@ public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<
|
||||
))
|
||||
.element(new GuideActionRenderer<>(
|
||||
new GuideAction<>(bindings.INV_QUICK_MOVE, ctx -> {
|
||||
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
||||
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem() && ctx.holdingItem().isEmpty())
|
||||
return Optional.of(Component.translatable("controlify.guide.container.quick_move"));
|
||||
return Optional.empty();
|
||||
}),
|
||||
|
@ -14,14 +14,18 @@ import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||
import dev.isxander.controlify.api.event.ControlifyEvents;
|
||||
import dev.isxander.controlify.mixins.feature.virtualmouse.KeyboardHandlerAccessor;
|
||||
import dev.isxander.controlify.mixins.feature.virtualmouse.MouseHandlerAccessor;
|
||||
import dev.isxander.controlify.utils.HoldRepeatHelper;
|
||||
import dev.isxander.controlify.utils.ToastUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.navigation.ScreenAxis;
|
||||
import net.minecraft.client.gui.navigation.ScreenDirection;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.joml.RoundingMode;
|
||||
import org.joml.Vector2d;
|
||||
import org.joml.Vector2dc;
|
||||
import org.joml.Vector2i;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
@ -42,6 +46,8 @@ public class VirtualMouseHandler {
|
||||
private Set<SnapPoint> snapPoints;
|
||||
private SnapPoint lastSnappedPoint;
|
||||
|
||||
private final HoldRepeatHelper holdRepeatHelper = new HoldRepeatHelper(10, 6);
|
||||
|
||||
public VirtualMouseHandler() {
|
||||
this.minecraft = Minecraft.getInstance();
|
||||
|
||||
@ -92,6 +98,20 @@ public class VirtualMouseHandler {
|
||||
|
||||
scrollY += controller.bindings().VMOUSE_SCROLL_UP.state() - controller.bindings().VMOUSE_SCROLL_DOWN.state();
|
||||
|
||||
if (holdRepeatHelper.shouldAction(controller.bindings().VMOUSE_SNAP_UP)) {
|
||||
snapInDirection(ScreenDirection.UP);
|
||||
holdRepeatHelper.onNavigate();
|
||||
} else if (holdRepeatHelper.shouldAction(controller.bindings().VMOUSE_SNAP_DOWN)) {
|
||||
snapInDirection(ScreenDirection.DOWN);
|
||||
holdRepeatHelper.onNavigate();
|
||||
} else if (holdRepeatHelper.shouldAction(controller.bindings().VMOUSE_SNAP_LEFT)) {
|
||||
snapInDirection(ScreenDirection.LEFT);
|
||||
holdRepeatHelper.onNavigate();
|
||||
} else if (holdRepeatHelper.shouldAction(controller.bindings().VMOUSE_SNAP_RIGHT)) {
|
||||
snapInDirection(ScreenDirection.RIGHT);
|
||||
holdRepeatHelper.onNavigate();
|
||||
}
|
||||
|
||||
if (ScreenProcessorProvider.provide(minecraft.screen).virtualMouseBehaviour().isDefaultOr(VirtualMouseBehaviour.ENABLED)) {
|
||||
handleCompatibilityBinds(controller);
|
||||
}
|
||||
@ -169,14 +189,58 @@ public class VirtualMouseHandler {
|
||||
.orElse(new Pair<>(null, Long.MAX_VALUE)).getFirst(); // retrieve point
|
||||
|
||||
if (closestSnapPoint != null) {
|
||||
lastSnappedPoint = closestSnapPoint;
|
||||
|
||||
targetX = currentX = closestSnapPoint.position().x() / scaleFactor.x();
|
||||
targetY = currentY = closestSnapPoint.position().y() / scaleFactor.y();
|
||||
((MouseHandlerAccessor) minecraft.mouseHandler).invokeOnMove(minecraft.getWindow().getWindow(), currentX, currentY);
|
||||
snapToPoint(closestSnapPoint, scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
private void snapInDirection(ScreenDirection direction) {
|
||||
var window = minecraft.getWindow();
|
||||
var scaleFactor = new Vector2d((double)window.getGuiScaledWidth() / (double)window.getScreenWidth(), (double)window.getGuiScaledHeight() / (double)window.getScreenHeight());
|
||||
var target = new Vector2d(targetX, targetY).mul(scaleFactor);
|
||||
|
||||
var closestSnapPoint = snapPoints.stream()
|
||||
.filter(snapPoint -> !snapPoint.equals(lastSnappedPoint)) // don't snap to the point currently over snapped point
|
||||
.map(snapPoint -> new Pair<>(snapPoint, new Vector2d(snapPoint.position().x() - target.x(), snapPoint.position().y() - target.y()))) // map with distance to current pos
|
||||
// filter points that are not in the correct direction
|
||||
.filter(pair -> {
|
||||
Vector2d dist = pair.getSecond();
|
||||
|
||||
double axis = direction.getAxis() == ScreenAxis.HORIZONTAL ? dist.x : dist.y;
|
||||
double positive = direction.isPositive() ? 1 : -1;
|
||||
|
||||
return axis * positive > 0;
|
||||
})
|
||||
.filter(pair -> {
|
||||
SnapPoint snapPoint = pair.getFirst();
|
||||
Vector2d dist = pair.getSecond();
|
||||
|
||||
double distance = Math.abs(direction.getAxis() == ScreenAxis.HORIZONTAL ? dist.x : dist.y);
|
||||
double deviation = Math.abs(direction.getAxis() == ScreenAxis.HORIZONTAL ? dist.y : dist.x);
|
||||
|
||||
pair.getSecond().set(distance, deviation);
|
||||
|
||||
return distance >= snapPoint.range();
|
||||
})
|
||||
// pick the closest point
|
||||
.min(Comparator.comparingDouble(pair -> {
|
||||
Vector2d distDev = pair.getSecond();
|
||||
return distDev.x + distDev.y;
|
||||
}))
|
||||
.map(Pair::getFirst);
|
||||
|
||||
closestSnapPoint.ifPresent(snapPoint -> {
|
||||
snapToPoint(snapPoint, scaleFactor);
|
||||
});
|
||||
}
|
||||
|
||||
public void snapToPoint(SnapPoint snapPoint, Vector2dc scaleFactor) {
|
||||
lastSnappedPoint = snapPoint;
|
||||
|
||||
targetX = currentX = snapPoint.position().x() / scaleFactor.x();
|
||||
targetY = currentY = snapPoint.position().y() / scaleFactor.y();
|
||||
((MouseHandlerAccessor) minecraft.mouseHandler).invokeOnMove(minecraft.getWindow().getWindow(), currentX, currentY);
|
||||
}
|
||||
|
||||
public void onScreenChanged() {
|
||||
if (minecraft.screen != null) {
|
||||
if (requiresVirtualMouse()) {
|
||||
|
@ -224,6 +224,7 @@
|
||||
"controlify.binding.controlify.inv_take_half": "Take Half",
|
||||
"controlify.binding.controlify.drop": "Drop Item",
|
||||
"controlify.binding.controlify.drop_stack": "Drop Stack",
|
||||
"controlify.binding.controlify.drop_inventory": "Drop Item (In Containers)",
|
||||
"controlify.binding.controlify.pick_block": "Pick Block",
|
||||
"controlify.binding.controlify.pick_block_nbt": "Pick Block (with NBT)",
|
||||
"controlify.binding.controlify.take_screenshot": "Take Screenshot",
|
||||
|
Reference in New Issue
Block a user