1
0
forked from Clones/Controlify

vmouse snapping

This commit is contained in:
isXander
2023-02-10 21:00:39 +00:00
parent 773aebe04e
commit 9e0440a7f4
41 changed files with 274 additions and 80 deletions

View File

@ -4,8 +4,8 @@ import com.mojang.blaze3d.vertex.PoseStack;
import dev.isxander.controlify.bindings.Bind; import dev.isxander.controlify.bindings.Bind;
import dev.isxander.controlify.bindings.IBind; import dev.isxander.controlify.bindings.IBind;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.yacl.api.Controller; import dev.isxander.yacl.api.Controller;
import dev.isxander.yacl.api.Option; import dev.isxander.yacl.api.Option;
import dev.isxander.yacl.api.utils.Dimension; import dev.isxander.yacl.api.utils.Dimension;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.vanilla.AbstractButtonComponentProcessor; import dev.isxander.controlify.screenop.compat.vanilla.AbstractButtonComponentProcessor;
import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.components.AbstractButton;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@ -1,6 +1,6 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.component.CustomFocus; import dev.isxander.controlify.screenop.CustomFocus;
import net.minecraft.client.gui.components.events.AbstractContainerEventHandler; import net.minecraft.client.gui.components.events.AbstractContainerEventHandler;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import dev.isxander.controlify.Controlify; import dev.isxander.controlify.Controlify;

View File

@ -1,10 +1,10 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import dev.isxander.controlify.Controlify; import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.InputMode; import dev.isxander.controlify.InputMode;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.vanilla.SliderComponentProcessor; import dev.isxander.controlify.screenop.compat.vanilla.SliderComponentProcessor;
import net.minecraft.client.InputType; import net.minecraft.client.InputType;
import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.client.gui.components.AbstractSliderButton;

View File

@ -1,6 +1,6 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.component.CustomFocus; import dev.isxander.controlify.screenop.CustomFocus;
import net.minecraft.client.gui.components.ContainerObjectSelectionList; import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTab;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.ScreenProcessorProvider; import dev.isxander.controlify.screenop.ScreenProcessorProvider;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.ScreenProcessorProvider; import dev.isxander.controlify.screenop.ScreenProcessorProvider;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.vanilla.LanguageSelectionListComponentProcessor; import dev.isxander.controlify.screenop.compat.vanilla.LanguageSelectionListComponentProcessor;
import net.minecraft.client.gui.screens.LanguageSelectScreen; import net.minecraft.client.gui.screens.LanguageSelectScreen;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import net.minecraft.client.gui.screens.OptionsSubScreen; import net.minecraft.client.gui.screens.OptionsSubScreen;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import net.minecraft.client.gui.ComponentPath; import net.minecraft.client.gui.ComponentPath;
import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.navigation.FocusNavigationEvent;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessorProvider; import dev.isxander.controlify.screenop.ScreenProcessorProvider;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.ScreenProcessorProvider; import dev.isxander.controlify.screenop.ScreenProcessorProvider;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.vanilla.ServerSelectionListEntryComponentProcessor; import dev.isxander.controlify.screenop.compat.vanilla.ServerSelectionListEntryComponentProcessor;
import net.minecraft.client.gui.screens.multiplayer.ServerSelectionList; import net.minecraft.client.gui.screens.multiplayer.ServerSelectionList;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.mixins.compat.screenop.vanilla; package dev.isxander.controlify.mixins.feature.screenop.vanilla;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.vanilla.WorldListEntryComponentProcessor; import dev.isxander.controlify.screenop.compat.vanilla.WorldListEntryComponentProcessor;
import net.minecraft.client.gui.screens.worldselection.WorldSelectionList; import net.minecraft.client.gui.screens.worldselection.WorldSelectionList;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.mixins.compat.screenop.yacl; package dev.isxander.controlify.mixins.feature.screenop.yacl;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.yacl.CyclingControllerElementComponentProcessor; import dev.isxander.controlify.screenop.compat.yacl.CyclingControllerElementComponentProcessor;
import dev.isxander.yacl.gui.controllers.cycling.CyclingControllerElement; import dev.isxander.yacl.gui.controllers.cycling.CyclingControllerElement;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.mixins.compat.screenop.yacl; package dev.isxander.controlify.mixins.feature.screenop.yacl;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider; import dev.isxander.controlify.screenop.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.compat.yacl.SliderControllerElementComponentProcessor; import dev.isxander.controlify.screenop.compat.yacl.SliderControllerElementComponentProcessor;
import dev.isxander.yacl.gui.controllers.slider.SliderControllerElement; import dev.isxander.yacl.gui.controllers.slider.SliderControllerElement;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.mixins.compat.screenop.yacl; package dev.isxander.controlify.mixins.feature.screenop.yacl;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.ScreenProcessorProvider; import dev.isxander.controlify.screenop.ScreenProcessorProvider;

View File

@ -0,0 +1,37 @@
package dev.isxander.controlify.mixins.feature.virtualmouse.snapping;
import dev.isxander.controlify.virtualmouse.ISnapBehaviour;
import dev.isxander.controlify.virtualmouse.SnapPoint;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.network.chat.Component;
import net.minecraft.world.inventory.AbstractContainerMenu;
import org.joml.Vector2i;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Set;
import java.util.stream.Collectors;
@Mixin(AbstractContainerScreen.class)
public abstract class AbstractContainerScreenMixin<T extends AbstractContainerMenu> extends Screen implements ISnapBehaviour {
protected AbstractContainerScreenMixin(Component title) {
super(title);
}
@Shadow public abstract T getMenu();
@Shadow protected int leftPos;
@Shadow protected int topPos;
@Shadow protected int imageHeight;
@Override
public Set<SnapPoint> getSnapPoints() {
return getMenu().slots.stream()
.map(slot -> new SnapPoint(new Vector2i(leftPos + slot.x + 8, topPos + slot.y + 8), 24))
.collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,48 @@
package dev.isxander.controlify.mixins.feature.virtualmouse.snapping;
import dev.isxander.controlify.virtualmouse.SnapPoint;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import org.joml.Vector2i;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Set;
@Mixin(CreativeModeInventoryScreen.class)
public abstract class CreativeModeInventoryScreenMixin extends AbstractContainerScreenMixin<CreativeModeInventoryScreen.ItemPickerMenu> {
@Shadow protected abstract int getTabX(CreativeModeTab group);
@Shadow private float scrollOffs;
@Shadow private EditBox searchBox;
@Shadow protected abstract boolean canScroll();
protected CreativeModeInventoryScreenMixin(Component title) {
super(title);
}
@Override
public Set<SnapPoint> getSnapPoints() {
Set<SnapPoint> points = super.getSnapPoints();
for (var tab : CreativeModeTabs.tabs()) {
boolean topRow = tab.row() == CreativeModeTab.Row.TOP;
int x = leftPos + getTabX(tab);
int y = topPos + (topRow ? -28 : imageHeight - 4);
points.add(new SnapPoint(new Vector2i(x + 13, y + 16), 38));
}
if (canScroll()) {
int scrollTop = topPos + 18;
int scrollBottom = scrollTop + 112;
points.add(new SnapPoint(new Vector2i(leftPos + 175 + 6, scrollTop + (int)((float)(scrollBottom - scrollTop - 17) * scrollOffs) + 7), 15));
}
if (searchBox.isVisible())
points.add(new SnapPoint(new Vector2i(searchBox.getX() + searchBox.getWidth() / 2, searchBox.getY() + searchBox.getHeight() / 2), searchBox.getHeight() + 2));
return points;
}
}

View File

@ -0,0 +1,31 @@
package dev.isxander.controlify.mixins.feature.virtualmouse.snapping;
import dev.isxander.controlify.virtualmouse.ISnapBehaviour;
import dev.isxander.controlify.virtualmouse.SnapPoint;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import org.joml.Vector2i;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Mixin(Screen.class)
public abstract class ScreenMixin implements ISnapBehaviour {
@Shadow public abstract List<? extends GuiEventListener> children();
@Override
public Set<SnapPoint> getSnapPoints() {
return children().stream()
.filter(child -> child instanceof AbstractWidget)
.map(AbstractWidget.class::cast)
.map(widget -> new SnapPoint(
new Vector2i(widget.getX() + widget.getWidth() / 2, widget.getY() + widget.getHeight() / 2),
Math.min(widget.getWidth(), widget.getHeight()) + 5
))
.collect(Collectors.toSet());
}
}

View File

@ -1,6 +1,5 @@
package dev.isxander.controlify.screenop.component; package dev.isxander.controlify.screenop;
import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
public interface ComponentProcessor { public interface ComponentProcessor {

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.screenop.component; package dev.isxander.controlify.screenop;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.screenop.component; package dev.isxander.controlify.screenop;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;

View File

@ -2,11 +2,9 @@ package dev.isxander.controlify.screenop;
import dev.isxander.controlify.Controlify; import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.InputMode; import dev.isxander.controlify.InputMode;
import dev.isxander.controlify.screenop.component.ComponentProcessorProvider;
import dev.isxander.controlify.screenop.component.CustomFocus;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.event.ControlifyEvents; import dev.isxander.controlify.event.ControlifyEvents;
import dev.isxander.controlify.mixins.compat.screenop.vanilla.ScreenAccessor; import dev.isxander.controlify.mixins.feature.screenop.vanilla.ScreenAccessor;
import net.minecraft.client.gui.ComponentPath; import net.minecraft.client.gui.ComponentPath;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.navigation.FocusNavigationEvent;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.screenop.compat.vanilla; package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.components.AbstractButton;

View File

@ -2,7 +2,7 @@ package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.mixins.compat.screenop.vanilla.CreativeModeInventoryScreenAccessor; import dev.isxander.controlify.mixins.feature.screenop.vanilla.CreativeModeInventoryScreenAccessor;
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.CreativeModeTabs;

View File

@ -1,9 +1,9 @@
package dev.isxander.controlify.screenop.compat.vanilla; package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.mixins.compat.screenop.vanilla.OptionsSubScreenAccessor; import dev.isxander.controlify.mixins.feature.screenop.vanilla.OptionsSubScreenAccessor;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
public class LanguageSelectionListComponentProcessor implements ComponentProcessor { public class LanguageSelectionListComponentProcessor implements ComponentProcessor {

View File

@ -2,7 +2,7 @@ package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.mixins.compat.screenop.vanilla.SelectWorldScreenAccessor; import dev.isxander.controlify.mixins.feature.screenop.vanilla.SelectWorldScreenAccessor;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen;

View File

@ -1,9 +1,9 @@
package dev.isxander.controlify.screenop.compat.vanilla; package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.mixins.compat.screenop.vanilla.JoinMultiplayerScreenAccessor; import dev.isxander.controlify.mixins.feature.screenop.vanilla.JoinMultiplayerScreenAccessor;
public class ServerSelectionListEntryComponentProcessor implements ComponentProcessor { public class ServerSelectionListEntryComponentProcessor implements ComponentProcessor {
@Override @Override

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.screenop.compat.vanilla; package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.client.gui.components.AbstractSliderButton;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;

View File

@ -1,9 +1,9 @@
package dev.isxander.controlify.screenop.compat.vanilla; package dev.isxander.controlify.screenop.compat.vanilla;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.mixins.compat.screenop.vanilla.SelectWorldScreenAccessor; import dev.isxander.controlify.mixins.feature.screenop.vanilla.SelectWorldScreenAccessor;
import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen; import net.minecraft.client.gui.screens.worldselection.SelectWorldScreen;
public class WorldListEntryComponentProcessor implements ComponentProcessor { public class WorldListEntryComponentProcessor implements ComponentProcessor {

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.screenop.compat.yacl; package dev.isxander.controlify.screenop.compat.yacl;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.yacl.gui.controllers.cycling.CyclingControllerElement; import dev.isxander.yacl.gui.controllers.cycling.CyclingControllerElement;

View File

@ -1,7 +1,7 @@
package dev.isxander.controlify.screenop.compat.yacl; package dev.isxander.controlify.screenop.compat.yacl;
import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessor;
import dev.isxander.controlify.screenop.component.ComponentProcessor; import dev.isxander.controlify.screenop.ComponentProcessor;
import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.Controller;
import dev.isxander.yacl.gui.controllers.slider.SliderControllerElement; import dev.isxander.yacl.gui.controllers.slider.SliderControllerElement;

View File

@ -0,0 +1,7 @@
package dev.isxander.controlify.virtualmouse;
import java.util.Set;
public interface ISnapBehaviour {
Set<SnapPoint> getSnapPoints();
}

View File

@ -0,0 +1,6 @@
package dev.isxander.controlify.virtualmouse;
import org.joml.Vector2ic;
public record SnapPoint(Vector2ic position, int range) {
}

View File

@ -2,6 +2,7 @@ package dev.isxander.controlify.virtualmouse;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.datafixers.util.Pair;
import dev.isxander.controlify.Controlify; import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.InputMode; import dev.isxander.controlify.InputMode;
import dev.isxander.controlify.screenop.ScreenProcessorProvider; import dev.isxander.controlify.screenop.ScreenProcessorProvider;
@ -9,15 +10,23 @@ import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.event.ControlifyEvents; import dev.isxander.controlify.event.ControlifyEvents;
import dev.isxander.controlify.mixins.feature.virtualmouse.KeyboardHandlerAccessor; import dev.isxander.controlify.mixins.feature.virtualmouse.KeyboardHandlerAccessor;
import dev.isxander.controlify.mixins.feature.virtualmouse.MouseHandlerAccessor; import dev.isxander.controlify.mixins.feature.virtualmouse.MouseHandlerAccessor;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.components.toasts.SystemToast; import net.minecraft.client.gui.components.toasts.SystemToast;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import org.joml.RoundingMode;
import org.joml.Vector2d;
import org.joml.Vector2i;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import java.util.Comparator;
import java.util.Set;
public class VirtualMouseHandler { public class VirtualMouseHandler {
private static final boolean DEBUG_SNAPPING = FabricLoader.getInstance().isDevelopmentEnvironment();
private static final ResourceLocation CURSOR_TEXTURE = new ResourceLocation("controlify", "textures/gui/virtual_mouse.png"); private static final ResourceLocation CURSOR_TEXTURE = new ResourceLocation("controlify", "textures/gui/virtual_mouse.png");
private double targetX, targetY; private double targetX, targetY;
@ -28,9 +37,17 @@ public class VirtualMouseHandler {
private final Minecraft minecraft; private final Minecraft minecraft;
private boolean virtualMouseEnabled; private boolean virtualMouseEnabled;
private Set<SnapPoint> snapPoints;
private SnapPoint snappedPoint, lastSnappedPoint;
public VirtualMouseHandler() { public VirtualMouseHandler() {
this.minecraft = Minecraft.getInstance(); this.minecraft = Minecraft.getInstance();
if (minecraft.screen != null && minecraft.screen instanceof ISnapBehaviour snapBehaviour)
snapPoints = snapBehaviour.getSnapPoints();
else
snapPoints = Set.of();
ControlifyEvents.INPUT_MODE_CHANGED.register(this::onInputModeChanged); ControlifyEvents.INPUT_MODE_CHANGED.register(this::onInputModeChanged);
} }
@ -45,6 +62,24 @@ public class VirtualMouseHandler {
var leftStickX = controller.state().axes().leftStickX(); var leftStickX = controller.state().axes().leftStickX();
var leftStickY = controller.state().axes().leftStickY(); var leftStickY = controller.state().axes().leftStickY();
var prevLeftStickX = controller.prevState().axes().leftStickX();
var prevLeftStickY = controller.prevState().axes().leftStickY();
if (minecraft.screen != null && minecraft.screen instanceof ISnapBehaviour snapBehaviour) {
snapPoints = snapBehaviour.getSnapPoints();
} else {
snapPoints = Set.of();
}
if (!snapPoints.contains(snappedPoint))
snappedPoint = null;
// if just released stick, snap to nearest snap point
if (leftStickX == 0 && leftStickY == 0) {
if ((prevLeftStickX != 0 || prevLeftStickY != 0))
snapToClosestPoint();
} else {
snappedPoint = null;
}
// quadratic function to make small movements smaller // quadratic function to make small movements smaller
// abs to keep sign // abs to keep sign
@ -82,8 +117,6 @@ public class VirtualMouseHandler {
} else if (controller.bindings().VMOUSE_ESCAPE.justReleased()) { } else if (controller.bindings().VMOUSE_ESCAPE.justReleased()) {
keyboardHandler.invokeKeyPress(minecraft.getWindow().getWindow(), GLFW.GLFW_KEY_ESCAPE, 0, GLFW.GLFW_RELEASE, 0); keyboardHandler.invokeKeyPress(minecraft.getWindow().getWindow(), GLFW.GLFW_KEY_ESCAPE, 0, GLFW.GLFW_RELEASE, 0);
} }
// TODO: scrolling with right stick
} }
public void updateMouse() { public void updateMouse() {
@ -111,6 +144,32 @@ public class VirtualMouseHandler {
} }
} }
private void snapToClosestPoint() {
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);
if (lastSnappedPoint != null) {
if (lastSnappedPoint.position().distanceSquared(new Vector2i(target, RoundingMode.FLOOR)) > lastSnappedPoint.range() * lastSnappedPoint.range() * scaleFactor.x()) {
lastSnappedPoint = null;
}
}
var closestSnapPoint = snapPoints.stream()
.filter(snapPoint -> snapPoint != lastSnappedPoint) // don't snap to the point currently over snapped point
.map(snapPoint -> new Pair<>(snapPoint, snapPoint.position().distanceSquared(new Vector2i(target, RoundingMode.FLOOR)))) // map with distance to current pos
.filter(point -> point.getSecond() <= point.getFirst().range() * point.getFirst().range() * scaleFactor.x()) // filter out of range options
.min(Comparator.comparingLong(Pair::getSecond)) // find the closest point
.orElse(new Pair<>(null, Long.MAX_VALUE)).getFirst(); // retrieve point
if (closestSnapPoint != null) {
snappedPoint = lastSnappedPoint = closestSnapPoint;
targetX = snappedPoint.position().x() / scaleFactor.x();
targetY = snappedPoint.position().y() / scaleFactor.y();
}
}
public void onScreenChanged() { public void onScreenChanged() {
if (minecraft.screen != null) { if (minecraft.screen != null) {
if (requiresVirtualMouse()) { if (requiresVirtualMouse()) {
@ -140,6 +199,12 @@ public class VirtualMouseHandler {
public void renderVirtualMouse(PoseStack matrices) { public void renderVirtualMouse(PoseStack matrices) {
if (!virtualMouseEnabled) return; if (!virtualMouseEnabled) return;
if (DEBUG_SNAPPING) {
for (var snapPoint : snapPoints) {
GuiComponent.fill(matrices, snapPoint.position().x() - 1, snapPoint.position().y() - 1, snapPoint.position().x() + 1, snapPoint.position().y() + 1, snapPoint == snappedPoint ? 0xFF00FF00 : snapPoint == lastSnappedPoint ? 0xFFFFFF00 : 0xFFFF0000);
}
}
RenderSystem.setShaderTexture(0, CURSOR_TEXTURE); RenderSystem.setShaderTexture(0, CURSOR_TEXTURE);
RenderSystem.setShaderColor(1f, 1f, 1f, 1f); RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
RenderSystem.enableBlend(); RenderSystem.enableBlend();

View File

@ -6,26 +6,6 @@
"mixins": [ "mixins": [
], ],
"client": [ "client": [
"compat.screenop.vanilla.AbstractButtonMixin",
"compat.screenop.vanilla.AbstractContainerEventHandlerMixin",
"compat.screenop.vanilla.AbstractSelectionListMixin",
"compat.screenop.vanilla.AbstractSliderButtonMixin",
"compat.screenop.vanilla.ContainerObjectSelectionListEntryMixin",
"compat.screenop.vanilla.CreativeModeInventoryScreenAccessor",
"compat.screenop.vanilla.CreativeModeInventoryScreenMixin",
"compat.screenop.vanilla.JoinMultiplayerScreenAccessor",
"compat.screenop.vanilla.JoinMultiplayerScreenMixin",
"compat.screenop.vanilla.LanguageSelectionListEntryMixin",
"compat.screenop.vanilla.OptionsSubScreenAccessor",
"compat.screenop.vanilla.ScreenAccessor",
"compat.screenop.vanilla.ScreenMixin",
"compat.screenop.vanilla.SelectWorldScreenAccessor",
"compat.screenop.vanilla.SelectWorldScreenMixin",
"compat.screenop.vanilla.ServerSelectionListEntryMixin",
"compat.screenop.vanilla.WorldSelectionListEntryMixin",
"compat.screenop.yacl.CyclingControllerElementMixin",
"compat.screenop.yacl.SliderControllerElementMixin",
"compat.screenop.yacl.YACLScreenMixin",
"core.ClientPacketListenerMixin", "core.ClientPacketListenerMixin",
"core.KeyboardHandlerMixin", "core.KeyboardHandlerMixin",
"core.MinecraftMixin", "core.MinecraftMixin",
@ -33,12 +13,35 @@
"feature.bind.KeyMappingAccessor", "feature.bind.KeyMappingAccessor",
"feature.guide.ClientPacketListenerMixin", "feature.guide.ClientPacketListenerMixin",
"feature.guide.GuiMixin", "feature.guide.GuiMixin",
"feature.screenop.vanilla.AbstractButtonMixin",
"feature.screenop.vanilla.AbstractContainerEventHandlerMixin",
"feature.screenop.vanilla.AbstractSelectionListMixin",
"feature.screenop.vanilla.AbstractSliderButtonMixin",
"feature.screenop.vanilla.ContainerObjectSelectionListEntryMixin",
"feature.screenop.vanilla.CreativeModeInventoryScreenAccessor",
"feature.screenop.vanilla.CreativeModeInventoryScreenMixin",
"feature.screenop.vanilla.JoinMultiplayerScreenAccessor",
"feature.screenop.vanilla.JoinMultiplayerScreenMixin",
"feature.screenop.vanilla.LanguageSelectionListEntryMixin",
"feature.screenop.vanilla.OptionsSubScreenAccessor",
"feature.screenop.vanilla.ScreenAccessor",
"feature.screenop.vanilla.ScreenMixin",
"feature.screenop.vanilla.SelectWorldScreenAccessor",
"feature.screenop.vanilla.SelectWorldScreenMixin",
"feature.screenop.vanilla.ServerSelectionListEntryMixin",
"feature.screenop.vanilla.WorldSelectionListEntryMixin",
"feature.screenop.yacl.CyclingControllerElementMixin",
"feature.screenop.yacl.SliderControllerElementMixin",
"feature.screenop.yacl.YACLScreenMixin",
"feature.settingsbutton.ControlsScreenMixin", "feature.settingsbutton.ControlsScreenMixin",
"feature.virtualmouse.GameRendererMixin", "feature.virtualmouse.GameRendererMixin",
"feature.virtualmouse.InputConstantsMixin", "feature.virtualmouse.InputConstantsMixin",
"feature.virtualmouse.KeyboardHandlerAccessor", "feature.virtualmouse.KeyboardHandlerAccessor",
"feature.virtualmouse.MinecraftMixin", "feature.virtualmouse.MinecraftMixin",
"feature.virtualmouse.MouseHandlerAccessor", "feature.virtualmouse.MouseHandlerAccessor",
"feature.virtualmouse.MouseHandlerMixin" "feature.virtualmouse.MouseHandlerMixin",
"feature.virtualmouse.snapping.AbstractContainerScreenMixin",
"feature.virtualmouse.snapping.CreativeModeInventoryScreenMixin",
"feature.virtualmouse.snapping.ScreenMixin"
] ]
} }