1
0
forked from Clones/Controlify

Implement basic container guide (unfinished)

This commit is contained in:
isXander
2023-05-12 15:45:11 +01:00
parent 4c9cb11830
commit 45c20bb2dc
22 changed files with 318 additions and 123 deletions

View File

@ -15,7 +15,7 @@ import dev.isxander.controlify.screenop.ScreenProcessorProvider;
import dev.isxander.controlify.config.ControlifyConfig;
import dev.isxander.controlify.controller.hid.ControllerHIDService;
import dev.isxander.controlify.api.event.ControlifyEvents;
import dev.isxander.controlify.ingame.guide.InGameButtonGuide;
import dev.isxander.controlify.gui.guide.InGameButtonGuide;
import dev.isxander.controlify.ingame.InGameInputHandler;
import dev.isxander.controlify.mixins.feature.virtualmouse.MouseHandlerAccessor;
import dev.isxander.controlify.sound.ControlifySounds;
@ -270,7 +270,8 @@ public class Controlify implements ControlifyApi {
this.virtualMouseHandler().handleControllerInput(controller);
if (minecraft.screen != null) {
ScreenProcessorProvider.provide(minecraft.screen).onControllerUpdate(controller);
} else if (minecraft.level != null) {
}
if (minecraft.level != null) {
this.inGameInputHandler().ifPresent(InGameInputHandler::inputTick);
}

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.api.ingameguide;
package dev.isxander.controlify.api.guide;
/**
* Defines how the action is sorted in the list. All default Controlify actions are {@link #NORMAL}.

View File

@ -1,4 +1,4 @@
package dev.isxander.controlify.api.ingameguide;
package dev.isxander.controlify.api.guide;
import net.minecraft.network.chat.Component;
@ -11,6 +11,6 @@ import java.util.Optional;
* This is supplied once every tick.
*/
@FunctionalInterface
public interface GuideActionNameSupplier {
Optional<Component> supply(IngameGuideContext ctx);
public interface GuideActionNameSupplier<T> {
Optional<Component> supply(T ctx);
}

View File

@ -1,6 +1,8 @@
package dev.isxander.controlify.api.ingameguide;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.api.guide.ActionPriority;
import dev.isxander.controlify.api.guide.GuideActionNameSupplier;
/**
* Allows you to register your own actions to the button guide.
@ -16,7 +18,7 @@ public interface IngameGuideRegistry {
* @param priority the priority of the action, used to sort the list.
* @param supplier the supplier for the name of the action. can be empty to hide the action.
*/
void registerGuideAction(ControllerBinding binding, ActionLocation location, ActionPriority priority, GuideActionNameSupplier supplier);
void registerGuideAction(ControllerBinding binding, ActionLocation location, ActionPriority priority, GuideActionNameSupplier<IngameGuideContext> supplier);
/**
* Registers a new action to the button guide.
@ -25,5 +27,5 @@ public interface IngameGuideRegistry {
* @param location the location of the action, left or right.
* @param supplier the supplier for the name of the action. can be empty to hide the action.
*/
void registerGuideAction(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier supplier);
void registerGuideAction(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier<IngameGuideContext> supplier);
}

View File

@ -194,7 +194,6 @@ public class ControllerBindings<T extends ControllerState> {
.defaultBind(GamepadBinds.Y_BUTTON)
.category(INVENTORY_CATEGORY)
.context(BindContexts.INGAME)
.vanillaOverride(options.keyInventory, () -> false)
.build());
register(CHANGE_PERSPECTIVE = ControllerBindingBuilder.create(controller)
.identifier("controlify", "change_perspective")

View File

@ -5,6 +5,7 @@ import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.ControllerManager;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.bindings.BindContext;
import dev.isxander.controlify.bindings.EmptyBind;
import dev.isxander.controlify.config.GlobalSettings;
import dev.isxander.controlify.controller.BatteryLevel;
import dev.isxander.controlify.controller.Controller;
@ -297,7 +298,8 @@ public class YACLHelper {
.stream()
.anyMatch(ctxs::contains);
boolean bindMatches = pair.option().pendingValue().equals(opt.option().pendingValue());
return contextsMatch && bindMatches;
boolean bindIsNotEmpty = !(pair.option().pendingValue() instanceof EmptyBind<?>);
return contextsMatch && bindMatches && bindIsNotEmpty;
}).toList();
conflicting.forEach(conflict -> ((AbstractBindController<?>) conflict.option().controller()).setConflicting(true));

View File

@ -0,0 +1,4 @@
package dev.isxander.controlify.gui.guide;
public class ContainerButtonGuide {
}

View File

@ -0,0 +1,8 @@
package dev.isxander.controlify.gui.guide;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
public record ContainerGuideCtx(@Nullable Slot hoveredSlot, ItemStack holdingItem, boolean cursorOutsideContainer) {
}

View File

@ -0,0 +1,17 @@
package dev.isxander.controlify.gui.guide;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.api.guide.ActionPriority;
import dev.isxander.controlify.api.guide.GuideActionNameSupplier;
import org.jetbrains.annotations.NotNull;
public record GuideAction<T>(ControllerBinding binding, GuideActionNameSupplier<T> name, ActionPriority priority) implements Comparable<GuideAction<T>> {
public GuideAction(ControllerBinding binding, GuideActionNameSupplier<T> name) {
this(binding, name, ActionPriority.NORMAL);
}
@Override
public int compareTo(@NotNull GuideAction<T> o) {
return this.priority().compareTo(o.priority());
}
}

View File

@ -1,8 +1,7 @@
package dev.isxander.controlify.ingame.guide;
package dev.isxander.controlify.gui.guide;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.isxander.controlify.api.bind.BindRenderer;
import dev.isxander.controlify.api.ingameguide.IngameGuideContext;
import dev.isxander.controlify.gui.DrawSize;
import dev.isxander.controlify.gui.layout.RenderComponent;
import net.minecraft.client.Minecraft;
@ -14,20 +13,22 @@ import org.joml.Vector2ic;
import java.util.Optional;
public class GuideActionRenderer implements RenderComponent {
private final GuideAction guideAction;
public class GuideActionRenderer<T> implements RenderComponent {
private final GuideAction<T> guideAction;
private final boolean rtl;
private final boolean textContrast;
private Optional<Component> name = Optional.empty();
public GuideActionRenderer(GuideAction action, boolean rtl) {
public GuideActionRenderer(GuideAction<T> action, boolean rtl, boolean textContrast) {
this.guideAction = action;
this.rtl = rtl;
this.textContrast = textContrast;
}
@Override
public void render(PoseStack stack, int x, int y, float deltaTime) {
if (name.isEmpty())
if (!isVisible())
return;
Font font = Minecraft.getInstance().font;
@ -41,7 +42,8 @@ public class GuideActionRenderer implements RenderComponent {
int textX = x + (rtl ? 0 : drawSize.width() + 2);
int textY = y + drawSize.height() / 2 - font.lineHeight / 2;
GuiComponent.fill(stack, textX - 1, textY - 1, textX + textWidth + 1, textY + font.lineHeight + 1, 0x80000000);
if (textContrast)
GuiComponent.fill(stack, textX - 1, textY - 1, textX + textWidth + 1, textY + font.lineHeight + 1, 0x80000000);
font.draw(stack, name.get(), textX, textY, 0xFFFFFF);
}
@ -55,10 +57,10 @@ public class GuideActionRenderer implements RenderComponent {
@Override
public boolean isVisible() {
return name.isPresent();
return name.isPresent() && !guideAction.binding().isUnbound();
}
public void updateName(IngameGuideContext ctx) {
public void updateName(T ctx) {
name = guideAction.name().supply(ctx);
}
}

View File

@ -1,9 +1,10 @@
package dev.isxander.controlify.ingame.guide;
package dev.isxander.controlify.gui.guide;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.api.guide.ActionPriority;
import dev.isxander.controlify.api.guide.GuideActionNameSupplier;
import dev.isxander.controlify.api.ingameguide.*;
import dev.isxander.controlify.bindings.ControllerBindingImpl;
import dev.isxander.controlify.compatibility.ControlifyCompat;
import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.api.event.ControlifyEvents;
@ -11,8 +12,6 @@ import dev.isxander.controlify.gui.layout.AnchorPoint;
import dev.isxander.controlify.gui.layout.ColumnLayoutComponent;
import dev.isxander.controlify.gui.layout.PositionedComponent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.effect.MobEffects;
@ -29,11 +28,11 @@ public class InGameButtonGuide implements IngameGuideRegistry {
private final LocalPlayer player;
private final Minecraft minecraft = Minecraft.getInstance();
private final List<GuideAction> leftGuides = new ArrayList<>();
private final List<GuideAction> rightGuides = new ArrayList<>();
private final List<GuideAction<IngameGuideContext>> leftGuides = new ArrayList<>();
private final List<GuideAction<IngameGuideContext>> rightGuides = new ArrayList<>();
private final PositionedComponent<ColumnLayoutComponent<GuideActionRenderer>> leftLayout;
private final PositionedComponent<ColumnLayoutComponent<GuideActionRenderer>> rightLayout;
private final PositionedComponent<ColumnLayoutComponent<GuideActionRenderer<IngameGuideContext>>> leftLayout;
private final PositionedComponent<ColumnLayoutComponent<GuideActionRenderer<IngameGuideContext>>> rightLayout;
public InGameButtonGuide(Controller<?, ?> controller, LocalPlayer localPlayer) {
this.controller = controller;
@ -46,11 +45,11 @@ public class InGameButtonGuide implements IngameGuideRegistry {
Collections.sort(rightGuides);
leftLayout = new PositionedComponent<>(
ColumnLayoutComponent.<GuideActionRenderer>builder()
.elementPadding(2)
ColumnLayoutComponent.<GuideActionRenderer<IngameGuideContext>>builder()
.spacing(2)
.colPadding(4, 4)
.elementPosition(ColumnLayoutComponent.ElementPosition.LEFT)
.elements(leftGuides.stream().map(guide -> new GuideActionRenderer(guide, false)).toList())
.elements(leftGuides.stream().map(guide -> new GuideActionRenderer<>(guide, false, true)).toList())
.build(),
AnchorPoint.TOP_LEFT,
0, 0,
@ -58,11 +57,11 @@ public class InGameButtonGuide implements IngameGuideRegistry {
);
rightLayout = new PositionedComponent<>(
ColumnLayoutComponent.<GuideActionRenderer>builder()
.elementPadding(2)
ColumnLayoutComponent.<GuideActionRenderer<IngameGuideContext>>builder()
.spacing(2)
.colPadding(4, 4)
.elementPosition(ColumnLayoutComponent.ElementPosition.RIGHT)
.elements(rightGuides.stream().map(guide -> new GuideActionRenderer(guide, true)).toList())
.elements(rightGuides.stream().map(guide -> new GuideActionRenderer<>(guide, true, true)).toList())
.build(),
AnchorPoint.TOP_RIGHT,
0, 0,
@ -93,16 +92,16 @@ public class InGameButtonGuide implements IngameGuideRegistry {
}
@Override
public void registerGuideAction(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier supplier) {
public void registerGuideAction(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier<IngameGuideContext> supplier) {
this.registerGuideAction(binding, location, ActionPriority.NORMAL, supplier);
}
@Override
public void registerGuideAction(ControllerBinding binding, ActionLocation location, ActionPriority priority, GuideActionNameSupplier supplier) {
public void registerGuideAction(ControllerBinding binding, ActionLocation location, ActionPriority priority, GuideActionNameSupplier<IngameGuideContext> supplier) {
if (location == ActionLocation.LEFT)
leftGuides.add(new GuideAction(binding, supplier, priority));
leftGuides.add(new GuideAction<>(binding, supplier, priority));
else
rightGuides.add(new GuideAction(binding, supplier, priority));
rightGuides.add(new GuideAction<>(binding, supplier, priority));
}
private void registerDefaultActions() {
@ -110,18 +109,18 @@ public class InGameButtonGuide implements IngameGuideRegistry {
registerGuideAction(controller.bindings().JUMP, ActionLocation.LEFT, (ctx) -> {
var player = ctx.player();
if (player.getAbilities().flying)
return Optional.of(Component.translatable("controlify.guide.fly_up"));
return Optional.of(Component.translatable("controlify.guide.ingame.fly_up"));
if (player.isOnGround())
return Optional.of(Component.translatable("key.jump"));
if (player.isInWater())
return Optional.of(Component.translatable("controlify.guide.swim_up"));
return Optional.of(Component.translatable("controlify.guide.ingame.swim_up"));
if (!player.isOnGround() && !player.isFallFlying() && !player.isInWater() && !player.hasEffect(MobEffects.LEVITATION)) {
var chestStack = player.getItemBySlot(EquipmentSlot.CHEST);
if (chestStack.is(Items.ELYTRA) && ElytraItem.isFlyEnabled(chestStack))
return Optional.of(Component.translatable("controlify.guide.start_elytra"));
return Optional.of(Component.translatable("controlify.guide.ingame.start_elytra"));
}
return Optional.empty();
@ -129,16 +128,16 @@ public class InGameButtonGuide implements IngameGuideRegistry {
registerGuideAction(controller.bindings().SNEAK, ActionLocation.LEFT, (ctx) -> {
var player = ctx.player();
if (player.getVehicle() != null)
return Optional.of(Component.translatable("controlify.guide.dismount"));
return Optional.of(Component.translatable("controlify.guide.ingame.dismount"));
if (player.getAbilities().flying)
return Optional.of(Component.translatable("controlify.guide.fly_down"));
return Optional.of(Component.translatable("controlify.guide.ingame.fly_down"));
if (player.isInWater() && !player.isOnGround())
return Optional.of(Component.translatable("controlify.guide.swim_down"));
return Optional.of(Component.translatable("controlify.guide.ingame.swim_down"));
if (ctx.controller().config().toggleSneak) {
return Optional.of(Component.translatable(player.input.shiftKeyDown ? "controlify.guide.stop_sneaking" : "controlify.guide.start_sneaking"));
return Optional.of(Component.translatable(player.input.shiftKeyDown ? "controlify.guide.ingame.stop_sneaking" : "controlify.guide.ingame.start_sneaking"));
} else {
if (!player.input.shiftKeyDown)
return Optional.of(Component.translatable("controlify.guide.sneak"));
return Optional.of(Component.translatable("controlify.guide.ingame.sneak"));
}
return Optional.empty();
});
@ -147,27 +146,27 @@ public class InGameButtonGuide implements IngameGuideRegistry {
if (!options.keySprint.isDown()) {
if (!player.input.getMoveVector().equals(Vec2.ZERO)) {
if (player.isUnderWater())
return Optional.of(Component.translatable("controlify.guide.start_swimming"));
return Optional.of(Component.translatable("controlify.guide.start_sprinting"));
return Optional.of(Component.translatable("controlify.guide.ingame.start_swimming"));
return Optional.of(Component.translatable("controlify.guide.ingame.start_sprinting"));
}
} else if (ctx.controller().config().toggleSprint) {
if (player.isUnderWater())
return Optional.of(Component.translatable("controlify.guide.stop_swimming"));
return Optional.of(Component.translatable("controlify.guide.stop_sprinting"));
return Optional.of(Component.translatable("controlify.guide.ingame.stop_swimming"));
return Optional.of(Component.translatable("controlify.guide.ingame.stop_sprinting"));
}
return Optional.empty();
});
registerGuideAction(controller.bindings().INVENTORY, ActionLocation.RIGHT, (ctx) -> {
if (ctx.client().screen == null)
return Optional.of(Component.translatable("controlify.guide.inventory"));
return Optional.of(Component.translatable("controlify.guide.ingame.inventory"));
return Optional.empty();
});
registerGuideAction(controller.bindings().ATTACK, ActionLocation.RIGHT, (ctx) -> {
var hitResult = ctx.hitResult();
if (hitResult.getType() == HitResult.Type.ENTITY)
return Optional.of(Component.translatable("controlify.guide.attack"));
return Optional.of(Component.translatable("controlify.guide.ingame.attack"));
if (hitResult.getType() == HitResult.Type.BLOCK)
return Optional.of(Component.translatable("controlify.guide.break"));
return Optional.of(Component.translatable("controlify.guide.ingame.break"));
return Optional.empty();
});
registerGuideAction(controller.bindings().USE, ActionLocation.RIGHT, (ctx) -> {
@ -175,28 +174,28 @@ public class InGameButtonGuide implements IngameGuideRegistry {
var player = ctx.player();
if (hitResult.getType() == HitResult.Type.ENTITY)
if (player.isSpectator())
return Optional.of(Component.translatable("controlify.guide.spectate"));
return Optional.of(Component.translatable("controlify.guide.ingame.spectate"));
else
return Optional.of(Component.translatable("controlify.guide.interact"));
return Optional.of(Component.translatable("controlify.guide.ingame.interact"));
if (hitResult.getType() == HitResult.Type.BLOCK || player.hasItemInSlot(EquipmentSlot.MAINHAND) || player.hasItemInSlot(EquipmentSlot.OFFHAND))
return Optional.of(Component.translatable("controlify.guide.use"));
return Optional.of(Component.translatable("controlify.guide.ingame.use"));
return Optional.empty();
});
registerGuideAction(controller.bindings().DROP, ActionLocation.RIGHT, (ctx) -> {
var player = ctx.player();
if (player.hasItemInSlot(EquipmentSlot.MAINHAND) || player.hasItemInSlot(EquipmentSlot.OFFHAND))
return Optional.of(Component.translatable("controlify.guide.drop"));
return Optional.of(Component.translatable("controlify.guide.ingame.drop"));
return Optional.empty();
});
registerGuideAction(controller.bindings().SWAP_HANDS, ActionLocation.RIGHT, (ctx) -> {
var player = ctx.player();
if (player.hasItemInSlot(EquipmentSlot.MAINHAND) || player.hasItemInSlot(EquipmentSlot.OFFHAND))
return Optional.of(Component.translatable("controlify.guide.swap_hands"));
return Optional.of(Component.translatable("controlify.guide.ingame.swap_hands"));
return Optional.empty();
});
registerGuideAction(controller.bindings().PICK_BLOCK, ActionLocation.RIGHT, (ctx) -> {
if (ctx.hitResult().getType() == HitResult.Type.BLOCK && ctx.player().isCreative())
return Optional.of(Component.translatable("controlify.guide.pick_block"));
return Optional.of(Component.translatable("controlify.guide.ingame.pick_block"));
return Optional.empty();
});
}

View File

@ -118,7 +118,7 @@ public class ColumnLayoutComponent<T extends RenderComponent> extends AbstractLa
return this;
}
public Builder<T> elementPadding(int padding) {
public Builder<T> spacing(int padding) {
this.componentPaddingVertical = padding;
return this;
}

View File

@ -78,6 +78,12 @@ public class RowLayoutComponent<T extends RenderComponent> extends AbstractLayou
.sum() - elementPaddingHorizontal;
}
@Override
public boolean isVisible() {
return this.getChildComponents().stream()
.anyMatch(RenderComponent::isVisible);
}
public static <T extends RenderComponent> Builder<T> builder() {
return new Builder<>();
}
@ -115,7 +121,7 @@ public class RowLayoutComponent<T extends RenderComponent> extends AbstractLayou
return this;
}
public Builder<T> elementPadding(int padding) {
public Builder<T> spacing(int padding) {
this.elementPaddingHorizontal = padding;
return this;
}

View File

@ -7,6 +7,7 @@ import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.api.event.ControlifyEvents;
import dev.isxander.controlify.controller.gamepad.GamepadController;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.inventory.InventoryScreen;
import net.minecraft.client.player.KeyboardInput;
import net.minecraft.world.InteractionHand;
@ -41,7 +42,7 @@ public class InGameInputHandler {
protected void handleKeybinds() {
shouldShowPlayerList = false;
if (Minecraft.getInstance().screen != null)
if (minecraft.screen != null)
return;
if (controller.bindings().PAUSE.justPressed()) {
@ -62,6 +63,14 @@ public class InGameInputHandler {
}
}
if (controller.bindings().INVENTORY.justPressed()) {
if (minecraft.gameMode.isServerControlledInventory()) {
minecraft.player.sendOpenInventory();
} else {
minecraft.getTutorial().onOpenInventory();
minecraft.setScreen(new InventoryScreen(minecraft.player));
}
}
}
if (controller.bindings().TOGGLE_HUD_VISIBILITY.justPressed()) {
minecraft.options.hideGui = !minecraft.options.hideGui;
@ -74,19 +83,23 @@ public class InGameInputHandler {
var player = this.minecraft.player;
var gamepad = controller instanceof GamepadController ? (GamepadController) controller : null;
if (!minecraft.mouseHandler.isMouseGrabbed() || (!minecraft.isWindowActive() && !Controlify.instance().config().globalSettings().outOfFocusInput) || minecraft.screen != null || player == null) {
lookInputX = 0;
lookInputY = 0;
return;
}
// flick stick - turn 90 degrees immediately upon turning
// should be paired with gyro controls
if (gamepad != null && gamepad.config().flickStick) {
if (player != null) {
var turnAngle = 90 / 0.15f; // Entity#turn multiplies cursor delta by 0.15 to get rotation
var turnAngle = 90 / 0.15f; // Entity#turn multiplies cursor delta by 0.15 to get rotation
player.turn(
(controller.bindings().LOOK_RIGHT.justPressed() ? turnAngle : 0)
- (controller.bindings().LOOK_LEFT.justPressed() ? turnAngle : 0),
(controller.bindings().LOOK_DOWN.justPressed() ? turnAngle : 0)
- (controller.bindings().LOOK_UP.justPressed() ? turnAngle : 0)
);
}
player.turn(
(controller.bindings().LOOK_RIGHT.justPressed() ? turnAngle : 0)
- (controller.bindings().LOOK_LEFT.justPressed() ? turnAngle : 0),
(controller.bindings().LOOK_DOWN.justPressed() ? turnAngle : 0)
- (controller.bindings().LOOK_UP.justPressed() ? turnAngle : 0)
);
return;
}
@ -122,12 +135,8 @@ public class InGameInputHandler {
impulseX = lookInputModifier.modifyX(impulseX, controller);
impulseY = lookInputModifier.modifyY(impulseY, controller);
if (minecraft.mouseHandler.isMouseGrabbed() && (minecraft.isWindowActive() || Controlify.instance().config().globalSettings().outOfFocusInput) && player != null) {
lookInputX = impulseX * controller.config().horizontalLookSensitivity * 65f;
lookInputY = impulseY * controller.config().verticalLookSensitivity * 65f;
} else {
lookInputX = lookInputY = 0;
}
lookInputX = impulseX * controller.config().horizontalLookSensitivity * 65f;
lookInputY = impulseY * controller.config().verticalLookSensitivity * 65f;
}
public void processPlayerLook(float deltaTime) {

View File

@ -1,19 +0,0 @@
package dev.isxander.controlify.ingame.guide;
import dev.isxander.controlify.api.bind.ControllerBinding;
import dev.isxander.controlify.api.ingameguide.ActionLocation;
import dev.isxander.controlify.api.ingameguide.ActionPriority;
import dev.isxander.controlify.api.ingameguide.GuideActionNameSupplier;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
public record GuideAction(ControllerBinding binding, GuideActionNameSupplier name, ActionPriority priority) implements Comparable<GuideAction> {
public GuideAction(ControllerBinding binding, GuideActionNameSupplier name) {
this(binding, name, ActionPriority.NORMAL);
}
@Override
public int compareTo(@NotNull GuideAction o) {
return this.priority().compareTo(o.priority());
}
}

View File

@ -2,7 +2,7 @@ package dev.isxander.controlify.mixins.feature.guide.ingame;
import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.InputMode;
import dev.isxander.controlify.ingame.guide.InGameButtonGuide;
import dev.isxander.controlify.gui.guide.InGameButtonGuide;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;

View File

@ -2,8 +2,7 @@ package dev.isxander.controlify.mixins.feature.guide.ingame;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.ingame.InGameInputHandler;
import dev.isxander.controlify.ingame.guide.InGameButtonGuide;
import dev.isxander.controlify.gui.guide.InGameButtonGuide;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import org.spongepowered.asm.mixin.Final;

View File

@ -0,0 +1,153 @@
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);
}
}

View File

@ -81,7 +81,7 @@ public class VirtualMouseHandler {
snapping = false;
}
var sensitivity = !snapping ? controller.config().virtualMouseSensitivity : 20f;
var sensitivity = controller.config().virtualMouseSensitivity;
// quadratic function to make small movements smaller
// abs to keep sign
@ -166,8 +166,9 @@ public class VirtualMouseHandler {
lastSnappedPoint = closestSnapPoint;
snapping = false;
targetX = closestSnapPoint.position().x() / scaleFactor.x();
targetY = closestSnapPoint.position().y() / scaleFactor.y();
targetX = currentX = closestSnapPoint.position().x() / scaleFactor.x();
targetY = currentY = closestSnapPoint.position().y() / scaleFactor.y();
((MouseHandlerAccessor) minecraft.mouseHandler).invokeOnMove(minecraft.getWindow().getWindow(), currentX, currentY);
}
}