forked from Clones/Controlify
✏️ Move button guide to screen processor + vmouse improvements
This commit is contained in:
@ -72,6 +72,7 @@ dependencies {
|
|||||||
"fabric-lifecycle-events-v1",
|
"fabric-lifecycle-events-v1",
|
||||||
"fabric-key-binding-api-v1",
|
"fabric-key-binding-api-v1",
|
||||||
"fabric-registry-sync-v0",
|
"fabric-registry-sync-v0",
|
||||||
|
"fabric-screen-api-v1",
|
||||||
).forEach {
|
).forEach {
|
||||||
modImplementation(fabricApi.module(it, libs.versions.fabric.api.get()))
|
modImplementation(fabricApi.module(it, libs.versions.fabric.api.get()))
|
||||||
}
|
}
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
4
gradlew
vendored
4
gradlew
vendored
@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
|
@ -9,6 +9,7 @@ import dev.isxander.controlify.controller.Controller;
|
|||||||
import dev.isxander.controlify.controller.ControllerState;
|
import dev.isxander.controlify.controller.ControllerState;
|
||||||
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
||||||
import dev.isxander.controlify.debug.DebugProperties;
|
import dev.isxander.controlify.debug.DebugProperties;
|
||||||
|
import dev.isxander.controlify.gui.guide.ContainerButtonGuide;
|
||||||
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
||||||
import dev.isxander.controlify.gui.screen.SDLOnboardingScreen;
|
import dev.isxander.controlify.gui.screen.SDLOnboardingScreen;
|
||||||
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||||
@ -149,7 +150,7 @@ public class Controlify implements ControlifyApi {
|
|||||||
LOGGER.info("No controllers found.");
|
LOGGER.info("No controllers found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCurrentController().isEmpty() && config().isFirstLaunch()) {
|
if (getCurrentController().isEmpty()) {
|
||||||
this.setCurrentController(ControllerManager.getConnectedControllers().stream().findFirst().orElse(null));
|
this.setCurrentController(ControllerManager.getConnectedControllers().stream().findFirst().orElse(null));
|
||||||
} else {
|
} else {
|
||||||
// setCurrentController saves config
|
// setCurrentController saves config
|
||||||
@ -183,6 +184,7 @@ public class Controlify implements ControlifyApi {
|
|||||||
|
|
||||||
this.inGameInputHandler = null;
|
this.inGameInputHandler = null;
|
||||||
this.virtualMouseHandler = new VirtualMouseHandler();
|
this.virtualMouseHandler = new VirtualMouseHandler();
|
||||||
|
//ContainerButtonGuide.setup();
|
||||||
|
|
||||||
controllerHIDService = new ControllerHIDService();
|
controllerHIDService = new ControllerHIDService();
|
||||||
controllerHIDService.start();
|
controllerHIDService.start();
|
||||||
|
@ -8,9 +8,10 @@ public final class BindContexts {
|
|||||||
public static final BindContext
|
public static final BindContext
|
||||||
INGAME = ctx("ingame"),
|
INGAME = ctx("ingame"),
|
||||||
GUI = ctx("gui"),
|
GUI = ctx("gui"),
|
||||||
GUI_VMOUSE = ctx("gui_vmouse"),
|
GUI_VMOUSE_CURSOR_ONLY = ctx("gui_vmouse_cursor"),
|
||||||
|
GUI_VMOUSE = ctx("gui_vmouse", GUI_VMOUSE_CURSOR_ONLY),
|
||||||
CONTROLIFY_CONFIG = ctx("controlify_config", GUI),
|
CONTROLIFY_CONFIG = ctx("controlify_config", GUI),
|
||||||
INVENTORY = ctx("inventory", GUI_VMOUSE);
|
INVENTORY = ctx("inventory", GUI_VMOUSE_CURSOR_ONLY);
|
||||||
|
|
||||||
private static BindContext ctx(String path, BindContext... parents) {
|
private static BindContext ctx(String path, BindContext... parents) {
|
||||||
return new BindContext(Controlify.id(path), Set.of(parents));
|
return new BindContext(Controlify.id(path), Set.of(parents));
|
||||||
|
@ -275,25 +275,25 @@ public class ControllerBindings<T extends ControllerState> {
|
|||||||
.identifier("controlify", "vmouse_move_up")
|
.identifier("controlify", "vmouse_move_up")
|
||||||
.defaultBind(GamepadBinds.LEFT_STICK_FORWARD)
|
.defaultBind(GamepadBinds.LEFT_STICK_FORWARD)
|
||||||
.category(VMOUSE_CATEGORY)
|
.category(VMOUSE_CATEGORY)
|
||||||
.context(BindContexts.GUI_VMOUSE)
|
.context(BindContexts.GUI_VMOUSE_CURSOR_ONLY)
|
||||||
.build());
|
.build());
|
||||||
register(VMOUSE_MOVE_DOWN = ControllerBindingBuilder.create(controller)
|
register(VMOUSE_MOVE_DOWN = ControllerBindingBuilder.create(controller)
|
||||||
.identifier("controlify", "vmouse_move_down")
|
.identifier("controlify", "vmouse_move_down")
|
||||||
.defaultBind(GamepadBinds.LEFT_STICK_BACKWARD)
|
.defaultBind(GamepadBinds.LEFT_STICK_BACKWARD)
|
||||||
.category(VMOUSE_CATEGORY)
|
.category(VMOUSE_CATEGORY)
|
||||||
.context(BindContexts.GUI_VMOUSE)
|
.context(BindContexts.GUI_VMOUSE_CURSOR_ONLY)
|
||||||
.build());
|
.build());
|
||||||
register(VMOUSE_MOVE_LEFT = ControllerBindingBuilder.create(controller)
|
register(VMOUSE_MOVE_LEFT = ControllerBindingBuilder.create(controller)
|
||||||
.identifier("controlify", "vmouse_move_left")
|
.identifier("controlify", "vmouse_move_left")
|
||||||
.defaultBind(GamepadBinds.LEFT_STICK_LEFT)
|
.defaultBind(GamepadBinds.LEFT_STICK_LEFT)
|
||||||
.category(VMOUSE_CATEGORY)
|
.category(VMOUSE_CATEGORY)
|
||||||
.context(BindContexts.GUI_VMOUSE)
|
.context(BindContexts.GUI_VMOUSE_CURSOR_ONLY)
|
||||||
.build());
|
.build());
|
||||||
register(VMOUSE_MOVE_RIGHT = ControllerBindingBuilder.create(controller)
|
register(VMOUSE_MOVE_RIGHT = ControllerBindingBuilder.create(controller)
|
||||||
.identifier("controlify", "vmouse_move_right")
|
.identifier("controlify", "vmouse_move_right")
|
||||||
.defaultBind(GamepadBinds.LEFT_STICK_RIGHT)
|
.defaultBind(GamepadBinds.LEFT_STICK_RIGHT)
|
||||||
.category(VMOUSE_CATEGORY)
|
.category(VMOUSE_CATEGORY)
|
||||||
.context(BindContexts.GUI_VMOUSE)
|
.context(BindContexts.GUI_VMOUSE_CURSOR_ONLY)
|
||||||
.build());
|
.build());
|
||||||
register(VMOUSE_LCLICK = ControllerBindingBuilder.create(controller)
|
register(VMOUSE_LCLICK = ControllerBindingBuilder.create(controller)
|
||||||
.identifier("controlify", "vmouse_lclick")
|
.identifier("controlify", "vmouse_lclick")
|
||||||
@ -335,7 +335,7 @@ public class ControllerBindings<T extends ControllerState> {
|
|||||||
.identifier("controlify", "vmouse_toggle")
|
.identifier("controlify", "vmouse_toggle")
|
||||||
.defaultBind(GamepadBinds.BACK)
|
.defaultBind(GamepadBinds.BACK)
|
||||||
.category(VMOUSE_CATEGORY)
|
.category(VMOUSE_CATEGORY)
|
||||||
.context(BindContexts.GUI_VMOUSE)
|
.context(BindContexts.GUI_VMOUSE, BindContexts.GUI)
|
||||||
.build());
|
.build());
|
||||||
register(GUI_NAVI_UP = ControllerBindingBuilder.create(controller)
|
register(GUI_NAVI_UP = ControllerBindingBuilder.create(controller)
|
||||||
.identifier("controlify", "gui_navi_up")
|
.identifier("controlify", "gui_navi_up")
|
||||||
|
@ -1,4 +1,178 @@
|
|||||||
package dev.isxander.controlify.gui.guide;
|
package dev.isxander.controlify.gui.guide;
|
||||||
|
|
||||||
public class ContainerButtonGuide {
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import dev.isxander.controlify.InputMode;
|
||||||
|
import dev.isxander.controlify.api.ControlifyApi;
|
||||||
|
import dev.isxander.controlify.api.event.ControlifyEvents;
|
||||||
|
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||||
|
import dev.isxander.controlify.compatibility.ControlifyCompat;
|
||||||
|
import dev.isxander.controlify.controller.Controller;
|
||||||
|
import dev.isxander.controlify.gui.layout.AnchorPoint;
|
||||||
|
import dev.isxander.controlify.gui.layout.ColumnLayoutComponent;
|
||||||
|
import dev.isxander.controlify.gui.layout.PositionedComponent;
|
||||||
|
import dev.isxander.controlify.gui.layout.RowLayoutComponent;
|
||||||
|
import dev.isxander.controlify.mixins.feature.guide.screen.AbstractContainerScreenAccessor;
|
||||||
|
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class ContainerButtonGuide {
|
||||||
|
private static PositionedComponent<ColumnLayoutComponent<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>> leftLayout;
|
||||||
|
private static PositionedComponent<ColumnLayoutComponent<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>> rightLayout;
|
||||||
|
|
||||||
|
public static void setup() {
|
||||||
|
ScreenEvents.BEFORE_INIT.register((minecraft, screen, sw, sh) -> {
|
||||||
|
removeLayout();
|
||||||
|
|
||||||
|
if (isScreenCompatible(screen)) {
|
||||||
|
setupLayout();
|
||||||
|
|
||||||
|
ScreenEvents.afterRender(screen).register((s, stack, mouseX, mouseY, tickDelta) -> {
|
||||||
|
// Fabric API provides the wrong matrixstack (which is translated -2000), behind
|
||||||
|
// the ortho near plane, so we need to translate it back to the front.
|
||||||
|
// https://github.com/FabricMC/fabric/pull/3061
|
||||||
|
stack.pushPose();
|
||||||
|
stack.translate(0, 0, 2000);
|
||||||
|
|
||||||
|
renderGuide((AbstractContainerScreen<?>) s, stack, tickDelta, mouseX, mouseY, sw, sh);
|
||||||
|
|
||||||
|
stack.popPose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ControlifyEvents.INPUT_MODE_CHANGED.register(mode -> {
|
||||||
|
if (isScreenCompatible(Minecraft.getInstance().screen)) {
|
||||||
|
if (mode == InputMode.CONTROLLER) {
|
||||||
|
setupLayout();
|
||||||
|
} else {
|
||||||
|
removeLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupLayout() {
|
||||||
|
ControllerBindings<?> bindings = ControlifyApi.get().getCurrentController()
|
||||||
|
.map(Controller::bindings)
|
||||||
|
.orElseThrow();
|
||||||
|
|
||||||
|
leftLayout = new PositionedComponent<>(
|
||||||
|
ColumnLayoutComponent.<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>builder()
|
||||||
|
.spacing(2)
|
||||||
|
.colPadding(2, 2)
|
||||||
|
.elementPosition(ColumnLayoutComponent.ElementPosition.LEFT)
|
||||||
|
.element(RowLayoutComponent.<GuideActionRenderer<ContainerGuideCtx>>builder()
|
||||||
|
.spacing(5)
|
||||||
|
.rowPadding(0)
|
||||||
|
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.VMOUSE_LCLICK, ctx -> {
|
||||||
|
if (!ctx.holdingItem().isEmpty())
|
||||||
|
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
||||||
|
if (ctx.hoveredSlot().mayPlace(ctx.holdingItem()))
|
||||||
|
if (ctx.holdingItem().getCount() > 1)
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.place_all"));
|
||||||
|
else
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.place_one"));
|
||||||
|
else
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.swap"));
|
||||||
|
else if (ctx.cursorOutsideContainer())
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.drop"));
|
||||||
|
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.take"));
|
||||||
|
return Optional.empty();
|
||||||
|
}),
|
||||||
|
false, false
|
||||||
|
))
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.GUI_BACK, ctx -> {
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.exit"));
|
||||||
|
}),
|
||||||
|
false, false
|
||||||
|
))
|
||||||
|
.build())
|
||||||
|
.build(),
|
||||||
|
AnchorPoint.BOTTOM_LEFT,
|
||||||
|
0, 0,
|
||||||
|
AnchorPoint.BOTTOM_LEFT
|
||||||
|
);
|
||||||
|
|
||||||
|
rightLayout = new PositionedComponent<>(
|
||||||
|
ColumnLayoutComponent.<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>builder()
|
||||||
|
.spacing(2)
|
||||||
|
.elementPosition(ColumnLayoutComponent.ElementPosition.RIGHT)
|
||||||
|
.colPadding(2, 2)
|
||||||
|
.element(RowLayoutComponent.<GuideActionRenderer<ContainerGuideCtx>>builder()
|
||||||
|
.spacing(5)
|
||||||
|
.rowPadding(0)
|
||||||
|
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.VMOUSE_RCLICK, ctx -> {
|
||||||
|
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().getItem().getCount() > 1 && ctx.holdingItem().isEmpty())
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.take_half"));
|
||||||
|
if (ctx.hoveredSlot() != null && !ctx.holdingItem().isEmpty() && ctx.hoveredSlot().mayPlace(ctx.holdingItem()))
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.take_one"));
|
||||||
|
return Optional.empty();
|
||||||
|
}),
|
||||||
|
true, false
|
||||||
|
))
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.VMOUSE_SHIFT_CLICK, ctx -> {
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.quick_move"));
|
||||||
|
}),
|
||||||
|
true, false
|
||||||
|
))
|
||||||
|
.build())
|
||||||
|
.build(),
|
||||||
|
AnchorPoint.BOTTOM_RIGHT,
|
||||||
|
0, 0,
|
||||||
|
AnchorPoint.BOTTOM_RIGHT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeLayout() {
|
||||||
|
leftLayout = null;
|
||||||
|
rightLayout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void renderGuide(AbstractContainerScreen<?> screen, PoseStack stack, float tickDelta, int mouseX, int mouseY, int screenWidth, int screenHeight) {
|
||||||
|
if (leftLayout == null || rightLayout == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!ControlifyApi.get().getCurrentController().map(controller -> controller.config().showScreenGuide).orElse(false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessor = (AbstractContainerScreenAccessor) screen;
|
||||||
|
|
||||||
|
ContainerGuideCtx ctx = new ContainerGuideCtx(accessor.getHoveredSlot(), screen.getMenu().getCarried(), accessor.invokeHasClickedOutside(mouseX, mouseY, accessor.getLeftPos(), accessor.getTopPos(), 0));
|
||||||
|
|
||||||
|
for (var row : leftLayout.getComponent().getChildComponents()) {
|
||||||
|
for (var element : row.getChildComponents()) {
|
||||||
|
element.updateName(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var row : rightLayout.getComponent().getChildComponents()) {
|
||||||
|
for (var element : row.getChildComponents()) {
|
||||||
|
element.updateName(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leftLayout.updatePosition();
|
||||||
|
rightLayout.updatePosition();
|
||||||
|
|
||||||
|
ControlifyCompat.ifBeginHudBatching();
|
||||||
|
leftLayout.renderComponent(stack, tickDelta);
|
||||||
|
rightLayout.renderComponent(stack, tickDelta);
|
||||||
|
ControlifyCompat.ifEndHudBatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isScreenCompatible(Screen screen) {
|
||||||
|
return screen instanceof AbstractContainerScreen<?>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,8 @@ public class InGameButtonGuide implements IngameGuideRegistry {
|
|||||||
|
|
||||||
ControlifyCompat.ifBeginHudBatching();
|
ControlifyCompat.ifBeginHudBatching();
|
||||||
|
|
||||||
leftLayout.render(poseStack, tickDelta);
|
leftLayout.renderComponent(poseStack, tickDelta);
|
||||||
rightLayout.render(poseStack, tickDelta);
|
rightLayout.renderComponent(poseStack, tickDelta);
|
||||||
|
|
||||||
ControlifyCompat.ifEndHudBatching();
|
ControlifyCompat.ifEndHudBatching();
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package dev.isxander.controlify.gui.layout;
|
package dev.isxander.controlify.gui.layout;
|
||||||
|
|
||||||
import org.joml.Vector2f;
|
|
||||||
import org.joml.Vector2fc;
|
|
||||||
import org.joml.Vector2i;
|
import org.joml.Vector2i;
|
||||||
import org.joml.Vector2ic;
|
|
||||||
|
|
||||||
public enum AnchorPoint {
|
public enum AnchorPoint {
|
||||||
TOP_LEFT(0, 0),
|
TOP_LEFT(0, 0),
|
||||||
@ -23,7 +20,7 @@ public enum AnchorPoint {
|
|||||||
this.anchorY = anchorY;
|
this.anchorY = anchorY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2i getAnchorPosition(Vector2ic windowSize) {
|
public Vector2i getAnchorPosition(int w, int h) {
|
||||||
return new Vector2i((int) (windowSize.x() * anchorX), (int) (windowSize.y() * anchorY));
|
return new Vector2i((int) (w * anchorX), (int) (h * anchorY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package dev.isxander.controlify.gui.layout;
|
package dev.isxander.controlify.gui.layout;
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.Window;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import org.joml.Vector2i;
|
import net.minecraft.client.gui.components.Renderable;
|
||||||
import org.joml.Vector2ic;
|
import org.joml.Vector2ic;
|
||||||
|
|
||||||
public class PositionedComponent<T extends RenderComponent> {
|
public class PositionedComponent<T extends RenderComponent> implements Renderable {
|
||||||
private final T component;
|
private final T component;
|
||||||
|
|
||||||
private int x, y;
|
private int x, y;
|
||||||
@ -21,19 +20,24 @@ public class PositionedComponent<T extends RenderComponent> {
|
|||||||
this.offsetY = offsetY;
|
this.offsetY = offsetY;
|
||||||
this.windowAnchor = windowAnchor;
|
this.windowAnchor = windowAnchor;
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
|
|
||||||
updatePosition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePosition() {
|
public void updatePosition() {
|
||||||
Vector2ic windowPosition = windowAnchor.getAnchorPosition(windowSize());
|
Vector2ic componentSize = component.size();
|
||||||
Vector2ic anchoredPosition = origin.getAnchorPosition(component.size());
|
|
||||||
|
Vector2ic windowPosition = windowAnchor.getAnchorPosition(Minecraft.getInstance().getWindow().getGuiScaledWidth(), Minecraft.getInstance().getWindow().getGuiScaledHeight());
|
||||||
|
Vector2ic anchoredPosition = origin.getAnchorPosition(componentSize.x(), componentSize.y());
|
||||||
|
|
||||||
this.x = windowPosition.x() + offsetX - anchoredPosition.x();
|
this.x = windowPosition.x() + offsetX - anchoredPosition.x();
|
||||||
this.y = windowPosition.y() + offsetY - anchoredPosition.y();
|
this.y = windowPosition.y() + offsetY - anchoredPosition.y();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(PoseStack stack, float deltaTime) {
|
@Override
|
||||||
|
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||||
|
this.renderComponent(matrices, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderComponent(PoseStack stack, float deltaTime) {
|
||||||
component.render(stack, x, y, deltaTime);
|
component.render(stack, x, y, deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,9 +52,4 @@ public class PositionedComponent<T extends RenderComponent> {
|
|||||||
public T getComponent() {
|
public T getComponent() {
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2i windowSize() {
|
|
||||||
Window window = Minecraft.getInstance().getWindow();
|
|
||||||
return new Vector2i(window.getGuiScaledWidth(), window.getGuiScaledHeight());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,8 @@ public class RowLayoutComponent<T extends RenderComponent> extends AbstractLayou
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder<T> elements(T... elements) {
|
@SafeVarargs
|
||||||
|
public final Builder<T> elements(T... elements) {
|
||||||
this.elements.addAll(Arrays.asList(elements));
|
this.elements.addAll(Arrays.asList(elements));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package dev.isxander.controlify.mixins.feature.guide.screen;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||||
|
|
||||||
|
@Mixin(AbstractContainerScreen.class)
|
||||||
|
public interface AbstractContainerScreenAccessor {
|
||||||
|
@Accessor
|
||||||
|
Slot getHoveredSlot();
|
||||||
|
|
||||||
|
@Invoker
|
||||||
|
boolean invokeHasClickedOutside(double mouseX, double mouseY, int left, int top, int button);
|
||||||
|
|
||||||
|
@Accessor
|
||||||
|
int getLeftPos();
|
||||||
|
|
||||||
|
@Accessor
|
||||||
|
int getTopPos();
|
||||||
|
}
|
@ -1,153 +0,0 @@
|
|||||||
package dev.isxander.controlify.mixins.feature.guide.screen;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import dev.isxander.controlify.InputMode;
|
|
||||||
import dev.isxander.controlify.api.ControlifyApi;
|
|
||||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
|
||||||
import dev.isxander.controlify.controller.Controller;
|
|
||||||
import dev.isxander.controlify.gui.guide.ContainerGuideCtx;
|
|
||||||
import dev.isxander.controlify.gui.guide.GuideAction;
|
|
||||||
import dev.isxander.controlify.gui.guide.GuideActionRenderer;
|
|
||||||
import dev.isxander.controlify.gui.layout.AnchorPoint;
|
|
||||||
import dev.isxander.controlify.gui.layout.ColumnLayoutComponent;
|
|
||||||
import dev.isxander.controlify.gui.layout.PositionedComponent;
|
|
||||||
import dev.isxander.controlify.gui.layout.RowLayoutComponent;
|
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
|
||||||
import net.minecraft.world.inventory.Slot;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
// TODO: Move out of mixin
|
|
||||||
@Mixin(AbstractContainerScreen.class)
|
|
||||||
public abstract class AbstractContainerScreenMixin<T extends AbstractContainerMenu> {
|
|
||||||
@Shadow @Nullable protected Slot hoveredSlot;
|
|
||||||
@Shadow @Final protected T menu;
|
|
||||||
@Shadow protected int leftPos;
|
|
||||||
@Shadow protected int topPos;
|
|
||||||
@Shadow protected abstract boolean hasClickedOutside(double mouseX, double mouseY, int left, int top, int button);
|
|
||||||
|
|
||||||
@Unique private PositionedComponent<ColumnLayoutComponent<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>> leftLayout;
|
|
||||||
@Unique private PositionedComponent<ColumnLayoutComponent<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>> rightLayout;
|
|
||||||
|
|
||||||
@Inject(method = "init", at = @At("RETURN"))
|
|
||||||
private void initButtonGuide(CallbackInfo ci) {
|
|
||||||
ControllerBindings<?> bindings = ControlifyApi.get().getCurrentController()
|
|
||||||
.map(Controller::bindings)
|
|
||||||
.orElse(null);
|
|
||||||
|
|
||||||
if (bindings == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
leftLayout = new PositionedComponent<>(
|
|
||||||
ColumnLayoutComponent.<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>builder()
|
|
||||||
.spacing(2)
|
|
||||||
.colPadding(2, 2)
|
|
||||||
.elementPosition(ColumnLayoutComponent.ElementPosition.LEFT)
|
|
||||||
.element(RowLayoutComponent.<GuideActionRenderer<ContainerGuideCtx>>builder()
|
|
||||||
.spacing(5)
|
|
||||||
.rowPadding(0)
|
|
||||||
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
|
||||||
.element(new GuideActionRenderer<>(
|
|
||||||
new GuideAction<>(bindings.VMOUSE_LCLICK, ctx -> {
|
|
||||||
if (!ctx.holdingItem().isEmpty())
|
|
||||||
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
|
||||||
if (ctx.hoveredSlot().mayPlace(ctx.holdingItem()))
|
|
||||||
if (ctx.holdingItem().getCount() > 1)
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.place_all"));
|
|
||||||
else
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.place_one"));
|
|
||||||
else
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.swap"));
|
|
||||||
else if (ctx.cursorOutsideContainer())
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.drop"));
|
|
||||||
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.take"));
|
|
||||||
return Optional.empty();
|
|
||||||
}),
|
|
||||||
false, false
|
|
||||||
))
|
|
||||||
.elements(new GuideActionRenderer<>(
|
|
||||||
new GuideAction<>(bindings.GUI_BACK, ctx -> {
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.exit"));
|
|
||||||
}),
|
|
||||||
false, false
|
|
||||||
))
|
|
||||||
.build())
|
|
||||||
.build(),
|
|
||||||
AnchorPoint.BOTTOM_LEFT,
|
|
||||||
0, 0,
|
|
||||||
AnchorPoint.BOTTOM_LEFT
|
|
||||||
);
|
|
||||||
|
|
||||||
rightLayout = new PositionedComponent<>(
|
|
||||||
ColumnLayoutComponent.<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>>builder()
|
|
||||||
.spacing(2)
|
|
||||||
.elementPosition(ColumnLayoutComponent.ElementPosition.RIGHT)
|
|
||||||
.colPadding(2, 2)
|
|
||||||
.element(RowLayoutComponent.<GuideActionRenderer<ContainerGuideCtx>>builder()
|
|
||||||
.spacing(5)
|
|
||||||
.rowPadding(0)
|
|
||||||
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
|
||||||
.element(new GuideActionRenderer<>(
|
|
||||||
new GuideAction<>(bindings.VMOUSE_RCLICK, ctx -> {
|
|
||||||
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().getItem().getCount() > 1 && ctx.holdingItem().isEmpty())
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.take_half"));
|
|
||||||
if (ctx.hoveredSlot() != null && !ctx.holdingItem().isEmpty() && ctx.hoveredSlot().mayPlace(ctx.holdingItem()))
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.take_one"));
|
|
||||||
return Optional.empty();
|
|
||||||
}),
|
|
||||||
true, false
|
|
||||||
))
|
|
||||||
.element(new GuideActionRenderer<>(
|
|
||||||
new GuideAction<>(bindings.VMOUSE_SHIFT_CLICK, ctx -> {
|
|
||||||
return Optional.of(Component.translatable("controlify.guide.container.quick_move"));
|
|
||||||
}),
|
|
||||||
true, false
|
|
||||||
))
|
|
||||||
.build())
|
|
||||||
.build(),
|
|
||||||
AnchorPoint.BOTTOM_RIGHT,
|
|
||||||
0, 0,
|
|
||||||
AnchorPoint.BOTTOM_RIGHT
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "render", at = @At("RETURN"))
|
|
||||||
private void renderButtonGuide(PoseStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
|
|
||||||
if (!ControlifyApi.get().getCurrentController().map(controller -> controller.config().showScreenGuide).orElse(false)
|
|
||||||
|| ControlifyApi.get().currentInputMode() != InputMode.CONTROLLER
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerGuideCtx ctx = new ContainerGuideCtx(hoveredSlot, menu.getCarried(), hasClickedOutside(mouseX, mouseY, this.leftPos, this.topPos, 0));
|
|
||||||
|
|
||||||
for (var row : leftLayout.getComponent().getChildComponents()) {
|
|
||||||
for (var element : row.getChildComponents()) {
|
|
||||||
element.updateName(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var row : rightLayout.getComponent().getChildComponents()) {
|
|
||||||
for (var element : row.getChildComponents()) {
|
|
||||||
element.updateName(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
leftLayout.updatePosition();
|
|
||||||
rightLayout.updatePosition();
|
|
||||||
|
|
||||||
leftLayout.render(matrices, delta);
|
|
||||||
rightLayout.render(matrices, delta);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,27 @@
|
|||||||
|
package dev.isxander.controlify.mixins.feature.screenop;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import dev.isxander.controlify.api.ControlifyApi;
|
||||||
|
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(GameRenderer.class)
|
||||||
|
public class GameRendererMixin {
|
||||||
|
@Shadow @Final Minecraft minecraft;
|
||||||
|
|
||||||
|
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;renderWithTooltip(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V", shift = At.Shift.AFTER))
|
||||||
|
private void onPostRenderScreen(float tickDelta, long startTime, boolean tick, CallbackInfo ci, @Local(ordinal = 1) PoseStack poseStack) {
|
||||||
|
ControlifyApi.get().getCurrentController().ifPresent(controller -> {
|
||||||
|
if (minecraft.screen == null) return;
|
||||||
|
ScreenProcessorProvider.provide(minecraft.screen).render(controller, poseStack, tickDelta);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,16 @@
|
|||||||
package dev.isxander.controlify.mixins.feature.screenop.vanilla;
|
package dev.isxander.controlify.mixins.feature.screenop;
|
||||||
|
|
||||||
import net.minecraft.client.gui.ComponentPath;
|
import net.minecraft.client.gui.ComponentPath;
|
||||||
|
import net.minecraft.client.gui.components.Renderable;
|
||||||
import net.minecraft.client.gui.navigation.FocusNavigationEvent;
|
import net.minecraft.client.gui.navigation.FocusNavigationEvent;
|
||||||
import net.minecraft.client.gui.navigation.ScreenDirection;
|
import net.minecraft.client.gui.navigation.ScreenDirection;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Mixin(Screen.class)
|
@Mixin(Screen.class)
|
||||||
public interface ScreenAccessor {
|
public interface ScreenAccessor {
|
||||||
@Invoker
|
@Invoker
|
||||||
@ -17,4 +21,7 @@ public interface ScreenAccessor {
|
|||||||
|
|
||||||
@Invoker
|
@Invoker
|
||||||
void invokeClearFocus();
|
void invokeClearFocus();
|
||||||
|
|
||||||
|
@Accessor
|
||||||
|
List<Renderable> getRenderables();
|
||||||
}
|
}
|
@ -1,13 +1,16 @@
|
|||||||
package dev.isxander.controlify.screenop;
|
package dev.isxander.controlify.screenop;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.InputMode;
|
import dev.isxander.controlify.InputMode;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.api.event.ControlifyEvents;
|
import dev.isxander.controlify.api.event.ControlifyEvents;
|
||||||
import dev.isxander.controlify.mixins.feature.screenop.vanilla.ScreenAccessor;
|
import dev.isxander.controlify.mixins.feature.screenop.ScreenAccessor;
|
||||||
import dev.isxander.controlify.mixins.feature.screenop.vanilla.TabNavigationBarAccessor;
|
import dev.isxander.controlify.mixins.feature.screenop.vanilla.TabNavigationBarAccessor;
|
||||||
import dev.isxander.controlify.sound.ControlifySounds;
|
import dev.isxander.controlify.sound.ControlifySounds;
|
||||||
import dev.isxander.controlify.utils.NavigationHelper;
|
import dev.isxander.controlify.utils.NavigationHelper;
|
||||||
|
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour;
|
||||||
|
import dev.isxander.controlify.virtualmouse.VirtualMouseHandler;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
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;
|
||||||
@ -25,7 +28,7 @@ import java.util.*;
|
|||||||
public class ScreenProcessor<T extends Screen> {
|
public class ScreenProcessor<T extends Screen> {
|
||||||
public final T screen;
|
public final T screen;
|
||||||
protected final NavigationHelper navigationHelper = new NavigationHelper(10, 3);
|
protected final NavigationHelper navigationHelper = new NavigationHelper(10, 3);
|
||||||
protected final Minecraft minecraft = Minecraft.getInstance();
|
protected static final Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
|
||||||
public ScreenProcessor(T screen) {
|
public ScreenProcessor(T screen) {
|
||||||
this.screen = screen;
|
this.screen = screen;
|
||||||
@ -40,12 +43,17 @@ public class ScreenProcessor<T extends Screen> {
|
|||||||
if (!handleComponentButtonOverride(controller))
|
if (!handleComponentButtonOverride(controller))
|
||||||
handleButtons(controller);
|
handleButtons(controller);
|
||||||
} else {
|
} else {
|
||||||
handleScreenVMouse(controller);
|
handleScreenVMouse(controller, Controlify.instance().virtualMouseHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTabNavigation(controller);
|
handleTabNavigation(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void render(Controller<?, ?> controller, PoseStack poseStack, float tickDelta) {
|
||||||
|
var vmouse = Controlify.instance().virtualMouseHandler();
|
||||||
|
this.render(controller, poseStack, tickDelta, vmouse.isVirtualMouseEnabled() ? Optional.of(vmouse) : Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
public void onInputModeChanged(InputMode mode) {
|
public void onInputModeChanged(InputMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case KEYBOARD_MOUSE -> ((ScreenAccessor) screen).invokeClearFocus();
|
case KEYBOARD_MOUSE -> ((ScreenAccessor) screen).invokeClearFocus();
|
||||||
@ -115,12 +123,12 @@ public class ScreenProcessor<T extends Screen> {
|
|||||||
screen.keyPressed(GLFW.GLFW_KEY_ENTER, 0, 0);
|
screen.keyPressed(GLFW.GLFW_KEY_ENTER, 0, 0);
|
||||||
}
|
}
|
||||||
if (controller.bindings().GUI_BACK.justPressed()) {
|
if (controller.bindings().GUI_BACK.justPressed()) {
|
||||||
this.playClackSound();
|
playClackSound();
|
||||||
screen.onClose();
|
screen.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleScreenVMouse(Controller<?, ?> controller) {
|
protected void handleScreenVMouse(Controller<?, ?> controller, VirtualMouseHandler vmouse) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +188,10 @@ public class ScreenProcessor<T extends Screen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void render(Controller<?, ?> controller, PoseStack poseStack, float tickDelta, Optional<VirtualMouseHandler> vmouse) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected void setInitialFocus() {
|
protected void setInitialFocus() {
|
||||||
if (screen.getFocused() == null && Controlify.instance().currentInputMode() == InputMode.CONTROLLER && !Controlify.instance().virtualMouseHandler().isVirtualMouseEnabled()) {
|
if (screen.getFocused() == null && Controlify.instance().currentInputMode() == InputMode.CONTROLLER && !Controlify.instance().virtualMouseHandler().isVirtualMouseEnabled()) {
|
||||||
var accessor = (ScreenAccessor) screen;
|
var accessor = (ScreenAccessor) screen;
|
||||||
@ -191,8 +203,8 @@ public class ScreenProcessor<T extends Screen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean forceVirtualMouse() {
|
public VirtualMouseBehaviour virtualMouseBehaviour() {
|
||||||
return false;
|
return VirtualMouseBehaviour.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Queue<GuiEventListener> getFocusTree() {
|
protected Queue<GuiEventListener> getFocusTree() {
|
||||||
@ -211,7 +223,7 @@ public class ScreenProcessor<T extends Screen> {
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void playClackSound() {
|
public static void playClackSound() {
|
||||||
minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package dev.isxander.controlify.screenop;
|
package dev.isxander.controlify.screenop;
|
||||||
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface ScreenProcessorProvider {
|
public interface ScreenProcessorProvider {
|
||||||
ScreenProcessor<?> screenProcessor();
|
ScreenProcessor<?> screenProcessor();
|
||||||
|
|
||||||
static ScreenProcessor<?> provide(Screen screen) {
|
static ScreenProcessor<?> provide(@NotNull Screen screen) {
|
||||||
Optional<ScreenProcessor<?>> optional = REGISTRY.get(screen);
|
Optional<ScreenProcessor<?>> optional = REGISTRY.get(screen);
|
||||||
if (optional.isPresent()) return optional.get();
|
if (optional.isPresent()) return optional.get();
|
||||||
|
|
||||||
|
@ -1,14 +1,34 @@
|
|||||||
package dev.isxander.controlify.screenop.compat.vanilla;
|
package dev.isxander.controlify.screenop.compat.vanilla;
|
||||||
|
|
||||||
|
import dev.isxander.controlify.InputMode;
|
||||||
|
import dev.isxander.controlify.api.ControlifyApi;
|
||||||
|
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
|
import dev.isxander.controlify.gui.guide.ContainerGuideCtx;
|
||||||
|
import dev.isxander.controlify.gui.guide.GuideAction;
|
||||||
|
import dev.isxander.controlify.gui.guide.GuideActionRenderer;
|
||||||
|
import dev.isxander.controlify.gui.layout.AnchorPoint;
|
||||||
|
import dev.isxander.controlify.gui.layout.PositionedComponent;
|
||||||
|
import dev.isxander.controlify.gui.layout.RowLayoutComponent;
|
||||||
|
import dev.isxander.controlify.mixins.feature.guide.screen.AbstractContainerScreenAccessor;
|
||||||
|
import dev.isxander.controlify.mixins.feature.screenop.ScreenAccessor;
|
||||||
import dev.isxander.controlify.screenop.ScreenProcessor;
|
import dev.isxander.controlify.screenop.ScreenProcessor;
|
||||||
|
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour;
|
||||||
|
import dev.isxander.controlify.virtualmouse.VirtualMouseHandler;
|
||||||
|
import net.minecraft.client.gui.components.Renderable;
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.inventory.ClickType;
|
import net.minecraft.world.inventory.ClickType;
|
||||||
import net.minecraft.world.inventory.Slot;
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<?>> extends ScreenProcessor<T> {
|
public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<?>> extends ScreenProcessor<T> {
|
||||||
|
private PositionedComponent<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>> leftLayout;
|
||||||
|
private PositionedComponent<RowLayoutComponent<GuideActionRenderer<ContainerGuideCtx>>> rightLayout;
|
||||||
|
|
||||||
private final Supplier<Slot> hoveredSlot;
|
private final Supplier<Slot> hoveredSlot;
|
||||||
private final ClickSlotFunction clickSlotFunction;
|
private final ClickSlotFunction clickSlotFunction;
|
||||||
|
|
||||||
@ -19,13 +39,134 @@ public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleScreenVMouse(Controller<?, ?> controller) {
|
protected void handleScreenVMouse(Controller<?, ?> controller, VirtualMouseHandler vmouse) {
|
||||||
if (controller.bindings().DROP.justPressed()) {
|
if (controller.bindings().DROP.justPressed()) {
|
||||||
Slot slot = hoveredSlot.get();
|
Slot slot = hoveredSlot.get();
|
||||||
if (slot != null && slot.hasItem()) {
|
if (slot != null && slot.hasItem()) {
|
||||||
clickSlotFunction.clickSlot(slot, slot.index, 0, ClickType.THROW);
|
clickSlotFunction.clickSlot(slot, slot.index, 0, ClickType.THROW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (leftLayout != null && rightLayout != null) {
|
||||||
|
var accessor = (AbstractContainerScreenAccessor) screen;
|
||||||
|
|
||||||
|
ContainerGuideCtx ctx = new ContainerGuideCtx(hoveredSlot.get(), screen.getMenu().getCarried(), accessor.invokeHasClickedOutside(vmouse.getCurrentX(1f), vmouse.getCurrentY(1f), accessor.getLeftPos(), accessor.getTopPos(), 0));
|
||||||
|
|
||||||
|
for (var element : leftLayout.getComponent().getChildComponents()) {
|
||||||
|
element.updateName(ctx);
|
||||||
|
}
|
||||||
|
for (var element : rightLayout.getComponent().getChildComponents()) {
|
||||||
|
element.updateName(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
leftLayout.updatePosition();
|
||||||
|
rightLayout.updatePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWidgetRebuild() {
|
||||||
|
ControllerBindings<?> bindings = ControlifyApi.get().getCurrentController()
|
||||||
|
.map(Controller::bindings)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (bindings == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftLayout = new PositionedComponent<>(
|
||||||
|
RowLayoutComponent.<GuideActionRenderer<ContainerGuideCtx>>builder()
|
||||||
|
.spacing(5)
|
||||||
|
.rowPadding(0)
|
||||||
|
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.VMOUSE_LCLICK, ctx -> {
|
||||||
|
if (!ctx.holdingItem().isEmpty())
|
||||||
|
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
||||||
|
if (ctx.hoveredSlot().mayPlace(ctx.holdingItem()))
|
||||||
|
if (ctx.holdingItem().getCount() > 1)
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.place_all"));
|
||||||
|
else
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.place_one"));
|
||||||
|
else
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.swap"));
|
||||||
|
else if (ctx.cursorOutsideContainer())
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.drop"));
|
||||||
|
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().hasItem())
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.take"));
|
||||||
|
return Optional.empty();
|
||||||
|
}),
|
||||||
|
false, false
|
||||||
|
))
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.GUI_BACK, ctx -> {
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.exit"));
|
||||||
|
}),
|
||||||
|
false, false
|
||||||
|
))
|
||||||
|
.build(),
|
||||||
|
AnchorPoint.BOTTOM_LEFT,
|
||||||
|
0, 0,
|
||||||
|
AnchorPoint.BOTTOM_LEFT
|
||||||
|
);
|
||||||
|
|
||||||
|
rightLayout = new PositionedComponent<>(
|
||||||
|
RowLayoutComponent.<GuideActionRenderer<ContainerGuideCtx>>builder()
|
||||||
|
.spacing(5)
|
||||||
|
.rowPadding(0)
|
||||||
|
.elementPosition(RowLayoutComponent.ElementPosition.MIDDLE)
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.VMOUSE_RCLICK, ctx -> {
|
||||||
|
if (ctx.hoveredSlot() != null && ctx.hoveredSlot().getItem().getCount() > 1 && ctx.holdingItem().isEmpty())
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.take_half"));
|
||||||
|
if (ctx.hoveredSlot() != null && !ctx.holdingItem().isEmpty() && ctx.hoveredSlot().mayPlace(ctx.holdingItem()))
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.take_one"));
|
||||||
|
return Optional.empty();
|
||||||
|
}),
|
||||||
|
true, false
|
||||||
|
))
|
||||||
|
.element(new GuideActionRenderer<>(
|
||||||
|
new GuideAction<>(bindings.VMOUSE_SHIFT_CLICK, ctx -> {
|
||||||
|
return Optional.of(Component.translatable("controlify.guide.container.quick_move"));
|
||||||
|
}),
|
||||||
|
true, false
|
||||||
|
))
|
||||||
|
.build(),
|
||||||
|
AnchorPoint.BOTTOM_RIGHT,
|
||||||
|
0, 0,
|
||||||
|
AnchorPoint.BOTTOM_RIGHT
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ControlifyApi.get().currentInputMode() == InputMode.CONTROLLER) {
|
||||||
|
setRenderGuide(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputModeChanged(InputMode mode) {
|
||||||
|
setRenderGuide(mode == InputMode.CONTROLLER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRenderGuide(boolean render) {
|
||||||
|
List<Renderable> renderables = ((ScreenAccessor) screen).getRenderables();
|
||||||
|
|
||||||
|
if (leftLayout == null || rightLayout == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (render) {
|
||||||
|
if (!renderables.contains(leftLayout))
|
||||||
|
renderables.add(leftLayout);
|
||||||
|
if (!renderables.contains(rightLayout))
|
||||||
|
renderables.add(rightLayout);
|
||||||
|
} else {
|
||||||
|
renderables.remove(leftLayout);
|
||||||
|
renderables.remove(rightLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VirtualMouseBehaviour virtualMouseBehaviour() {
|
||||||
|
return VirtualMouseBehaviour.CURSOR_ONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package dev.isxander.controlify.screenop.compat.vanilla;
|
package dev.isxander.controlify.screenop.compat.vanilla;
|
||||||
|
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.screenop.ScreenProcessor;
|
|
||||||
import dev.isxander.controlify.mixins.feature.screenop.vanilla.CreativeModeInventoryScreenAccessor;
|
import dev.isxander.controlify.mixins.feature.screenop.vanilla.CreativeModeInventoryScreenAccessor;
|
||||||
|
import dev.isxander.controlify.virtualmouse.VirtualMouseHandler;
|
||||||
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
|
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
|
||||||
import net.minecraft.world.inventory.Slot;
|
import net.minecraft.world.inventory.Slot;
|
||||||
import net.minecraft.world.item.CreativeModeTabs;
|
import net.minecraft.world.item.CreativeModeTabs;
|
||||||
@ -15,7 +15,7 @@ public class CreativeModeInventoryScreenProcessor extends AbstractContainerScree
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleScreenVMouse(Controller<?, ?> controller) {
|
protected void handleScreenVMouse(Controller<?, ?> controller, VirtualMouseHandler vmouse) {
|
||||||
var accessor = (CreativeModeInventoryScreenAccessor) screen;
|
var accessor = (CreativeModeInventoryScreenAccessor) screen;
|
||||||
|
|
||||||
if (controller.bindings().GUI_NEXT_TAB.justPressed()) {
|
if (controller.bindings().GUI_NEXT_TAB.justPressed()) {
|
||||||
@ -31,6 +31,6 @@ public class CreativeModeInventoryScreenProcessor extends AbstractContainerScree
|
|||||||
accessor.invokeSelectTab(tabs.get(newIndex));
|
accessor.invokeSelectTab(tabs.get(newIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
super.handleScreenVMouse(controller);
|
super.handleScreenVMouse(controller, vmouse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package dev.isxander.controlify.virtualmouse;
|
||||||
|
|
||||||
|
public enum VirtualMouseBehaviour {
|
||||||
|
DEFAULT,
|
||||||
|
ENABLED,
|
||||||
|
DISABLED,
|
||||||
|
CURSOR_ONLY;
|
||||||
|
|
||||||
|
public boolean hasCursor() {
|
||||||
|
return this != DISABLED;
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,14 @@ import dev.isxander.controlify.api.vmousesnapping.ISnapBehaviour;
|
|||||||
import dev.isxander.controlify.api.vmousesnapping.SnapPoint;
|
import dev.isxander.controlify.api.vmousesnapping.SnapPoint;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.debug.DebugProperties;
|
import dev.isxander.controlify.debug.DebugProperties;
|
||||||
|
import dev.isxander.controlify.screenop.ScreenProcessor;
|
||||||
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||||
import dev.isxander.controlify.api.event.ControlifyEvents;
|
import dev.isxander.controlify.api.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 dev.isxander.controlify.utils.ToastUtils;
|
||||||
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.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;
|
||||||
@ -40,7 +41,6 @@ public class VirtualMouseHandler {
|
|||||||
|
|
||||||
private Set<SnapPoint> snapPoints;
|
private Set<SnapPoint> snapPoints;
|
||||||
private SnapPoint lastSnappedPoint;
|
private SnapPoint lastSnappedPoint;
|
||||||
private boolean snapping;
|
|
||||||
|
|
||||||
public VirtualMouseHandler() {
|
public VirtualMouseHandler() {
|
||||||
this.minecraft = Minecraft.getInstance();
|
this.minecraft = Minecraft.getInstance();
|
||||||
@ -77,8 +77,6 @@ public class VirtualMouseHandler {
|
|||||||
if (impulseX == 0 && impulseY == 0) {
|
if (impulseX == 0 && impulseY == 0) {
|
||||||
if ((prevImpulseX != 0 || prevImpulseY != 0))
|
if ((prevImpulseX != 0 || prevImpulseY != 0))
|
||||||
snapToClosestPoint();
|
snapToClosestPoint();
|
||||||
} else {
|
|
||||||
snapping = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var sensitivity = controller.config().virtualMouseSensitivity;
|
var sensitivity = controller.config().virtualMouseSensitivity;
|
||||||
@ -91,6 +89,17 @@ public class VirtualMouseHandler {
|
|||||||
targetX = Mth.clamp(targetX, 0, minecraft.getWindow().getWidth());
|
targetX = Mth.clamp(targetX, 0, minecraft.getWindow().getWidth());
|
||||||
targetY = Mth.clamp(targetY, 0, minecraft.getWindow().getHeight());
|
targetY = Mth.clamp(targetY, 0, minecraft.getWindow().getHeight());
|
||||||
|
|
||||||
|
if (controller.bindings().GUI_BACK.justPressed() && minecraft.screen != null) {
|
||||||
|
ScreenProcessor.playClackSound();
|
||||||
|
minecraft.screen.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ScreenProcessorProvider.provide(minecraft.screen).virtualMouseBehaviour().hasCursor()) {
|
||||||
|
handleCompatibilityBinds(controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCompatibilityBinds(Controller<?, ?> controller) {
|
||||||
scrollY += controller.bindings().VMOUSE_SCROLL_UP.state() - controller.bindings().VMOUSE_SCROLL_DOWN.state();
|
scrollY += controller.bindings().VMOUSE_SCROLL_UP.state() - controller.bindings().VMOUSE_SCROLL_DOWN.state();
|
||||||
|
|
||||||
var mouseHandler = (MouseHandlerAccessor) minecraft.mouseHandler;
|
var mouseHandler = (MouseHandlerAccessor) minecraft.mouseHandler;
|
||||||
@ -113,10 +122,6 @@ public class VirtualMouseHandler {
|
|||||||
} else if (controller.bindings().VMOUSE_SHIFT_CLICK.justReleased()) {
|
} else if (controller.bindings().VMOUSE_SHIFT_CLICK.justReleased()) {
|
||||||
mouseHandler.invokeOnPress(minecraft.getWindow().getWindow(), GLFW.GLFW_MOUSE_BUTTON_LEFT, GLFW.GLFW_RELEASE, 0);
|
mouseHandler.invokeOnPress(minecraft.getWindow().getWindow(), GLFW.GLFW_MOUSE_BUTTON_LEFT, GLFW.GLFW_RELEASE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller.bindings().GUI_BACK.justPressed() && minecraft.screen != null) {
|
|
||||||
minecraft.screen.onClose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMouse() {
|
public void updateMouse() {
|
||||||
@ -164,7 +169,6 @@ public class VirtualMouseHandler {
|
|||||||
|
|
||||||
if (closestSnapPoint != null) {
|
if (closestSnapPoint != null) {
|
||||||
lastSnappedPoint = closestSnapPoint;
|
lastSnappedPoint = closestSnapPoint;
|
||||||
snapping = false;
|
|
||||||
|
|
||||||
targetX = currentX = closestSnapPoint.position().x() / scaleFactor.x();
|
targetX = currentX = closestSnapPoint.position().x() / scaleFactor.x();
|
||||||
targetY = currentY = closestSnapPoint.position().y() / scaleFactor.y();
|
targetY = currentY = closestSnapPoint.position().y() / scaleFactor.y();
|
||||||
@ -271,15 +275,30 @@ public class VirtualMouseHandler {
|
|||||||
public boolean requiresVirtualMouse() {
|
public boolean requiresVirtualMouse() {
|
||||||
var isController = Controlify.instance().currentInputMode() == InputMode.CONTROLLER;
|
var isController = Controlify.instance().currentInputMode() == InputMode.CONTROLLER;
|
||||||
var hasScreen = minecraft.screen != null;
|
var hasScreen = minecraft.screen != null;
|
||||||
var forceVirtualMouse = hasScreen && ScreenProcessorProvider.provide(minecraft.screen).forceVirtualMouse();
|
|
||||||
var screenIsVMouseScreen = hasScreen && Controlify.instance().config().globalSettings().virtualMouseScreens.stream().anyMatch(s -> s.isAssignableFrom(minecraft.screen.getClass()));
|
|
||||||
|
|
||||||
return isController && hasScreen && (forceVirtualMouse || screenIsVMouseScreen);
|
if (isController && hasScreen) {
|
||||||
|
return switch (ScreenProcessorProvider.provide(minecraft.screen).virtualMouseBehaviour()) {
|
||||||
|
case DEFAULT -> Controlify.instance().config().globalSettings().virtualMouseScreens.stream().anyMatch(s -> s.isAssignableFrom(minecraft.screen.getClass()));
|
||||||
|
case ENABLED, CURSOR_ONLY -> true;
|
||||||
|
case DISABLED -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleVirtualMouse() {
|
public void toggleVirtualMouse() {
|
||||||
if (minecraft.screen == null) return;
|
if (minecraft.screen == null) return;
|
||||||
|
|
||||||
|
if (ScreenProcessorProvider.provide(minecraft.screen).virtualMouseBehaviour() != VirtualMouseBehaviour.DEFAULT) {
|
||||||
|
ToastUtils.sendToast(
|
||||||
|
Component.translatable("controlify.toast.vmouse_unavailable.title"),
|
||||||
|
Component.translatable("controlify.toast.vmouse_unavailable.description"),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var screens = Controlify.instance().config().globalSettings().virtualMouseScreens;
|
var screens = Controlify.instance().config().globalSettings().virtualMouseScreens;
|
||||||
var screenClass = minecraft.screen.getClass();
|
var screenClass = minecraft.screen.getClass();
|
||||||
if (screens.contains(screenClass)) {
|
if (screens.contains(screenClass)) {
|
||||||
@ -287,22 +306,20 @@ public class VirtualMouseHandler {
|
|||||||
disableVirtualMouse();
|
disableVirtualMouse();
|
||||||
Controlify.instance().hideMouse(true, false);
|
Controlify.instance().hideMouse(true, false);
|
||||||
|
|
||||||
minecraft.getToasts().addToast(SystemToast.multiline(
|
ToastUtils.sendToast(
|
||||||
minecraft,
|
|
||||||
SystemToast.SystemToastIds.PERIODIC_NOTIFICATION,
|
|
||||||
Component.translatable("controlify.toast.vmouse_disabled.title"),
|
Component.translatable("controlify.toast.vmouse_disabled.title"),
|
||||||
Component.translatable("controlify.toast.vmouse_disabled.description")
|
Component.translatable("controlify.toast.vmouse_disabled.description"),
|
||||||
));
|
false
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
screens.add(screenClass);
|
screens.add(screenClass);
|
||||||
enableVirtualMouse();
|
enableVirtualMouse();
|
||||||
|
|
||||||
minecraft.getToasts().addToast(SystemToast.multiline(
|
ToastUtils.sendToast(
|
||||||
minecraft,
|
|
||||||
SystemToast.SystemToastIds.PERIODIC_NOTIFICATION,
|
|
||||||
Component.translatable("controlify.toast.vmouse_enabled.title"),
|
Component.translatable("controlify.toast.vmouse_enabled.title"),
|
||||||
Component.translatable("controlify.toast.vmouse_enabled.description")
|
Component.translatable("controlify.toast.vmouse_enabled.description"),
|
||||||
));
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Controlify.instance().config().save();
|
Controlify.instance().config().save();
|
||||||
@ -311,4 +328,12 @@ public class VirtualMouseHandler {
|
|||||||
public boolean isVirtualMouseEnabled() {
|
public boolean isVirtualMouseEnabled() {
|
||||||
return virtualMouseEnabled;
|
return virtualMouseEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCurrentX(float deltaTime) {
|
||||||
|
return (int) Mth.lerp(deltaTime, currentX, targetX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentY(float deltaTime) {
|
||||||
|
return (int) Mth.lerp(deltaTime, currentY, targetY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,8 @@
|
|||||||
"controlify.toast.vmouse_enabled.description": "Controlify virtual mouse is now enabled for this screen.",
|
"controlify.toast.vmouse_enabled.description": "Controlify virtual mouse is now enabled for this screen.",
|
||||||
"controlify.toast.vmouse_disabled.title": "Virtual Mouse Disabled",
|
"controlify.toast.vmouse_disabled.title": "Virtual Mouse Disabled",
|
||||||
"controlify.toast.vmouse_disabled.description": "Controlify virtual mouse is now disabled for this screen.",
|
"controlify.toast.vmouse_disabled.description": "Controlify virtual mouse is now disabled for this screen.",
|
||||||
|
"controlify.toast.vmouse_unavailable.title": "Virtual Mouse Unavailable",
|
||||||
|
"controlify.toast.vmouse_unavailable.description": "This screen is forcing a specific virtual mouse mode and you cannot change it.",
|
||||||
"controlify.toast.ask_to_switch.title": "Switch Controller?",
|
"controlify.toast.ask_to_switch.title": "Switch Controller?",
|
||||||
"controlify.toast.ask_to_switch.description": "A new controller named '%s' has just been connected. Press any button to switch to it.",
|
"controlify.toast.ask_to_switch.description": "A new controller named '%s' has just been connected. Press any button to switch to it.",
|
||||||
"controlify.toast.default_controller_connected.title": "Controller Connected",
|
"controlify.toast.default_controller_connected.title": "Controller Connected",
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"feature.guide.ingame.ClientPacketListenerMixin",
|
"feature.guide.ingame.ClientPacketListenerMixin",
|
||||||
"feature.guide.ingame.GuiMixin",
|
"feature.guide.ingame.GuiMixin",
|
||||||
"feature.guide.screen.AbstractButtonMixin",
|
"feature.guide.screen.AbstractButtonMixin",
|
||||||
"feature.guide.screen.AbstractContainerScreenMixin",
|
"feature.guide.screen.AbstractContainerScreenAccessor",
|
||||||
"feature.guide.screen.AbstractWidgetMixin",
|
"feature.guide.screen.AbstractWidgetMixin",
|
||||||
"feature.guide.screen.TabNavigationBarMixin",
|
"feature.guide.screen.TabNavigationBarMixin",
|
||||||
"feature.oofinput.GameRendererMixin",
|
"feature.oofinput.GameRendererMixin",
|
||||||
@ -49,7 +49,9 @@
|
|||||||
"feature.rumble.explosion.ClientPacketListenerMixin",
|
"feature.rumble.explosion.ClientPacketListenerMixin",
|
||||||
"feature.rumble.itembreak.LocalPlayerMixin",
|
"feature.rumble.itembreak.LocalPlayerMixin",
|
||||||
"feature.rumble.useitem.LocalPlayerMixin",
|
"feature.rumble.useitem.LocalPlayerMixin",
|
||||||
|
"feature.screenop.GameRendererMixin",
|
||||||
"feature.screenop.MinecraftMixin",
|
"feature.screenop.MinecraftMixin",
|
||||||
|
"feature.screenop.ScreenAccessor",
|
||||||
"feature.screenop.ScreenMixin",
|
"feature.screenop.ScreenMixin",
|
||||||
"feature.screenop.vanilla.AbstractButtonMixin",
|
"feature.screenop.vanilla.AbstractButtonMixin",
|
||||||
"feature.screenop.vanilla.AbstractContainerEventHandlerMixin",
|
"feature.screenop.vanilla.AbstractContainerEventHandlerMixin",
|
||||||
@ -64,7 +66,6 @@
|
|||||||
"feature.screenop.vanilla.JoinMultiplayerScreenMixin",
|
"feature.screenop.vanilla.JoinMultiplayerScreenMixin",
|
||||||
"feature.screenop.vanilla.LanguageSelectionListEntryMixin",
|
"feature.screenop.vanilla.LanguageSelectionListEntryMixin",
|
||||||
"feature.screenop.vanilla.OptionsSubScreenAccessor",
|
"feature.screenop.vanilla.OptionsSubScreenAccessor",
|
||||||
"feature.screenop.vanilla.ScreenAccessor",
|
|
||||||
"feature.screenop.vanilla.SelectWorldScreenAccessor",
|
"feature.screenop.vanilla.SelectWorldScreenAccessor",
|
||||||
"feature.screenop.vanilla.SelectWorldScreenMixin",
|
"feature.screenop.vanilla.SelectWorldScreenMixin",
|
||||||
"feature.screenop.vanilla.ServerSelectionListEntryMixin",
|
"feature.screenop.vanilla.ServerSelectionListEntryMixin",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package dev.isxander.controlify.test;
|
package dev.isxander.controlify.test;
|
||||||
|
|
||||||
import dev.isxander.controlify.controller.Controller;
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.Screenshot;
|
import net.minecraft.client.Screenshot;
|
||||||
|
|
||||||
@ -69,7 +68,6 @@ public class ClientTestHelper {
|
|||||||
|
|
||||||
public static FakeController createAndUseDummyController() {
|
public static FakeController createAndUseDummyController() {
|
||||||
var controller = new FakeController();
|
var controller = new FakeController();
|
||||||
Controller.CONTROLLERS.put(controller.uid(), controller);
|
|
||||||
controller.use();
|
controller.use();
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
|
||||||
import dev.isxander.controlify.controller.ControllerType;
|
import dev.isxander.controlify.controller.ControllerType;
|
||||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||||
import dev.isxander.controlify.controller.joystick.JoystickConfig;
|
import dev.isxander.controlify.controller.joystick.JoystickConfig;
|
||||||
@ -194,7 +193,6 @@ public class FakeController implements JoystickController<JoystickConfig> {
|
|||||||
|
|
||||||
public void finish() {
|
public void finish() {
|
||||||
Controlify.instance().setCurrentController(null);
|
Controlify.instance().setCurrentController(null);
|
||||||
Controller.CONTROLLERS.remove(uid, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user